Пример #1
0
void BulletPhysics::BulletInternalTickCallback(btDynamicsWorld* world, btScalar timeStep)
{
	// called after bullet sdk performs its internal step

	CB_ASSERT(world);
	CB_ASSERT(world->getWorldUserInfo());

	BulletPhysics* bulletPhysics = static_cast<BulletPhysics*>(world->getWorldUserInfo());
	CollisionPairs currentTickCollisionPairs;

	// look at all existing collisions
	btDispatcher* dispatcher = world->getDispatcher();
	const int numManifolds = dispatcher->getNumManifolds();
	for (int i = 0; i < numManifolds; i++)
	{
		// get the manifold which is the data corresponding to a contact point between two colliders
		const btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal(i);
		CB_ASSERT(manifold);

		// get the colliding bodies
		const btRigidBody* body0 = static_cast<const btRigidBody *>(manifold->getBody0());
		const btRigidBody* body1 = static_cast<const btRigidBody *>(manifold->getBody1());

		// swap them if need be
		const bool swapped = body0 > body1;
		const btRigidBody* sortedBody0 = swapped ? body1 : body0;
		const btRigidBody* sortedBody1 = swapped ? body0 : body1;

		// insert the collision pair into the set
		const CollisionPair pair = std::make_pair(sortedBody0, sortedBody1);
		currentTickCollisionPairs.insert(pair);
		
		// if this is a new contact, send an event
		if (bulletPhysics->m_PreviousTickCollisionPairs.find(pair) == bulletPhysics->m_PreviousTickCollisionPairs.end())
		{
			bulletPhysics->SendCollisionPairAddEvent(manifold, body0, body1);
		}
	}

	CollisionPairs removedCollisionPairs;

	// use set difference to see which collisions existed last tick but are no longer colliding
	std::set_difference(bulletPhysics->m_PreviousTickCollisionPairs.begin(), bulletPhysics->m_PreviousTickCollisionPairs.end(),
		currentTickCollisionPairs.begin(), currentTickCollisionPairs.end(),
		std::inserter(removedCollisionPairs, removedCollisionPairs.begin()));

	// send collision exit events
	for (auto it = removedCollisionPairs.begin(); it != removedCollisionPairs.end(); ++it)
	{
		const btRigidBody* body0 = it->first;
		const btRigidBody* body1 = it->second;

		bulletPhysics->SendCollisionPairRemoveEvent(body0, body1);
	}

	// update the collision pairs
	bulletPhysics->m_PreviousTickCollisionPairs = currentTickCollisionPairs;
}
Пример #2
0
void BulletPhysics::RemoveCollisionObject(btCollisionObject* obj)
{
	// remove a collision object from the physics world
	m_DynamicsWorld->removeCollisionObject(obj);

	// remove the pointer from the collision contacts list
	for (auto it = m_PreviousTickCollisionPairs.begin(); it != m_PreviousTickCollisionPairs.end(); )
	{
		// step the iterator by 1
		auto next = it;
		++next;

		// remove the object from any currently happening collision
		if (it->first == obj || it->second == obj)
		{
			SendCollisionPairRemoveEvent(it->first, it->second);
			m_PreviousTickCollisionPairs.erase(it);
		}

		it = next;
	}

	// if the object was a rigid body
	if (btRigidBody* body = btRigidBody::upcast(obj))
	{
		// delete the components of the body
		delete body->getMotionState();
		delete body->getCollisionShape();
		delete body->getUserPointer();

		for (int i = body->getNumConstraintRefs() - 1; i >= 0; i--)
		{
			btTypedConstraint* constraint = body->getConstraintRef(i);
			m_DynamicsWorld->removeConstraint(constraint);
			delete constraint;
		}
	}

	delete obj;
}
void BulletOpenGLApplication::CheckForCollisionEvents() {
	// keep a list of the collision pairs we
	// found during the current update
	CollisionPairs pairsThisUpdate;

	// iterate through all of the manifolds in the dispatcher
	for (int i = 0; i < m_pDispatcher->getNumManifolds(); ++i) {
		
		// get the manifold
		btPersistentManifold* pManifold = m_pDispatcher->getManifoldByIndexInternal(i);
		
		// ignore manifolds that have 
		// no contact points.
		if (pManifold->getNumContacts() > 0) {
			// get the two rigid bodies involved in the collision
			const btRigidBody* pBody0 = static_cast<const btRigidBody*>(pManifold->getBody0());
			const btRigidBody* pBody1 = static_cast<const btRigidBody*>(pManifold->getBody1());
    
			// always create the pair in a predictable order
			// (use the pointer value..)
			bool const swapped = pBody0 > pBody1;
			const btRigidBody* pSortedBodyA = swapped ? pBody1 : pBody0;
			const btRigidBody* pSortedBodyB = swapped ? pBody0 : pBody1;
			
			// create the pair
			CollisionPair thisPair = std::make_pair(pSortedBodyA, pSortedBodyB);
			
			// insert the pair into the current list
			pairsThisUpdate.insert(thisPair);

			// if this pair doesn't exist in the list
			// from the previous update, it is a new
			// pair and we must send a collision event
			if (m_pairsLastUpdate.find(thisPair) == m_pairsLastUpdate.end()) {
				CollisionEvent((btRigidBody*)pBody0, (btRigidBody*)pBody1);
			}
		}
	}
	
	// create another list for pairs that
	// were removed this update
	CollisionPairs removedPairs;
	
	// this handy function gets the difference beween
	// two sets. It takes the difference between
	// collision pairs from the last update, and this 
	// update and pushes them into the removed pairs list
	std::set_difference( m_pairsLastUpdate.begin(), m_pairsLastUpdate.end(),
	pairsThisUpdate.begin(), pairsThisUpdate.end(),
	std::inserter(removedPairs, removedPairs.begin()));
	
	// iterate through all of the removed pairs
	// sending separation events for them
	for (CollisionPairs::const_iterator iter = removedPairs.begin(); iter != removedPairs.end(); ++iter) {
		SeparationEvent((btRigidBody*)iter->first, (btRigidBody*)iter->second);
	}
	
	// in the next iteration we'll want to
	// compare against the pairs we found
	// in this iteration
	m_pairsLastUpdate = pairsThisUpdate;
}
Пример #4
0
void BulletPhysicsManager::BulletInternalTickCallback( btDynamicsWorld * const world, btScalar const timeStep ) {
	assert( world );
	
	assert( world->getWorldUserInfo() );
	BulletPhysicsManager * const bulletPhysics = static_cast<BulletPhysicsManager*>( world->getWorldUserInfo() );
	
	// TODO - iterating through all physics components probably isn't the fastest way to handle this...
	for(std::vector<GameObject*>::iterator it = bulletPhysics->physicsObjects.begin(); it != bulletPhysics->physicsObjects.end(); ++it) {
		GameObject* gameObject = (*it);
		Dynamics* rigidBodyComponent = gameObject->getDynamics();
		if(rigidBodyComponent != NULL) {
			btRigidBody* rigidBody = dynamic_cast<BulletDynamics*>(rigidBodyComponent)->rigidBody;
			float maxVelocity = rigidBodyComponent->getMaxVelocity();
			if(maxVelocity >= 0.0f) {
				btVector3 velocity = rigidBody->getLinearVelocity();
				btScalar speed = velocity.length();
				if(speed > maxVelocity) {
					velocity *= maxVelocity/speed;
					rigidBody->setLinearVelocity(velocity);
				}
			}
		}
	}
	
	bulletPhysics->currentTickCollisionPairs.clear();
	
	// look at all existing contacts
	btDispatcher * const dispatcher = world->getDispatcher();
	
	for ( int manifoldIdx=0; manifoldIdx<dispatcher->getNumManifolds(); ++manifoldIdx )
	{
		// get the "manifold", which is the set of data corresponding to a contact point
		//   between two physics objects
		btPersistentManifold const * const manifold = dispatcher->getManifoldByIndexInternal( manifoldIdx );
		assert( manifold );
		
		if(manifold->getNumContacts() > 0) {
			btCollisionObject const * const body0 = static_cast<btCollisionObject const *>(manifold->getBody0());
			btCollisionObject const * const body1 = static_cast<btCollisionObject const *>(manifold->getBody1());

			// always create the pair in a predictable order
			bool const swapped = body0 > body1;
			
			btCollisionObject const * const sortedBodyA = swapped ? body1 : body0;
			btCollisionObject const * const sortedBodyB = swapped ? body0 : body1;
			
			CollisionPair const thisPair = std::make_pair( sortedBodyA, sortedBodyB );
			
			// TODO - why are there duplicate collisions? Probably shouldn't have to check if these objects have already collided this tick
			if ( bulletPhysics->previousTickCollisionPairs.find( thisPair ) == bulletPhysics->previousTickCollisionPairs.end() 
				&& bulletPhysics->currentTickCollisionPairs.find( thisPair ) == bulletPhysics->currentTickCollisionPairs.end())
			{
				// this needs to happen before sending the collision add event, since we might remove one of the game objects
				// as part of handling the event
				bulletPhysics->currentTickCollisionPairs.insert( thisPair );
				
				// this is a new contact, which wasn't in our list before.  send an event to the game.
				bulletPhysics->SendCollisionPairAddEvent( manifold, body0, body1 );
			} else {
				bulletPhysics->currentTickCollisionPairs.insert( thisPair );
			}
		}
	}
	
	CollisionPairs removedCollisionPairs;
	
	// use the STL set difference function to find collision pairs that existed during the previous tick but not any more
	std::set_difference( bulletPhysics->previousTickCollisionPairs.begin(), bulletPhysics->previousTickCollisionPairs.end(),
						bulletPhysics->currentTickCollisionPairs.begin(), bulletPhysics->currentTickCollisionPairs.end(),
						std::inserter( removedCollisionPairs, removedCollisionPairs.begin() ) );
	
	for ( CollisionPairs::const_iterator it = removedCollisionPairs.begin(), 
         end = removedCollisionPairs.end(); it != end; ++it )
	{
		btCollisionObject const * const body0 = it->first;
		btCollisionObject const * const body1 = it->second;
		
		bulletPhysics->SendCollisionPairRemoveEvent( body0, body1 );
	}
	
	// the current tick becomes the previous tick.  this is the way of all things.
	bulletPhysics->previousTickCollisionPairs = bulletPhysics->currentTickCollisionPairs;
}