// This is a callback from the broadphase when two AABB proxies cease // to overlap. We destroy the b2Contact. void b2ContactManager::PairRemoved(void* proxyUserData1, void* proxyUserData2, void* pairUserData) { NOT_USED(proxyUserData1); NOT_USED(proxyUserData2); if (pairUserData == NULL) { return; } b2Contact* c = (b2Contact*)pairUserData; if (c != &m_nullContact) { b2Assert(m_world->m_contactCount > 0); if (m_destroyImmediate == true) { DestroyContact(c); c = NULL; } else { c->m_flags |= b2Contact::e_destroyFlag; } } }
// Destroy any contacts marked for deferred destruction. void b2ContactManager::CleanContactList() { b2Contact* c = m_world->m_contactList; while (c != NULL) { b2Contact* c0 = c; c = c->m_next; if (c0->m_flags & b2Contact::e_destroyFlag) { DestroyContact(c0); c0 = NULL; } } }
void b3ContactGraph::UpdateContacts() { // Update all contact constraints and its states. b3Contact* c = m_contactList; while (c) { const b3Shape* shapeA = c->m_shapeA; const b3Shape* shapeB = c->m_shapeB; b3Body* bodyA = c->m_shapeA->m_body; b3Body* bodyB = c->m_shapeB->m_body; if (bodyA == bodyB) { b3Contact* quack = c; c = c->m_next; DestroyContact(quack); continue; } bool activeA = bodyA->IsAwake() && (bodyA->m_type != e_staticBody); bool activeB = bodyB->IsAwake() && (bodyB->m_type != e_staticBody); if (!activeA && !activeB) { c = c->m_next; continue; } // Destroy the contact if is definately persistenting. if (!m_broadPhase.TestOverlap(shapeA->broadPhaseID, shapeB->broadPhaseID)) { b3Contact* quack = c; c = c->m_next; DestroyContact(quack); continue; } bool wasTouching = c->IsTouching(); bool isTouching = false; bool isSensorContact = shapeA->IsSensor() || shapeB->IsSensor(); if (isSensorContact) { // Simply, a sensor is active if its bounds is touching with another other shape's bounds. isTouching = m_broadPhase.TestOverlap(shapeA->broadPhaseID, shapeB->broadPhaseID); c->m_manifold.pointCount = 0; } else { // For the time being, Bounce can compute the closest distance between convex objects only. typedef void(*b3DistanceQuery) (b3Manifold&, const b3Transform&, const b3Shape*, const b3Transform&, const b3Shape*); // Simply, register the collision routines here. static b3DistanceQuery queryMatrix[e_maxShapes][e_maxShapes] = { { &b3HullHullShapeContact }, }; b3ShapeType typeA = shapeA->GetType(); b3ShapeType typeB = shapeB->GetType(); b3Assert(typeA <= typeB); b3DistanceQuery Query = queryMatrix[typeA][typeB]; b3Assert(Query); // Copy the old manifold so we can compare the new contact points with it. b3Manifold oldManifold = c->m_manifold; // Compute the a new contact manifold. c->m_manifold.pointCount = 0; Query(c->m_manifold, bodyA->m_transform * shapeA->m_local, shapeA, bodyB->m_transform * shapeB->m_local, shapeB); isTouching = c->m_manifold.pointCount > 0; // Look up the contact cache for identical contact points. b3Manifold* newManifold = &c->m_manifold; b3Vec3 normal = newManifold->normal; b3Vec3 xA = bodyA->m_worldCenter; b3Vec3 vA = bodyA->m_linearVelocity; b3Vec3 wA = bodyA->m_angularVelocity; b3Vec3 xB = bodyB->m_worldCenter; b3Vec3 vB = bodyB->m_linearVelocity; b3Vec3 wB = bodyB->m_angularVelocity; for (u32 i = 0; i < newManifold->pointCount; ++i) { b3ContactPoint* p2 = newManifold->points + i; b3Vec3 position = p2->position; b3Vec3 tangent1; b3Vec3 tangent2; p2->normalImpulse = B3_ZERO; p2->tangentImpulse[0] = B3_ZERO; p2->tangentImpulse[1] = B3_ZERO; p2->warmStarted = false; // Compute the (two) new tangent directions. b3Vec3 rA = position - xA; b3Vec3 rB = position - xB; b3Vec3 dv = vB + b3Cross(wB, rB) - vA - b3Cross(wA, rA); tangent1 = dv - b3Dot(dv, normal) * normal; r32 tangentMag = b3Dot(tangent1, tangent1); if (tangentMag > B3_EPSILON) { tangent1 *= B3_ONE / b3Sqrt(tangentMag); tangent2 = b3Cross(tangent1, normal); } else { b3ComputeBasis(normal, &tangent1, &tangent2); } p2->tangents[0] = tangent1; p2->tangents[1] = tangent2; // Initialize new contact point with the old contact point solution if they're identical. for (u32 j = 0; j < oldManifold.pointCount; ++j) { b3ContactPoint* p1 = oldManifold.points + j; if (p1->id.key == p2->id.key) { // Copy normal impulse. p2->warmStarted = true; p2->normalImpulse = p1->normalImpulse; // Project old friction solutions into the new tangential directions. b3Vec3 oldFrictionSolution = p1->tangentImpulse[0] * p1->tangents[0] + p1->tangentImpulse[1] * p1->tangents[1]; p2->tangentImpulse[0] = b3Dot(oldFrictionSolution, p2->tangents[0]); p2->tangentImpulse[1] = b3Dot(oldFrictionSolution, p2->tangents[1]); break; } } } // If the contact has begun then awake the bodies. if (isTouching != wasTouching) { bodyA->SetAwake(true); bodyB->SetAwake(true); } } // Mark the contact as touching. if (isTouching) { c->m_flags |= b3Contact::e_touchingFlag; } else { c->m_flags &= ~b3Contact::e_touchingFlag; } // Notify the contact listener the contact state. if (m_contactListener) { if (!wasTouching && isTouching) { m_contactListener->BeginContact(c); } if (wasTouching && !isTouching) { m_contactListener->EndContact(c); } if (!isSensorContact && isTouching) { m_contactListener->Persisting(c); } } // Go to the next contact. c = c->m_next; } }