My custom patch for collision callback events
Posted: Thu Dec 29, 2011 10:13 pm
For my purposes, I want two very simple collision callbacks: CollisionStarted(objA, objB) and CollisionEnded(objA, objB). I got tired of Bullet's seemingly convoluted, quirky methods for detecting what collisions have happened. Iterating over the manifolds doesn't tell you whether a collision is new or not, and can't yield the correct events as a result. Contact processing is exposed in a very confusing way, and ghost objects are a hassle. So I dropped into the source and wrote up a new set of callbacks that work the way I want. The modifications are trivial, yet immensely helpful IMO.
This is how it looks in client code:
That's it. You get a single notification when a collision starts, no matter what is happening with the contacts. You get another notification when the collision ends. In my code I walk back into my own object hierarchy, but you could conceivably do whatever since the whole manifold is present and persistent.
The changes to Bullet are a mere handful of lines, and attached to this post as a patch. The logic is dead simple: If a contact is added to a manifold with zero contacts, trigger gCollisionStarted. If a contact is removed leaving a manifold with zero contacts, trigger gCollisionEnded. Personally I think this is what most people want. This may not work well if you need all of the contact points, as the collision started callback triggers as soon as a single point is available.
I'm posting this here first in case I did something incredibly stupid or unnecessary, but all of the stuff I've seen in the forums and documentation is waaaay more of a PITA than what I've put together here. If this is something useful and productive, I'll probably publish on GameDev and my blog, dunno if it's appropriate for inclusion into Bullet main-line.
This is how it looks in client code:
Code: Select all
//set the callbacks somewhere
gCollisionStartedCallback = CollisionStarted;
gCollisionEndedCallback = CollisionEnded;
static void CollisionStarted(btPersistentManifold* manifold)
{
btCollisionObject* obA = static_cast<btCollisionObject*>(manifold->getBody0());
btCollisionObject* obB = static_cast<btCollisionObject*>(manifold->getBody1());
PhysicsComponent* phyA = (PhysicsComponent*) obA->getUserPointer();
PhysicsComponent* phyB = (PhysicsComponent*) obB->getUserPointer();
if(!phyA || !phyB)
return;
printf("Collision started between: %s, %s.\n", phyA->_parent->Name.c_str(), phyB->_parent->Name.c_str());
}
static void CollisionEnded(btPersistentManifold* manifold)
{
btCollisionObject* obA = static_cast<btCollisionObject*>(manifold->getBody0());
btCollisionObject* obB = static_cast<btCollisionObject*>(manifold->getBody1());
PhysicsComponent* phyA = (PhysicsComponent*) obA->getUserPointer();
PhysicsComponent* phyB = (PhysicsComponent*) obB->getUserPointer();
if(!phyA || !phyB)
return;
printf("Collision ended between: %s, %s.\n", phyA->_parent->Name.c_str(), phyB->_parent->Name.c_str());
}
The changes to Bullet are a mere handful of lines, and attached to this post as a patch. The logic is dead simple: If a contact is added to a manifold with zero contacts, trigger gCollisionStarted. If a contact is removed leaving a manifold with zero contacts, trigger gCollisionEnded. Personally I think this is what most people want. This may not work well if you need all of the contact points, as the collision started callback triggers as soon as a single point is available.
I'm posting this here first in case I did something incredibly stupid or unnecessary, but all of the stuff I've seen in the forums and documentation is waaaay more of a PITA than what I've put together here. If this is something useful and productive, I'll probably publish on GameDev and my blog, dunno if it's appropriate for inclusion into Bullet main-line.