/// <summary>
        /// Update the contact manifold and touching status.
        /// Note: do not assume the fixture AABBs are overlapping or are valid.
        /// </summary>
        /// <param name="contactManager">The contact manager.</param>
        internal void Update(ContactManager contactManager)
        {
            Body bodyA = FixtureA.Body;
            Body bodyB = FixtureB.Body;

            if (FixtureA == null || FixtureB == null)
            {
                return;
            }

            if (!ContactManager.CheckCollisionConditions(FixtureA, FixtureB))
            {
                Enabled = false;
                return;
            }

            Manifold oldManifold = Manifold;

            // Re-enable this contact.
            Enabled = true;

            bool touching;
            bool wasTouching = IsTouching;

            bool sensor = FixtureA.IsSensor || FixtureB.IsSensor;

            // Is this contact a sensor?
            if (sensor)
            {
                Shape shapeA = FixtureA.Shape;
                Shape shapeB = FixtureB.Shape;
                touching = Collision.TestOverlap(shapeA, ChildIndexA, shapeB, ChildIndexB, ref bodyA._xf, ref bodyB._xf);

                // Sensors don't generate manifolds.
                Manifold.PointCount = 0;
            }
            else
            {
                Evaluate(ref Manifold, ref bodyA._xf, ref bodyB._xf);
                touching = Manifold.PointCount > 0;

                // Match old contact ids to new contact ids and copy the
                // stored impulses to warm start the solver.
                for (int i = 0; i < Manifold.PointCount; ++i)
                {
                    ManifoldPoint mp2 = Manifold.Points[i];
                    mp2.NormalImpulse  = 0.0f;
                    mp2.TangentImpulse = 0.0f;
                    ContactID id2 = mp2.Id;

                    for (int j = 0; j < oldManifold.PointCount; ++j)
                    {
                        ManifoldPoint mp1 = oldManifold.Points[j];

                        if (mp1.Id.Key == id2.Key)
                        {
                            mp2.NormalImpulse  = mp1.NormalImpulse;
                            mp2.TangentImpulse = mp1.TangentImpulse;
                            break;
                        }
                    }

                    Manifold.Points[i] = mp2;
                }

                if (touching != wasTouching)
                {
                    bodyA.Awake = true;
                    bodyB.Awake = true;
                }
            }

            IsTouching = touching;

            if (wasTouching == false)
            {
                if (touching)
                {
                    if (Settings.AllCollisionCallbacksAgree)
                    {
                        bool enabledA = true, enabledB = true;

                        // Report the collision to both participants. Track which ones returned true so we can
                        // later call OnSeparation if the contact is disabled for a different reason.
                        if (FixtureA.OnCollision != null)
                        {
                            foreach (OnCollisionEventHandler handler in FixtureA.OnCollision.GetInvocationList())
                            {
                                enabledA = handler(FixtureA, FixtureB, this) && enabledA;
                            }
                        }

                        // Reverse the order of the reported fixtures. The first fixture is always the one that the
                        // user subscribed to.
                        if (FixtureB.OnCollision != null)
                        {
                            foreach (OnCollisionEventHandler handler in FixtureB.OnCollision.GetInvocationList())
                            {
                                enabledB = handler(FixtureB, FixtureA, this) && enabledB;
                            }
                        }

                        Enabled = enabledA && enabledB;

                        // BeginContact can also return false and disable the contact
                        if (enabledA && enabledB && contactManager.BeginContact != null)
                        {
                            Enabled = contactManager.BeginContact(this);
                        }
                    }
                    else
                    {
                        //Report the collision to both participants:
                        if (FixtureA.OnCollision != null)
                        {
                            foreach (OnCollisionEventHandler handler in FixtureA.OnCollision.GetInvocationList())
                            {
                                Enabled = handler(FixtureA, FixtureB, this);
                            }
                        }

                        //Reverse the order of the reported fixtures. The first fixture is always the one that the
                        //user subscribed to.
                        if (FixtureB.OnCollision != null)
                        {
                            foreach (OnCollisionEventHandler handler in FixtureB.OnCollision.GetInvocationList())
                            {
                                Enabled = handler(FixtureB, FixtureA, this);
                            }
                        }

                        //BeginContact can also return false and disable the contact
                        if (contactManager.BeginContact != null)
                        {
                            Enabled = contactManager.BeginContact(this);
                        }
                    }

                    // If the user disabled the contact (needed to exclude it in TOI solver) at any point by
                    // any of the callbacks, we need to mark it as not touching and call any separation
                    // callbacks for fixtures that didn't explicitly disable the collision.
                    if (!Enabled)
                    {
                        IsTouching = false;
                    }
                }
            }
            else
            {
                if (touching == false)
                {
                    //Report the separation to both participants:
                    if (FixtureA != null && FixtureA.OnSeparation != null)
                    {
                        FixtureA.OnSeparation(FixtureA, FixtureB);
                    }

                    //Reverse the order of the reported fixtures. The first fixture is always the one that the
                    //user subscribed to.
                    if (FixtureB != null && FixtureB.OnSeparation != null)
                    {
                        FixtureB.OnSeparation(FixtureB, FixtureA);
                    }

                    if (contactManager.EndContact != null)
                    {
                        contactManager.EndContact(this);
                    }
                }
                else
                {
                    if (contactManager.StayContact != null)
                    {
                        contactManager.StayContact(this);
                    }
                }
            }

            if (sensor)
            {
                return;
            }

            if (contactManager.PreSolve != null)
            {
                contactManager.PreSolve(this, ref oldManifold);
            }
        }
示例#2
0
        internal void Destroy(Contact contact)
        {
            Fixture fixtureA = contact.FixtureA;
            Fixture fixtureB = contact.FixtureB;
            Body    bodyA    = fixtureA.Body;
            Body    bodyB    = fixtureB.Body;

            if (contact.IsTouching)
            {
                //Report the separation to both participants:
                if (fixtureA != null && fixtureA.OnSeparation != null)
                {
                    fixtureA.OnSeparation(fixtureA, fixtureB);
                }

                //Reverse the order of the reported fixtures. The first fixture is always the one that the
                //user subscribed to.
                if (fixtureB != null && fixtureB.OnSeparation != null)
                {
                    fixtureB.OnSeparation(fixtureB, fixtureA);
                }

                if (EndContact != null)
                {
                    EndContact(contact);
                }
            }

            // Remove from the world.
            ContactList.Remove(contact);

            // Remove from body 1
            if (contact._nodeA.Prev != null)
            {
                contact._nodeA.Prev.Next = contact._nodeA.Next;
            }

            if (contact._nodeA.Next != null)
            {
                contact._nodeA.Next.Prev = contact._nodeA.Prev;
            }

            if (contact._nodeA == bodyA.ContactList)
            {
                bodyA.ContactList = contact._nodeA.Next;
            }

            // Remove from body 2
            if (contact._nodeB.Prev != null)
            {
                contact._nodeB.Prev.Next = contact._nodeB.Next;
            }

            if (contact._nodeB.Next != null)
            {
                contact._nodeB.Next.Prev = contact._nodeB.Prev;
            }

            if (contact._nodeB == bodyB.ContactList)
            {
                bodyB.ContactList = contact._nodeB.Next;
            }

#if USE_ACTIVE_CONTACT_SET
            if (ActiveContacts.Contains(contact))
            {
                ActiveContacts.Remove(contact);
            }
#endif
            contact.Destroy();
        }