Enhancing collision callbacks.
Posted: Tue Nov 17, 2009 2:54 pm
I've been toying around with some new ideas for collision callbacks. I've attached a patch file for trunk with a quick mockup of the proposed changes.
Basically, it would simplify and greatly increase the usefulness of callbacks. The function prototype of the old collision callbacks looked like this:
There are way to many parameters there. Every time I want to write one of those I've had to copy paste the prototype to be able to remember them all. A lot of the time I don't even use any of the arguments, and most of the time I don't use anything more than the shapes. Enter the new collision callback. Simpler and easier to remember.
Now an explanation of why this is better: With the new post step callback functionality you can add callbacks that are called at the end of a step to do things like safely remove colliding shapes. Another neat potential usage is retrieving the size of a collision impulse in a post step function to calculate falling damage or the like. To do that, you would have had to pass the space as your user data parameter. Now it's just passed to you regardlessly.
Another feature that has been requested a couple of times was getting event callbacks when objects start and stop touching. Chipmunk stored this information internally, but it was locked up in the arbiter structs and was very hard to get at from within a callback. Being passed both the space and the arbiter allows you to check if the collision is brand new. The space also filters out old cached collision data stored in the arbiters each step. By adding a function pointer to the arbiter struct, it can call back into your code if a collision happened last step, but not this one.
This would obviously break existing collision callbacks. I can't easily write in compatibility for it either. A wrapper function that calls the old style function would have to allocate a context struct that held the old function and old data pointer. There would have to be logic to free that struct if you remove an old style callback. Converting code that has old style callbacks would be as easy as pasting over the new arguments and throwing a macro that defines the proper variables as the first line to the function.
Would people using trunk rather have this functionality sooner or should I delay this until the next major revision? Honestly I have no idea when that will be either.
Basically, it would simplify and greatly increase the usefulness of callbacks. The function prototype of the old collision callbacks looked like this:
Code: Select all
typedef int (*cpCollFunc)(cpShape *a, cpShape *b, cpContact *contacts, int numContacts, cpFloat normal_coef, void *data);
Code: Select all
typedef int (*cpCollFunc)(cpArbiter *arb, struct cpSpace *space, void *data);
Another feature that has been requested a couple of times was getting event callbacks when objects start and stop touching. Chipmunk stored this information internally, but it was locked up in the arbiter structs and was very hard to get at from within a callback. Being passed both the space and the arbiter allows you to check if the collision is brand new. The space also filters out old cached collision data stored in the arbiters each step. By adding a function pointer to the arbiter struct, it can call back into your code if a collision happened last step, but not this one.
Code: Select all
static void
untouch(void)
{
printf("untouched a wall\n");
}
// This function has existed for a while, but was not useful until now really
cpVect cpContactsSumImpulses(cpContact *contacts, int numContacts);
static void
printCollisionImpulse(cpArbiter *arb, void *unused)
{
cpVect j = cpContactsSumImpulses(arb->contacts, arb->numContacts);
printf("Collision impulse:%s magnitude:%f\n", cpvstr(j), cpvlength(j));
}
static int
collision(cpArbiter *arb, cpSpace *space, void *data){
// The old arguments would still be easy to get. I'd probably write helper/getter functions for these.
// int swapped = arb->swappedColl;
// cpShape *a = (swapped ? arb->b : arb->a);
// cpShape *b = (swapped ? arb->a : arb->b);
// cpContact *contacts = arb->contacts;
// int numContacts = arb->numContacts;
// cpFloat normal_coef = (swapped ? -1.0 : 1.0);
// Now for some neat new stuff
if(space->stamp == arb->stamp){ // if these are equal, the collision is brand new
printf("Just touched a wall\n");
// Need to come up with a name and some useful arguments, but arb->func() will
// be called when the objects untouch.
arb->func = untouch;
// Let's register a post step callback to further process the arbiter
cpSpaceAddPostStepCallback(space, (cpPostStepFunc)printCollisionImpulse, arb, space);
} else {
// This collision is not brand new, do something else maybe?
}
return 1;
}
Would people using trunk rather have this functionality sooner or should I delay this until the next major revision? Honestly I have no idea when that will be either.