public void Update(ContactListener listener) { int oldCount = GetManifoldCount(); Evaluate(listener); int newCount = GetManifoldCount(); Body body1 = _shape1.GetBody(); Body body2 = _shape2.GetBody(); if (newCount == 0 && oldCount > 0) { body1.WakeUp(); body2.WakeUp(); } // Slow contacts don't generate TOI events. if (body1.IsStatic() || body1.IsBullet() || body2.IsStatic() || body2.IsBullet()) { _flags &= ~CollisionFlags.Slow; } else { _flags |= CollisionFlags.Slow; } }
public void Update(ContactListener listener) { int manifoldCount = this.GetManifoldCount(); this.Evaluate(listener); int manifoldCount2 = this.GetManifoldCount(); Body body = this._shape1.GetBody(); Body body2 = this._shape2.GetBody(); if (manifoldCount2 == 0 && manifoldCount > 0) { body.WakeUp(); body2.WakeUp(); } if (body.IsStatic() || body.IsBullet() || body2.IsStatic() || body2.IsBullet()) { this._flags &= ~Contact.CollisionFlags.Slow; } else { this._flags |= Contact.CollisionFlags.Slow; } }
public void Update(ContactListener listener) { Manifold oldManifold = _manifold.Clone(); Evaluate(); Body bodyA = _fixtureA.Body; Body bodyB = _fixtureB.Body; int oldCount = oldManifold.PointCount; int newCount = _manifold.PointCount; if (newCount == 0 && oldCount > 0) { bodyA.WakeUp(); bodyB.WakeUp(); } // Slow contacts don't generate TOI events. if (bodyA.IsStatic() || bodyA.IsBullet() || bodyB.IsStatic() || bodyB.IsBullet()) { _flags &= ~CollisionFlags.Slow; } else { _flags |= CollisionFlags.Slow; } // 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; } } } if (oldCount == 0 && newCount > 0) { _flags |= CollisionFlags.Touch; if (listener != null) { listener.BeginContact(this); } } if (oldCount > 0 && newCount == 0) { _flags &= ~CollisionFlags.Touch; if (listener != null) { listener.EndContact(this); } } if ((_flags & CollisionFlags.NonSolid) == 0) { if (listener != null) { listener.PreSolve(this, oldManifold); } // The user may have disabled contact. if (_manifold.PointCount == 0) { _flags &= ~CollisionFlags.Touch; } } }
// Find TOI contacts and solve them. private void SolveTOI(TimeStep step) { // Reserve an island and a queue for TOI island solution. Island island = new Island(_bodyCount, Settings.MaxTOIContactsPerIsland, Settings.MaxTOIJointsPerIsland, _contactManager._contactListener); //Simple one pass queue //Relies on the fact that we're only making one pass //through and each body can only be pushed/popped once. //To push: // queue[queueStart+queueSize++] = newElement; //To pop: // poppedElement = queue[queueStart++]; // --queueSize; int queueCapacity = _bodyCount; Body[] queue = new Body[queueCapacity]; for (Body b = _bodyList; b != null; b = b._next) { b._flags &= ~Body.BodyFlags.Island; b._sweep.T0 = 0.0f; } for (Contact c = _contactManager._contactList; c != null; c = c.Next) { // Invalidate TOI c.Flags &= ~(ContactFlag.ToiFlag | ContactFlag.IslandFlag); } for (Joint j = _jointList; j != null; j = j._next) { j._islandFlag = false; } // Find TOI events and solve them. for (; ;) { // Find the first TOI. Contact minContact = null; float minTOI = 1.0f; for (Contact c = _contactManager._contactList; c != null; c = c.Next) { // Can this contact generate a solid TOI contact? if (c.IsSolid() == false || c.IsContinuous() == false) { continue; } // TODO_ERIN keep a counter on the contact, only respond to M TOIs per contact. float toi = 1.0f; if ((c.Flags & ContactFlag.ToiFlag) != 0) { // This contact has a valid cached TOI. toi = c.Toi; } else { // Compute the TOI for this contact. Fixture s1 = c.GetFixtureA(); Fixture s2 = c.GetFixtureB(); Body b1 = s1.GetBody(); Body b2 = s2.GetBody(); if ((b1.IsStatic() || b1.IsSleeping()) && (b2.IsStatic() || b2.IsSleeping())) { continue; } // Put the sweeps onto the same time interval. float t0 = b1._sweep.T0; if (b1._sweep.T0 < b2._sweep.T0) { t0 = b2._sweep.T0; b1._sweep.Advance(t0); } else if (b2._sweep.T0 < b1._sweep.T0) { t0 = b1._sweep.T0; b2._sweep.Advance(t0); } Box2DXDebug.Assert(t0 < 1.0f); // Compute the time of impact. toi = c.ComputeTOI(b1._sweep, b2._sweep); Box2DXDebug.Assert(0.0f <= toi && toi <= 1.0f); // If the TOI is in range ... if (0.0f < toi && toi < 1.0f) { // Interpolate on the actual range. toi = Math.Min((1.0f - toi) * t0 + toi, 1.0f); } c.Toi = toi; c.Flags |= ContactFlag.ToiFlag; } if (Settings.FLT_EPSILON < toi && toi < minTOI) { // This is the minimum TOI found so far. minContact = c; minTOI = toi; } } if (minContact == null || 1.0f - 100.0f * Settings.FLT_EPSILON < minTOI) { // No more TOI events. Done! break; } // Advance the bodies to the TOI. Fixture f1 = minContact.GetFixtureA(); Fixture f2 = minContact.GetFixtureB(); Body b3 = f1.GetBody(); Body b4 = f2.GetBody(); Sweep backup1 = b3._sweep; Sweep backup2 = b4._sweep; b3.Advance(minTOI); b4.Advance(minTOI); // The TOI contact likely has some new contact points. minContact.Update(_contactManager._contactListener); minContact.Flags &= ~ContactFlag.ToiFlag; // Is the contact solid? if (minContact.IsSolid() == false) { // Restore the sweeps. b3._sweep = backup1; b4._sweep = backup2; b3.SynchronizeTransform(); b4.SynchronizeTransform(); continue; } // Did numerical issues prevent a contact point from being generated? if (minContact.IsTouching() == false) { // Give up on this TOI. continue; } // Build the TOI island. We need a dynamic seed. Body seed = b3; if (seed.IsStatic()) { seed = b4; } // Reset island and queue. island.Clear(); int queueStart = 0; // starting index for queue int queueSize = 0; // elements in queue queue[queueStart + queueSize++] = seed; seed._flags |= Body.BodyFlags.Island; // Perform a breadth first search (BFS) on the contact/joint graph. while (queueSize > 0) { // Grab the next body off the stack and add it to the island. Body b = queue[queueStart++]; --queueSize; island.Add(ref b); // Make sure the body is awake. b._flags &= ~Body.BodyFlags.Sleep; // To keep islands as small as possible, we don't // propagate islands across static bodies. if (b.IsStatic()) { continue; } // Search all contacts connected to this body. for (ContactEdge cEdge = b._contactList; cEdge != null; cEdge = cEdge.Next) { // Does the TOI island still have space for contacts? if (island.ContactCount == island.ContactCapacity) { break; } // Has this contact already been added to an island? Skip slow or non-solid contacts. if ((cEdge.Contact.Flags & ContactFlag.IslandFlag) != 0) { continue; } // Is this contact touching? For performance we are not updating this contact. if (cEdge.Contact.IsSolid() == false || cEdge.Contact.IsTouching() == false) { continue; } island.Add(ref cEdge.Contact); cEdge.Contact.Flags |= ContactFlag.IslandFlag; // Update other body. Body other = cEdge.Other; // Was the other body already added to this island? if ((other._flags & Body.BodyFlags.Island) != 0) { continue; } // March forward, this can do no harm since this is the min TOI. if (other.IsStatic() == false) { other.Advance(minTOI); other.WakeUp(); } Box2DXDebug.Assert(queueStart + queueSize < queueCapacity); queue[queueStart + queueSize] = other; ++queueSize; other._flags |= Body.BodyFlags.Island; } for (JointEdge jEdge = b._jointList; jEdge != null; jEdge = jEdge.Next) { if (island.JointCount == island.JointCapacity) { continue; } if (jEdge.Joint._islandFlag == true) { continue; } island.Add(jEdge.Joint); jEdge.Joint._islandFlag = true; Body other = jEdge.Other; if ((other._flags & Body.BodyFlags.Island) != 0) { continue; } if (!other.IsStatic()) { other.Advance(minTOI); other.WakeUp(); } Box2DXDebug.Assert(queueStart + queueSize < queueCapacity); queue[queueStart + queueSize] = other; ++queueSize; other._flags |= Body.BodyFlags.Island; } } TimeStep subStep; subStep.WarmStarting = false; subStep.Dt = (1.0f - minTOI) * step.Dt; subStep.Inv_Dt = 1.0f / subStep.Dt; subStep.DtRatio = 0.0f; subStep.VelocityIterations = step.VelocityIterations; subStep.PositionIterations = step.PositionIterations; island.SolveTOI(ref subStep); // Post solve cleanup. for (int i = 0; i < island.BodyCount; ++i) { // Allow bodies to participate in future TOI islands. Body b = island.Bodies[i]; b._flags &= ~Body.BodyFlags.Island; if ((b._flags & Body.BodyFlags.Sleep) != 0) { continue; } if (b.IsStatic()) { continue; } b.SynchronizeFixtures(); // Invalidate all contact TOIs associated with this body. Some of these // may not be in the island because they were not touching. for (ContactEdge ce = b._contactList; ce != null; ce = ce.Next) { ce.Contact.Flags &= ~ContactFlag.ToiFlag; } } for (int i = 0; i < island.ContactCount; ++i) { // Allow contacts to participate in future TOI islands. Contact c = island.Contacts[i]; c.Flags &= ~(ContactFlag.ToiFlag | ContactFlag.IslandFlag); } for (int i = 0; i < island.JointCount; ++i) { // Allow joints to participate in future TOI islands. Joint j = island.Joints[i]; j._islandFlag = false; } // Commit fixture proxy movements to the broad-phase so that new contacts are created. // Also, some contacts can be destroyed. _contactManager.FindNewContacts(); } queue = null; }
/// <summary> /// Destroy a joint. This may cause the connected bodies to begin colliding. /// @warning This function is locked during callbacks. /// </summary> /// <param name="j"></param> public void DestroyJoint(Joint j) { Box2DXDebug.Assert(IsLocked() == false); if (IsLocked()) { return; } bool collideConnected = j._collideConnected; // Remove from the doubly linked list. if (j._prev != null) { j._prev._next = j._next; } if (j._next != null) { j._next._prev = j._prev; } if (j == _jointList) { _jointList = j._next; } // Disconnect from island graph. Body bodyA = j._bodyA; Body bodyB = j._bodyB; // Wake up connected bodies. bodyA.WakeUp(); bodyB.WakeUp(); // Remove from body 1. if (j._edgeA.Prev != null) { j._edgeA.Prev.Next = j._edgeA.Next; } if (j._edgeA.Next != null) { j._edgeA.Next.Prev = j._edgeA.Prev; } if (j._edgeA == bodyA._jointList) { bodyA._jointList = j._edgeA.Next; } j._edgeA.Prev = null; j._edgeA.Next = null; // Remove from body 2 if (j._edgeB.Prev != null) { j._edgeB.Prev.Next = j._edgeB.Next; } if (j._edgeB.Next != null) { j._edgeB.Next.Prev = j._edgeB.Prev; } if (j._edgeB == bodyB._jointList) { bodyB._jointList = j._edgeB.Next; } j._edgeB.Prev = null; j._edgeB.Next = null; Joint.Destroy(j); Box2DXDebug.Assert(_jointCount > 0); --_jointCount; // If the joint prevents collisions, then flag any contacts for filtering. if (collideConnected == false) { ContactEdge edge = bodyB.GetContactList(); while (edge != null) { if (edge.Other == bodyA) { // Flag the contact for filtering at the next time step (where either // body is awake). edge.Contact.FlagForFiltering(); } edge = edge.Next; } } }
public void Update(ContactListener listener) { //Note: Manifold is a class, not a struct. It will reference the old manifest, not copy it - DONE Manifold oldManifold = new Manifold(); oldManifold.LocalPlaneNormal = Manifold.LocalPlaneNormal; oldManifold.LocalPoint = Manifold.LocalPoint; oldManifold.PointCount = Manifold.PointCount; oldManifold.Points = Manifold.Points; oldManifold.Type = Manifold.Type; // Re-enable this contact. Flags &= ~ContactFlag.DisabledFlag; if (Collision.Collision.TestOverlap(_fixtureA.Aabb, _fixtureB.Aabb)) { Evaluate(); } else { Manifold.PointCount = 0; } Body bodyA = _fixtureA.GetBody(); Body bodyB = _fixtureB.GetBody(); int oldCount = oldManifold.PointCount; int newCount = Manifold.PointCount; if (newCount == 0 && oldCount > 0) { bodyA.WakeUp(); bodyB.WakeUp(); } // Slow contacts don't generate TOI events. if (bodyA.IsStatic() || bodyA.IsBullet() || bodyB.IsStatic() || bodyB.IsBullet()) { Flags |= ContactFlag.ContinuousFlag; } else { Flags &= ~ContactFlag.ContinuousFlag; } // 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; } } } if (newCount > 0) { Flags |= ContactFlag.TouchingFlag; } else { Flags &= ~ContactFlag.TouchingFlag; } if (oldCount == 0 && newCount > 0) { listener.BeginContact(this); } if (oldCount > 0 && newCount == 0) { listener.EndContact(this); } if ((Flags & ContactFlag.SensorFlag) == 0) { listener.PreSolve(this, oldManifold); } }