Using the Chipmunk physics engine in Star Fighter X2 was great as I got to learn something new and was able to flex some basic math muscles that I hadn’t had a chance to use in years.
I’d like to provide an overview of the basic structure and flow of how collisions and object relationships are setup and handled in Chipmunk.
In the beginning, there was
-(id) init;
- always remember to initialize the Chipmunk engine (cpInitChipmunk)
- initialize any required cpBody’s/cpShapes and associated Sprites
- setup the collision handler method (cpSpaceAddCollisionHandler)
- schedule the main [step:] loop
2) Bodies and Shapes and Sprites, Oh My!
There’s not much to say about point (1), just do it.
Moving on…
Some of the required bodies for SFX2 were two spaceships, randomly generated numbers of three different sizes of asteroids, and static shapes that defined the boundaries of the playable areas.
One important thing to consider is what bodies will be colliding and what bodies will simply ignore interaction. There is a collision_type property in cpShape that allows you to identify the category or type of body it is. You can eventually use that property to define the collision behaviour.
A cpShape also allows you set a void *data object that you can use to carry important data for later processing in callback methods. For example, with each asteroid or ship, I would set a new data object that would track the associated sprite(s), projectile type, and asteroid rock type.
3) Collision Handler
Chipmunk’s collision support is handled via the method:
void cpSpaceAddCollisionHandler( cpSpace *space, cpCollisionType a, cpCollisionType b, cpCollisionBeginFunc begin, cpCollisionPreSolveFunc preSolve, cpCollisionPostSolveFunc postSolve, cpCollisionSeparateFunc separate, void *data );
The fourth parameter is the callback function that you would use to handle the collisions as they happen.
Here is an example of a ‘begin’ callback:
static int begin(cpArbiter *arb, cpSpace *mainSpace,
void *ignore) {
// use this macro to declare two shapes and call
// cpArbiterGetShapes which uses the cpArbiter
// which contains info on the collision such as
// the shapes involved, contacts, normals, etc.
CP_ARBITER_GET_SHAPES(arb, a, b);
// use the data property of the cpShape to pull
// out your custom data object
SpaceData * shapeDataA = a->data;
SpaceData * shapeDataB = b->data;
if ( /* a should collide with b */ ) {
return TRUE;
} else if ( /* a should avoid b */ ) {
return FALSE;
}
}
Collisions would be checked via this callback at every step iteration.
One important thing to consider is how to manage your bodies during collisions. Say, for instance, you would have an asteroid and ship collide. After enough collisions, the asteroid might explode and go away. You might be tempted to try to remove the body and shape at this point, right from the begin callback. By design, changes to space aren’t able to be done safely in mid-step.
You would accomplish the removal of the element(s) by using a post-step callback.
Therefore, if ‘a’ should collide with ‘b’, and ‘b’ should go away, then you would call the following:
cpSpaceAddPostStepCallback(space, (cpPostStepFunc)postStepRemove, b, NULL);
Your postStepRemove would then look something like this:
static void postStepRemove(cpSpace * mainSpace, cpShape *shape,
void *unused) {
cpSpaceRemoveBody(mainSpace, shape->body);
cpSpaceRemoveShape(mainSpace, shape);
// remove the associated sprite from the main
// layer, won't cover that here
cpBodyFree(shape->body);
cpShapeFree(shape);
}
This callback function would then be called after the step iteration finishes and it would then attempt to clean up the body, shape, and sprite for ‘b’.
4) Step Loop
As is typical for game loop processing, the step loop would iterate through all bodies involved in the system and allow you to respond to shifts in motion and behaviour as the bodies would interact.
General Concepts in Math & Physics
As is typical in physics simulations, you need to know your stuff about vectors and how to manipulate them. Think back to your high school physics and how to deal with normals, vector multiplication, cross products, addition and subtractions. That’s only a few of the operations you’ll likely need. Chipmunk does a lot of the dirty work for you, but you will still need to know how to apply the ops.
Check out cpVect.h and you’ll find a number of them already provided for you:
cpvadd, cpvsub, cpvmult, cpvdot, cpvcross… and many more.
Cocos2d also provides some convenience methods and macros that allow you to do some quick angle math.
CC_DEGREES_TO_RADIANS (also RADS to DEG)
ccpForAngle will convert an angle in rads to a unit vector of direction clockwise with respect to the x-axis
ccpToAngle takes a normalized vector and returns the angle between it and the x-axis
Check out the CGPointExtension header file to get a rundown of all the support available.
Thanks for reading! Hopefully this provides you with a bit of insight as to the general flow of managing your physics system in Chipmunk within the game loop.
If I’ve messed up a description or mis-interpreted how anything works, please let me know!
This post is part of iDevBlogADay, a group of indie iOS development blogs featuring two posts per day. You can keep up with iDevBlogADay through the web site, RSS feed, or Twitter.




