// Sets the listener to report collision start/end. Provides the user // with a pointer to an ContactConstraint. The ContactConstraint // holds pointers to the two shapes involved in a collision, and the // two bodies connected to each shape. The ContactListener will be // called very often, so it is recommended for the funciton to be very // efficient. Provide a NULL pointer to remove the previously set // listener. public void SetContactListener(ContactListener listener) { ContactManager.ContactListener = listener; }
// Remove contacts without broadphase overlap // Solves contact manifolds public void TestCollisions() { for (int h = 0; h < ContactList.Count; h++) { var constraint = ContactList[h]; Box A = constraint.A; Box B = constraint.B; Body bodyA = A.body; Body bodyB = B.body; constraint.Flags &= ~ContactFlags.eIsland; if (!bodyA.IsAwake() && !bodyB.IsAwake()) { continue; } if (!bodyA.CanCollide(bodyB)) { RemoveContact(constraint); continue; } // Check if contact should persist if (!Broadphase.TestOverlap(A.broadPhaseIndex, B.broadPhaseIndex)) { RemoveContact(constraint); continue; } Manifold manifold = constraint.manifold; Manifold oldManifold = constraint.manifold; Vec3 ot0 = oldManifold.tangentVectors; Vec3 ot1 = oldManifold.bitangentVectors; constraint.SolveCollision(); AABB.ComputeBasis(manifold.normal, ref manifold.tangentVectors, ref manifold.bitangentVectors); for (int i = 0; i < manifold.contactCount; ++i) { Contact c = manifold.contacts[i]; c.tangentImpulse = c.bitangentImpulse = c.normalImpulse = 0; byte oldWarmStart = c.warmStarted; c.warmStarted = 0; for (int j = 0; j < oldManifold.contactCount; ++j) { Contact oc = oldManifold.contacts[j]; if (c.fp.key == oc.fp.key) { c.normalImpulse = oc.normalImpulse; // Attempt to re-project old friction solutions Vec3 friction = ot0 * oc.tangentImpulse + ot1 * oc.bitangentImpulse; c.tangentImpulse = Vec3.Dot(friction, manifold.tangentVectors); c.bitangentImpulse = Vec3.Dot(friction, manifold.bitangentVectors); c.warmStarted = Math.Max(oldWarmStart, (byte)(oldWarmStart + 1)); break; } } } if (ContactListener != null) { var now_colliding = constraint.Flags & ContactFlags.eColliding; var was_colliding = constraint.Flags & ContactFlags.eWasColliding; if (now_colliding > 0 && was_colliding == 0) { ContactListener.BeginContact(constraint); } else if (now_colliding == 0 && was_colliding > 0) { ContactListener.EndContact(constraint); } } } }