/** This function is called at each internal bullet timestep. It is used * here to do the collision handling: using the contact manifolds after a * physics time step might miss some collisions (when more than one internal * time step was done, and the collision is added and removed). So this * function stores all collisions in a list, which is then handled after the * actual physics timestep. This list only stores a collision if it's not * already in the list, so a collisions which is reported more than once is * nevertheless only handled once. * The list of collision * Parameters: see bullet documentation for details. */ btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies, btPersistentManifold** manifold,int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& info, btIDebugDraw* debugDrawer, btStackAlloc* stackAlloc, btDispatcher* dispatcher) { btScalar returnValue= btSequentialImpulseConstraintSolver::solveGroup(bodies, numBodies, manifold, numManifolds, constraints, numConstraints, info, debugDrawer, stackAlloc, dispatcher); int currentNumManifolds = m_dispatcher->getNumManifolds(); // We can't explode a rocket in a loop, since a rocket might collide with // more than one object, and/or more than once with each object (if there // is more than one collision point). So keep a list of rockets that will // be exploded after the collisions for(int i=0; i<currentNumManifolds; i++) { btPersistentManifold* contact_manifold = m_dynamics_world->getDispatcher()->getManifoldByIndexInternal(i); const btCollisionObject* objA = static_cast<const btCollisionObject*>(contact_manifold->getBody0()); const btCollisionObject* objB = static_cast<const btCollisionObject*>(contact_manifold->getBody1()); unsigned int num_contacts = contact_manifold->getNumContacts(); if(!num_contacts) continue; // no real collision const UserPointer *upA = (UserPointer*)(objA->getUserPointer()); const UserPointer *upB = (UserPointer*)(objB->getUserPointer()); if(!upA || !upB) continue; // 1) object A is a track // ======================= if(upA->is(UserPointer::UP_TRACK)) { if(upB->is(UserPointer::UP_FLYABLE)) // 1.1 projectile hits track m_all_collisions.push_back( upB, contact_manifold->getContactPoint(0).m_localPointB, upA, contact_manifold->getContactPoint(0).m_localPointA); else if(upB->is(UserPointer::UP_KART)) { AbstractKart *kart=upB->getPointerKart(); int n = contact_manifold->getContactPoint(0).m_index0; const Material *m = n>=0 ? upA->getPointerTriangleMesh()->getMaterial(n) : NULL; // I assume that the normal needs to be flipped in this case, // but I can't verify this since it appears that bullet // always has the kart as object A, not B. const btVector3 &normal = -contact_manifold->getContactPoint(0) .m_normalWorldOnB; kart->crashed(m, normal); } else if(upB->is(UserPointer::UP_PHYSICAL_OBJECT)) { int n = contact_manifold->getContactPoint(0).m_index1; const Material *m = n>=0 ? upA->getPointerTriangleMesh()->getMaterial(n) : NULL; const btVector3 &normal = contact_manifold->getContactPoint(0) .m_normalWorldOnB; upB->getPointerPhysicalObject()->hit(m, normal); } } // 2) object a is a kart // ===================== else if(upA->is(UserPointer::UP_KART)) { if(upB->is(UserPointer::UP_TRACK)) { AbstractKart *kart = upA->getPointerKart(); int n = contact_manifold->getContactPoint(0).m_index1; const Material *m = n>=0 ? upB->getPointerTriangleMesh()->getMaterial(n) : NULL; const btVector3 &normal = contact_manifold->getContactPoint(0) .m_normalWorldOnB; kart->crashed(m, normal); // Kart hit track } else if(upB->is(UserPointer::UP_FLYABLE)) // 2.1 projectile hits kart m_all_collisions.push_back( upB, contact_manifold->getContactPoint(0).m_localPointB, upA, contact_manifold->getContactPoint(0).m_localPointA); else if(upB->is(UserPointer::UP_KART)) // 2.2 kart hits kart m_all_collisions.push_back( upA, contact_manifold->getContactPoint(0).m_localPointA, upB, contact_manifold->getContactPoint(0).m_localPointB); else if(upB->is(UserPointer::UP_PHYSICAL_OBJECT)) // 2.3 kart hits physical object m_all_collisions.push_back( upB, contact_manifold->getContactPoint(0).m_localPointB, upA, contact_manifold->getContactPoint(0).m_localPointA); else if(upB->is(UserPointer::UP_ANIMATION)) m_all_collisions.push_back( upB, contact_manifold->getContactPoint(0).m_localPointB, upA, contact_manifold->getContactPoint(0).m_localPointA); } // 3) object is a projectile // ========================= else if(upA->is(UserPointer::UP_FLYABLE)) { // 3.1) projectile hits track // 3.2) projectile hits projectile // 3.3) projectile hits physical object // 3.4) projectile hits kart if(upB->is(UserPointer::UP_TRACK ) || upB->is(UserPointer::UP_FLYABLE ) || upB->is(UserPointer::UP_PHYSICAL_OBJECT) || upB->is(UserPointer::UP_KART ) ) { m_all_collisions.push_back( upA, contact_manifold->getContactPoint(0).m_localPointA, upB, contact_manifold->getContactPoint(0).m_localPointB); } } // Object is a physical object // =========================== else if(upA->is(UserPointer::UP_PHYSICAL_OBJECT)) { if(upB->is(UserPointer::UP_FLYABLE)) m_all_collisions.push_back( upB, contact_manifold->getContactPoint(0).m_localPointB, upA, contact_manifold->getContactPoint(0).m_localPointA); else if(upB->is(UserPointer::UP_KART)) m_all_collisions.push_back( upA, contact_manifold->getContactPoint(0).m_localPointA, upB, contact_manifold->getContactPoint(0).m_localPointB); else if(upB->is(UserPointer::UP_TRACK)) { int n = contact_manifold->getContactPoint(0).m_index1; const Material *m = n>=0 ? upB->getPointerTriangleMesh()->getMaterial(n) : NULL; const btVector3 &normal = contact_manifold->getContactPoint(0) .m_normalWorldOnB; upA->getPointerPhysicalObject()->hit(m, normal); } } else if (upA->is(UserPointer::UP_ANIMATION)) { if(upB->is(UserPointer::UP_KART)) m_all_collisions.push_back( upA, contact_manifold->getContactPoint(0).m_localPointA, upB, contact_manifold->getContactPoint(0).m_localPointB); } else assert("Unknown user pointer"); // 4) Should never happen } // for i<numManifolds return returnValue; } // solveGroup