3
\$\begingroup\$

I have two Farseer bodies. A static rectangle and a dynamic ball that is flying around. I want to determine where the ball touched the rectangle. I need the exact coordinates of the contact point.

How can I do that? Is there a way to determine the contact point?

Ball touches rectangle

 bool BlueRectangle_OnCollision(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact)
   {
       if (fixtureB.Body == RedBall)
       {
          Vector2 normal;
          FixedArray2<Vector2> worldPoints;
          contact.GetWorldManifold(out normal, out worldPoints);

          if(contact.Manifold.PointCount >= 1)
          {
            Vector2 contactPoint = worldPoints[0];
          }             
        }

        return true;
    }

It works with the following code.

\$\endgroup\$
  • \$\begingroup\$ Note that the contact point will never be mathematically "exact". It will be close enough. \$\endgroup\$ – Andrew Russell Mar 30 '14 at 1:14
  • \$\begingroup\$ To answer your additional question: worldPoints[0] is the first point (zero-based indexes) and worldPoints[1] is the second point (if it exists - re-read my answer for why it might exist). worldPoints[2] will give you an "index out of range" error ([2] refers to the third point, but the number of points is limited to two). \$\endgroup\$ – Andrew Russell Mar 31 '14 at 7:13
  • \$\begingroup\$ iforce2d.net/b2dtut/collision-anatomy See Collision points and the normal \$\endgroup\$ – ClassicThunder Mar 31 '14 at 20:32
1
\$\begingroup\$

Get the list of contacts for each body by walking the contact list (a linked list). Note that a Contact might not actually be touching, it might almost be touching. A contact can also be disabled.

ContactEdge ce = body.ContactList;
while(ce != null)
{
    Contact contact = ce.Contact;
    if(contact.IsTouching() && contact.Enabled)
    {
        /* ... do stuff with "contact" ... */
    }
    ce = ce.Next;
}

You can also get contacts in some of the event handlers, like so:

bool MyOnCollisionHandler(Fixture fixtureA, Fixture fixtureB, Contact contact)
{
    /* ... do stuff with "contact" ... */
    return true;
}

Note that an event handler can disable a contact if it returns false. Also note that the OnContact event triggers when touching first becomes true (so there's no need to check it). See the Farseer source code for Contact.Update to see exactly how this works.

A contact can be touching at a single point (as in your example, or a point resting on a line). Or it can be touching along a line between two points (eg: two lines on top of each other). Get these points like so:

Vector2 normal;
FixedArray2<Vector2> worldPoints;
contact.GetWorldManifold(out normal, out worldPoints);

This gives you a list of contact points (in world space), containing between 0 and 2 points (with the count stored in contact.Manifold.PointCount), and the normal (direction) of the contact.

If you strictly need a single point, you can do this:

if(contact.Manifold.PointCount >= 1)
{
    Vector2 contactPoint = worldPoints[0];
}

Otherwise, use a loop to get either zero, one or both points.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I still have difficulties to get the contact point. I updated my question with my code and some new questions. \$\endgroup\$ – Homer_Simpson Mar 30 '14 at 11:34
  • \$\begingroup\$ @Homer_Simpson I've updated my answer to hopefully clarify things. \$\endgroup\$ – Andrew Russell Mar 30 '14 at 14:49
  • \$\begingroup\$ I changed my question because I get an error message. \$\endgroup\$ – Homer_Simpson Mar 30 '14 at 16:26
  • \$\begingroup\$ @Homer_Simpson Apologies. That was a bug in my code. The point count is actually stored in the contact manifold. See my latest edit. \$\endgroup\$ – Andrew Russell Mar 31 '14 at 7:07
  • \$\begingroup\$ I tried it but it's not working because contact.Manifold.PointCount is never more than 1. \$\endgroup\$ – Homer_Simpson Mar 31 '14 at 20:54
-1
\$\begingroup\$

I had the same problem and used the following pixel collission which I found on the net (sorry i dont know who made that, sorry for no credits :D) and modified it a little.

The 2 Gameobjects checking first, whether they are allowed to collide and then it itereates about the overlaying pixels of object something and target.

private bool PixelCollisionDetection(GameObject something, GameObject target)
    {
        // Find the bounds of the rectangle intersection
        int top = Math.Max(something.Rectangle.Top, target.Rectangle.Top);
        int bottom = Math.Min(something.Rectangle.Bottom, target.Rectangle.Bottom);
        int left = Math.Max(something.Rectangle.Left, target.Rectangle.Left);
        int right = Math.Min(something.Rectangle.Right, target.Rectangle.Right);

        if (!target.DoesCollideWith(something.GetType()) && !something.DoesCollideWith(target.GetType()))
        {
            return false;
        }

        if (!something.Rectangle.Intersects(target.Rectangle))
        {
            return false;
        }

        // Check every point within the intersection bounds
        for (int y = top; y < bottom; y++)
        {
            for (int x = left; x < right; x++)
            {
                // Get the color of both pixels at this point
                Color colorA = something.SpriteData[(x - something.Rectangle.Left) +
                                     (y - something.Rectangle.Top) * something.Rectangle.Width];
                Color colorB = target.SpriteData[(x - target.Rectangle.Left) +
                                     (y - target.Rectangle.Top) * target.Rectangle.Width];

                // If both pixels are not completely transparent and attackColors match...
                if (colorA.A != 0 && colorB.A != 0)
                {
                    target.CollisionWith(something, new Vector2(x, y));
                    something.CollisionWith(target, new Vector2(x, y));
                    return true;
                }
            }
        }
        // No intersection found
        return false;
    }

The method CollissionWith(... part is interesting for you, since there I get the exact point of collission, or at least the first, if there are more than one :D

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Hi, Daniel. Could you explain why this is better than using the built in physics tools? \$\endgroup\$ – Vaughan Hilts Mar 30 '14 at 16:48
  • \$\begingroup\$ Well i dont know the farseer physics engine at all but for me it works this way ;) The Pixelcollission returns true only if it is a collission, and false if they are just "close to another" as in your example. I dont know how exact it shall be for your project. \$\endgroup\$ – Daniel Mar 30 '14 at 20:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.