// 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;
		}
	}
}
예제 #3
0
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;
	}
}