CollideList

Nov 22, 2009 at 8:11 PM

Given the CollideList, rotation, and position of the geom, how can I figure out where the geom was hit?  For instance, if the geom's rotation was 180 degrees, and another geom hits it from above, the contact is actually occurring on the bottom of the geom in question.  Are there any values from which I can pull that type of information?  Or maybe Contact already takes that into account?

Coordinator
Nov 22, 2009 at 8:25 PM

The ContactList given to you by the OnCollision delegate contains this kind of information. If you run the SimpleSamples for XNA and turn on the debug view by pressing F1, you will see some small red rectangles appearing when a collision happens. Those rectangles are using the ContactList information from the PhysicsSimulator.

If you need some kind of orientation on your geometry, the easiest way is to create a couple of sensor geometries: top, bottom, left, right and simply use that for your orientation. If you need something more advanced, you will have to somehow attach information about the orientation of the vertices used. When a collision occurs, you extract that information and you will know what is "up" and what is "down".

Nov 22, 2009 at 8:33 PM

I just found the Contact.Normal variable.  Is is possible to figure it out using just Normal and Rotation?  For instance, say the Normal.X is -1 and we know which geom we're using as a reference.  We know we've been hit on the left hand side.  Now we just need to convert the normal to be relative to the rotation?  I'm just not sure on the math involved to do so.  Or maybe that's not possible?

Coordinator
Nov 22, 2009 at 11:48 PM

I'm writing a blog post about pseudo orientation in Farseer Physics. It should describe exactly what you need (determining the side that was hit using the normal and rotation). Hopefully it will be done tomorrow.

Nov 22, 2009 at 11:57 PM
Edited Nov 23, 2009 at 12:21 AM

So far I've had a little luck with the following function.

The problem is that it's generating the right answer when I collide with another geom, but for some reason the opposite of the right answer when I collide with the screen borders.  I'm kind of new to the physics involved here, but if you could take a look at that and let me know if I'm at least on the right track that would be cool.  Thanks!

 

public static CollisionPoints GetCollisionPoints(float rotation, ContactList contactList)
{
CollisionPoints result = CollisionPoints.None;
foreach (Contact c in contactList)
{
float normAngle = (float)Math.Atan2(c.Normal.X, c.Normal.Y);
float collisionSide = normAngle + rotation;
Vector2 newNorm = AngleToVector2(collisionSide);
if (newNorm.X > .1)
result |= CollisionPoints.Right;
if (newNorm.X < -.1)
result |= CollisionPoints.Left;
if (newNorm.Y > .1)
result |= CollisionPoints.Bottom;
if (newNorm.Y < -.1)
result |= CollisionPoints.Top;
}
return result;
}

 

Nov 23, 2009 at 12:57 AM

Got it!

The problem with the previous code was the order that the geoms are added to the simulator.  That affects the Normal value.  The value is relative to the geom that was added first.  Here's the code working if anybody's interested.  I also upped the threshold for each to .5 for a little more useful results:

public static CollisionPoints GetCollisionPoints(Geom geom, Geom collidedWith, ContactList contactList)
        {
            CollisionPoints result = CollisionPoints.None;
            foreach (Contact c in contactList)
            {
                Vector2 normVec = c.Normal;
                if (geom.Id > collidedWith.Id)
                    normVec = -normVec;
                float normAngle = (float)Math.Atan2(normVec.X, normVec.Y);
                float collisionSide = normAngle + geom.Rotation;
                Vector2 newNorm = AngleToVector2(collisionSide);
                if (newNorm.X > .5)
                    result |= CollisionPoints.Right;
                if (newNorm.X < -.5)
                    result |= CollisionPoints.Left;
                if (newNorm.Y > .5)
                    result |= CollisionPoints.Bottom;
                if (newNorm.Y < -.5)
                    result |= CollisionPoints.Top;
            }
            return result;
        }

Coordinator
Nov 23, 2009 at 8:05 PM

Seems like I was too slow. :) However, I still finished the blogpost and wrote up some code since it uses a more generic approach.
If you find any errors, please let me know. I wrote it in the middle of the night and I've not had the time to read it myself. (or test the project)

You can find the blog post here.