Chipmunk Tutorial for iOS: How To Create A Simple iPhone Game

Ray Wenderlich
Create a simple game with Chipmunk physics!

Create a simple game with Chipmunk physics!

Recently Rod Strougo and I gave a workshop titled Cocos2D Via Minigames at the Voices That Matter iPhone Conference in Seattle.

We had an awesome time and really enjoyed meeting those who attended, and hope you guys enjoyed it as much as we did!

One of the minigames we made in the workshop was “Cat Nap”, a simple puzzle game using Chipmunk physics.

It’s about a cat who has had a very rough day and wants to sleep, but there are tons of bricks blocking his way!

Your job is to tap the bricks that block the way to destroy them, so the cat can land in his bed. But don’t wake the cat!

Since I haven’t written a Chipmunk Physics tutorial on this site yet, I thought you guys might enjoy if I converted the workshop slides & demo into tutorial form, for those who were unable to attend (or who want to review it again!)

This Chipmunk Physics tutorial assumes you are already familiar with the basics of Cocos2D, including sprites, actions, spritesheets, and animations. If you are new to these concepts, you might want to review some of the other Cocos2D tutorials on this site first.

So without further ado, let’s dive into Chipmunk!

What Is Chipmunk?

Chipmunk is a game physics library written in C, that comes as part of Cocos2D. With it, you can make objects in your game behave like real life objects – they can be affected by gravity, collide into other objects, bounce around, and much more.

Chipmunk was created by Scott Lembcke. It was originally based on Erin Catto‘s Box2D physics library (which also ships with Cocos2D), but has diverged quite a bit since then.

There are several differences between Chipmunk and Box2D which Rod and I cover in our upcoming cocos2D book, but suffice it to say that both are great libraries, and you can’t go wrong with either one!

Obviously this tutorial is about Chipmunk, so that is what we’ll be using here :]

How Does Chipmunk Work?

Chipmunk simulates physics behavior in a “virtual Chipmunk space”. It’s your job to:

Add objects to this space. Examples: shapes representing animals, flowers, or Muppets.

Adding objects to the Chipmunk virtual space

Tell Chipmunk about any forces that are acting upon these objects. Examples: gravity, wind, alien tractor beams, etc.

Specifying forces, impulses, gravity in Chipmunk virtual space

Occasionally give Chipmunk time to update the simulation. Examples: Chipmunk might calculate an animal falling a little bit more since last time, a flower bending slightly in the wind, of Gonzo might getting pulled in the air

Stepping Chipmunk virtual space

Update your “real” Cocos2D world based on the physical simulation. Examples: Set your animal, flower, or muppet sprites to be the same position as where Chipmunk says the virtual bodies are.

Setting positions of sprites based on Chipmunk bodies

The key thing to understand about the above is Chipmunk-land is completely different than Cocos2D-land.

Bodies and Shapes

There’s one more thing you should understand before we dive into code: the concept of Chipmunk bodies and shapes.

A Chipmunk body represents an object in the Chipmunk virtual space. It can contain one or more Chipmunk shapes that represent the object’s geometry, as you can see below.

Chipmunk Bodies and Shapes

This picture shows the Chipmunk body we’ll be using to represent the cat bed. It has three Chipmunk shapes inside – one for the left side of the bed, one for the right side of the bed, and one for the bottom of the bed.

There are two kinds of Chipmunk bodies:

  1. Dynamic bodies are bodies that can move – you’ll be using these most of the time.
  2. Static bodies are bodies that never move – these are good to use for the ground in your game and other permanent fixtures.

For each Chipmunk body, you can specify how much mass it has. The more mass a shape has, the harder it is to move around and the heavier it becomes.

When you create shapes, you can specify whether they are boxes, circles, polygons, or segments (which are straight lines with a thickness). On each shape, you can set several properties, including the following:

  • elasticity: Represents how bouncy an object is. If you set this to 0, it’s not bouncy at all. If you set it to 1, it bounces back up with the same exact force it bounced down. If you set it higher to 1, it bounces away with an even higher force!
  • friction: Represents how slippery an object is. If you set this to 0, it’s extremely slippery. If you set this to 1 or higher, it’s not very slippery at all.

Hello, Chipmunk!

Enough talk – let’s walk the Chipmunk walk!

Start up Xcode (we’ll be using Xcode 4 in this tutorial), and go to File\New\New Project. Choose the iOS\cocos2d\cocos2d_chipmunk template, and click Next. Name the project CatNap, and save it somewhere on your hard drive.

Before doing anything else, compile and run the project. At this point, you should see a strange little dude in your simulator:

Chipmunk Cocos2D Template Starter Code

Who this dude is, and why his name is “Grossini”, I have no idea.

Update: Ricardo Quesada has been kind enough to reveal the secret origins of Grossini! If you want to see for yourself (along with some Star Wars and naked angels), download this game by Riq! Note you’ll need the to download the Pygame Mac OSX installer and run “python game.py” to play the game! :]

But this little demo does demonstrate a few cool things Chipmunk can do. If you click around the screen you’ll can create some more of these dudes, and they’ll collide with each other and knock each other around:

Chipmunk Template Starter Project with Multiple Dudes

It’s even cooler if you try it on your device – the objects will move around with gravity and the accelerometer.

You can learn some neat things about Chipmunk by going through this sample code that comes with the template, but for this tutorial we’re just going to toss that over our shoulder, much like Boston Rob did with the immunity idol clue in this season’s Survivor.

And we’re going to do it all from scratch, mwuhahaha! Not because I’m a glutton for punishment, but because it will be easier to understand how everything works that way.

But don’t worry – if you don’t care about all the initial setup details and feel like this guy:

"F that!" guy

Feel free to download this starter project with the “Starting from Scratch” Chipmunk code pre-integrated and skip the next two sections :]

Otherwise, read on!

Starting from Scratch

So go to File\New\New File, choose iOS\Cocoa Touch\Objective-C class, and click Next. Enter CCLayer for Subclass of, click Next, name the new class ActionLayer.m, and click Finish.

Once that’s done, open up ActionLayer.h and replace it with the following:

#import "cocos2d.h"
 
@interface ActionLayer : CCLayer {
 
}
 
+ (id)scene;
 
@end

Here you’re creating just a standard CCLayer. We’ll eventually put the Chipmunk code in here, but for now it will just be blank.

Then switch to ActionLayer.m and replace it with the following:

#import "ActionLayer.h"
 
@implementation ActionLayer
 
+ (id)scene {
    CCScene *scene = [CCScene node];
    ActionLayer *layer = [ActionLayer node];
    [scene addChild:layer];
    return scene;
}
 
- (id)init {
    if ((self = [super init])) {        
        CGSize winSize = [CCDirector sharedDirector].winSize;
 
        CCLabelBMFont *label = [CCLabelBMFont labelWithString:@"Hello, Chipmunk!" fntFile:@"Arial.fnt"];
        label.position = ccp(winSize.width/2, winSize.height/2);
        [self addChild:label];
    }
    return self;
}  
 
@end

This code does the following:

  • The scene method creates a CCScene, adds a single layer to it (ActionLayer), and returns it.
  • The init method simply puts a label in the middle of the screen that says “Hello, Chipmunk!”

Note this uses CCLabelBMFont to display the text, because I’ve sworn off ever using CCLabelTTF again due to it’s insane slowness.

If you haven’t used CCLabelBMFont before, notice that the last parameter specifies a bitmap font to use to display the text – called Arial.fnt here.

If you’d like, you can create this your own bitmap font file using Glyph Designer (recommended) or Hiero, or you can download one I’ve already made in the resources for this tutorial.

Once you’ve either made a font file (or downloaded the one I made), add it to your project.

Once you’re done, open up AppDelegate.m and make the following changes:

// Add to top of file
#import "ActionLayer.h"
 
// Modify call to replaceScene at bottom of applicationDidFinishLaunching to the following
[[CCDirector sharedDirector] runWithScene: [ActionLayer scene]];

If all works well, you should see the the following:

Starting from Scratch with Chipmunk

At this point you have a “blank slate” that we can start adding the Chipmunk code to. Time for the fun stuff!

Creating a Basic Chipmunk Scene

There are seven steps to create a basic Chipmunk scene that you can use as a starting point for your projects.

Most of the time, I still follow these steps myself when making a new Chipmunk project, just to have a good “home base” to start from.

Rather than me blabbing on about it, let’s just practice doing each one, one at a time.

1. Initialize Chipmunk

The first step is to initialize the Chipmunk library. You should only do this once, so a good place is inside applicationDidFinishLaunching.

Let’s try this out. Open up AppDelegate.m and add the following changes:

// Add to top of the file
#import "chipmunk.h"
 
// In applicationDidFinishLaunching, right before call to runWithScene
cpInitChipmunk();

That’s it! This is probably the easiest thing you’ll do with Chipmunk, lol. You just have to remember that you should only call this once, otherwise you’ll get a memory leak.

2. Create Chipmunk space

The next step is to create a virtual Chipmunk space for it to run the physics simulation in.

There’s an object that represents the Chipmunk space called cpSpace – you just need to create it an initialize it.

Switch to ActionLayer.h and make the following modifications:

// At top of file
#import "chipmunk.h"
 
// Inside @interface
cpSpace *space;

Here you’re just importing the chipmunk header, and declaring an instance variable to keep track of the Chipmunk space, because you’ll be using it a lot!

Then switch to ActionLayer.m and make the following modifications:

// Add new method before init
- (void)createSpace {
    space = cpSpaceNew();
    space->gravity = ccp(0, -750);
    cpSpaceResizeStaticHash(space, 400, 200);
    cpSpaceResizeActiveHash(space, 200, 200);
}
 
// Comment out the lines that create the label in init, and add this:
[self createSpace];

As you can see, the important lines are in createSpace. The first line calls cpSpaceNew to create a new object for the Chipmunk virtual space, and stores it in the space instance variable.

The second line sets the Chipmunk gravity to be nothing along the x-axis, and a decent amount down on the y-axis. As for what values to put here, it’s really a matter of tweaking to whatever “feels right” for your game.

The final two lines create the Chipmunk static and active hashes. This is just an optimization Chipmunk uses to speed up collision detection.

It basically divides up the Chipmunk space into a grid. Then if two objects are in different grid cells, Chipmunk knows instantly they don’t collide, and doesn’t have to do any further math.

So with these calls you’re setting up the size of a grid cell (second parameter), and the number of grid cells (third parameter). The recommendation is to set the size of the grid cell bigger than your average object, and the number of grid cells at least 10x greater than the number of objects in your game.

For a simple games this won’t matter, but keep in mind this is something you may want to tweak if performance is critical for your game.

3. (Optional) Add “ground”

For many games, it can be helpful to add objects to your Chipmunk space to represent the ground of your level.

For example, in this minigame we’re going to create a line segment shape from the bottom left to the bottom right. This way, when we create an object it will collide with the ground, rather than falling right off the screen!

To add the ground, make the following modifications to ActionLayer.m:

// Add new method
- (void)createGround {    
    // 1
    CGSize winSize = [CCDirector sharedDirector].winSize; 
    CGPoint lowerLeft = ccp(0, 0);
    CGPoint lowerRight = ccp(winSize.width, 0);
 
    // 2
    cpBody *groundBody = cpBodyNewStatic();
 
    // 3
    float radius = 10.0;
    cpShape *groundShape = cpSegmentShapeNew(groundBody, lowerLeft, lowerRight, radius);
 
    // 4
    groundShape->e = 0.5; // elasticity
    groundShape->u = 1.0; // friction 
 
    // 5
    cpSpaceAddShape(space, groundShape);    
}
 
// Add inside init method, right after call to createSpace
[self createGround];

This is the first time you’ve seen how to add objects to the Chipmunk scene, so let’s go through this section by section.

  1. We’re going to make the ground as a line from the lower left of the screen to the lower right of the screen, so this gets the coordinates of these for future reference.
  2. Creates a new Chipmunk body – a static body, because it never moves. Usually you have to add the body to the scene, but you don’t have to for static bodies. In fact, if you do add it, it will cause dynamic bodies to fall through the ground! I’m not actually sure why this is, so if anyone knows please chime in.
  3. Creates a new segment shape and associates it to the body just created.
  4. Sets the elasticity to be somewhat bouncy, and the friction to be not very slippery.
  5. Adds the shape to the Chipmunk space.

4. (Optional) Add bodies/shapes

Next, we’re going to create a helper routine to add a dynamic (movable) Chipmunk body to the scene, and call it a few times to create a few boxes.

// Add new method
- (void)createBoxAtLocation:(CGPoint)location {
 
    float boxSize = 60.0;
    float mass = 1.0;
    cpBody *body = cpBodyNew(mass, cpMomentForBox(mass, boxSize, boxSize));
    body->p = location;
    cpSpaceAddBody(space, body);
 
    cpShape *shape = cpBoxShapeNew(body, boxSize, boxSize);
    shape->e = 1.0; 
    shape->u = 1.0;
    cpSpaceAddShape(space, shape);
 
}
 
// Add in init, after call to createGround
[self createBoxAtLocation:ccp(100,100)];
[self createBoxAtLocation:ccp(200,200)];

This should look pretty similar to step 3, with two main differences.

The first difference is instead of calling cpBodyNewStatic, you’re just calling cpBodyNew to create a dynamic (movable) body.

Notice how when you call cpBodyNew you have to pass in mass and a “moment of inertia.” We’ve already talked about mass, and the “moment of inertia” has to do with how hard a body is to rotate. To figure out what to put for that parameter, you can just call a helper routine to calculate it, based on the type of shape(s) you’re adding to the body.

The second difference is it’s creating a box shape instead of a segment shape, so it calls cpBoxShapeNew (which takes a width and height) rather than cpSegmentShapeNew.

So we can call this routine twice to add two different bodies to the scene, just to have something to play around with for now.

5. Step sim in update loop

We need to give Chipmunk time to perform the simulation every frame. I’ll show you the simplest possible way to do this now – later on in the article I’ll discuss a better way.

// In init after calls to createBoxAtLocation
[self scheduleUpdate];
 
// Add new method
- (void)update:(ccTime)dt {
    cpSpaceStep(space, dt);
}

The first thing we do here is call scheduleUpdate in the initializer, which tells Cocos2D to call a method on the layer (update) every frame.

The update method then simply gives Chipmunk time to run the simulation, by calling cpSpaceStep.

6. (Optional) Enable debug draw

At this point the simulation would actually run, but you would’t see anything on the screen.

To visualize what’s going on in the Chipmunk virtual space, you can use some classes that draw visual representations of the Chipmunk bodies to the scene. It works by looping through each Chipmunk body, and then drawing a representation to the screen using OpenGL commands.

Let’s try this out. Inside the resources for this tutorial under “Helper Code”, you’ll find drawSpace.c and drawSpace.h. Drag these into your project, make sure “Copy items into destination group’s folder (if selected)” is checked, and click Finish.

Important step: drawSpace.c won’t compile correctly unless you change a setting on it first. To do this in Xcode 4, select drawSpace.c, then click the third tab in the toolbar’s “View” section to bring up the Utilities window. In the dropdown for “File Type”, change the entry from “Default – C source” to “Objective-C source”, as you can see in the screenshot below.

Setting the file type to Objective-C source for .c files in Xcode 4

Next, switch to ActionLayer.m and add this to the top of the file:

#import "drawSpace.h"

Then implement the draw method to call the helper routine in drawSpace.c/h as follows:

- (void)draw {
 
    drawSpaceOptions options = {
        0, // drawHash
        0, // drawBBs,
        1, // drawShapes
        4.0, // collisionPointSize
        4.0, // bodyPointSize,
        2.0 // lineThickness
    };
 
    drawSpace(space, &options);
 
}

As you can see here, the first step is to tell the function what it should draw. Here we tell it not to draw a visualization of the Chipmunk hash (which I don’t think works on the iPhone anyway), not to draw the bounding boxes, but to draw the shapes themselves (the most important part). It also sets some values for the point sizes and line thickness.

At this point, you can finally compile and run! If all goes well, you should see a few bodes fall onto the ground, bounce a bit, and then settle down:

Debug draw with Cocos2D and Chipmunk Physics

But unfortunately after the boxes drop, they just sit there forever. It would be cool (and useful for debugging) if we could move the objects around by dragging them, so let’s add that next!

7. (Optional) Add mouse joints

Inside the resources for this tutorial under “Helper Code”, you’ll find cpMouse.c and cpMouse.h. Drag these into your project, make sure “Copy items into destination group’s folder (if selected)” is checked, and click Finish.

After adding the files, change the file type for cpMouse.c to “Objective-C source” the same way you did for drawSpace.c.

Then open up ActionLayer.h and make the following changes:

// At top of file
#import "cpMouse.h"
 
// Inside @interface
cpMouse *mouse;

This just imports the header file, and makes an instance variable to keep track of the mouse joint.

Next switch to ActionLayer.m and make the following changes:

// Inside init, after call to scheduleUpdate
mouse = cpMouseNew(space);
self.isTouchEnabled = YES;
 
// Add new methods
- (void)registerWithTouchDispatcher {
    [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
}
 
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
    CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
    cpMouseGrab(mouse, touchLocation, false);
    return YES;
}
 
- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event {
    CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
    cpMouseMove(mouse, touchLocation);
}
 
- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
    cpMouseRelease(mouse);
}
 
- (void)ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event {
    cpMouseRelease(mouse);    
}
 
- (void)dealloc {
    cpMouseFree(mouse);
    cpSpaceFree(space);
    [super dealloc];
}

This should be pretty self-explanatory – it enables touch handling, then calls some methods in the helper code to initialize the mouse joint, grab something on a touch down, move it on a touch move, and release it on a touch ended or cancelled.

Compile and run your code, and now you should be able to move objects around by dragging them!

Decorating with Sprites

If you’ve downloaded the starter project and skipped ahead, here’s where you should pick back up – welcome back!

Now that you’ve got a basic Chipmunk scene in place, let’s get this game started by adding a some actual game art into the scene.

So start by adding the art! Open up the resources for this tutorial and drag the Spritesheets folder into your Xcode project. Make sure “Copy items into destination group’s folder (if needed)” is checked, and click Finish.

If you take a look at the sprite sheet, you’ll see the images you’ll be using in this game:

Sprite sheet for Cat Nap Minigame

First you’ll be creating a Chipmunk body and box shape to represent the cat, as well as the orange and black bricks that block the cat’s way to the bed.

But how do you associate a Chipmunk body with a Cocos2D sprite? It’s simple – you just set the position/angle of the sprite to be the same as the position/angle of the Chipmunk body, each frame.

And how do you keep track of which Chipmunk body a sprite should “follow”? There are several ways to do this, but here’s the approach we’re going to take:

  • Create a subclass of CCSprite called CPSprite (for Chipmunk sprite).
  • Have it keep track of which Chipmunk body the sprite is “following”.
  • Create a method on CPSprite called update, that sets its position/angle to the position/angle of the Chipmunk body.
  • For each CPSprite in the layer, call update each frame.

Let’s see how this works. Go to File\New\New File, choose iOS\Cocoa Touch\Objective-C class, and click Next. Enter CCSprite for “Subclass of”, click Next, name the file CPSprite.m, and click Save.

Then replace CPSprite.h with the following:

#import "cocos2d.h"
#import "chipmunk.h"
 
@interface CPSprite : CCSprite {
    cpBody *body;
    cpShape *shape;
    cpSpace *space;
    BOOL canBeDestroyed;
}
 
@property (assign) cpBody *body;
 
- (id)initWithSpace:(cpSpace *)theSpace location:(CGPoint)location spriteFrameName:(NSString *)spriteFrameName;
- (void)update;
- (void)createBodyAtLocation:(CGPoint)location;
- (void)destroy;
 
@end

First, this imports the headers for Chipmunk and Cocos2D. It then creates instance variables to keep track of the Chipmunk body that it is following, along with the Chipmunk space and shape. It also has a boolean to keep track of whether this object should be able to be destroyed when the user taps on it.

It then defines an initializer for the object, and predeclares the method to update the sprite’s position/rotation based on the Chipmunk body it’s following, the method to create a Chipmunk body/shape based on the sprite’s size, and a method to destroy the Chipmunk body/shape and sprite.

Let’s implement this next. Switch to CPSprite.m and replace it with the following:

#import "CPSprite.h"
 
@implementation CPSprite
@synthesize body;
 
- (void)update {    
    self.position = body->p;
    self.rotation = CC_RADIANS_TO_DEGREES(-1 * body->a);
}
 
- (void)createBodyAtLocation:(CGPoint)location {
 
    float mass = 1.0;
    body = cpBodyNew(mass, cpMomentForBox(mass, self.contentSize.width, self.contentSize.height));
    body->p = location;
    body->data = self;
    cpSpaceAddBody(space, body);
 
    shape = cpBoxShapeNew(body, self.contentSize.width, self.contentSize.height);
    shape->e = 0.3; 
    shape->u = 1.0;
    shape->data = self;
    cpSpaceAddShape(space, shape);
 
}
 
- (id)initWithSpace:(cpSpace *)theSpace location:(CGPoint)location spriteFrameName:(NSString *)spriteFrameName {
 
    if ((self = [super initWithSpriteFrameName:spriteFrameName])) {
 
        space = theSpace;
        [self createBodyAtLocation:location];
        canBeDestroyed = YES;
 
    }
    return self;
 
}
 
- (void)destroy {
 
    if (!canBeDestroyed) return;
 
    cpSpaceRemoveBody(space, body);
    cpSpaceRemoveShape(space, shape);
    [self removeFromParentAndCleanup:YES];
}
 
@end

The update method is very simple. It sets the position of the sprite to be the same as the position of the Chipmunk body. It does the same thing for the rotation, except it has to do a little conversion (because Cocos2D uses degrees rather than radians, and rotations are clockwise rather than counterclockwise).

createBodyAtLocation is very similar to the createBoxAtLocation code you wrote earlier – it first creates a body, then creates a box shape on that body. The main difference is that it sets the size of the box equal to the size of the sprite (the contentSize).

Also, another difference is that it sets the data pointer of the body and shape equal to self (the sprite). This is so that if you have a Chipmunk body or shape, you can get the sprite associated with it through the data pointer, as you’ll see later.

initWithSpace first calls initwithSpriteFrameName on its superclass (CCSprite), then sets up the instance variables and makes the call to create the body.

destroy simply calls cpSpaceRemoveBody and cpSpaceRemoveShape to destroy the body/shape upon request. It also calls removeFromParentAndCleanup to remove the sprite itself.

Now that you have this class in place, you could use it to add the cat sprite and block sprites into the scene just by calling the initializers. But to make things a little bit nicer and more extensible, we’re going to create subclasses for these next.

Subclasses for Sprites

These are very simple so we’re going to go through these quickly. Go to File\New\New File, choose iOS\Cocoa Touch\Objective-C class, and click Next. Enter CPSprite for “Subclass of”, click Next, name the file CatSprite.m, and click Save.

Open CatSprite.h and replace it with the following:

#import "CPSprite.h"
 
@interface CatSprite : CPSprite {
}
 
- (id)initWithSpace:(cpSpace *)theSpace location:(CGPoint)location;
 
@end

Then open CatSprite.m and replace it with the following:

#import "CatSprite.h"
 
@implementation CatSprite
 
- (id)initWithSpace:(cpSpace *)theSpace location:(CGPoint)location {
    if ((self = [super initWithSpace:theSpace location:location spriteFrameName:@"cat_sleepy.png"])) {
        canBeDestroyed = NO;        
    }
    return self;
}
 
@end

As you can see, not much is going on here except it sets the name of the image to use, and sets canBeDestroyed to be NO.

Now go to File\New\New File again, choose iOS\Cocoa Touch\Objective-C class, and click Next. Enter CPSprite for “Subclass of”, click Next, name the file SmallBlockSprite.m, and click Save.

Open up SmallBlockSprite.h and replace it with the following:

#import "CPSprite.h"
 
@interface SmallBlockSprite : CPSprite {
 
}
 
- (id)initWithSpace:(cpSpace *)theSpace location:(CGPoint)location;
 
@end

Then replace SmallBlockSprite.m with the following:

#import "SmallBlockSprite.h"
 
@implementation SmallBlockSprite
 
- (id)initWithSpace:(cpSpace *)theSpace location:(CGPoint)location {
    if ((self = [super initWithSpace:theSpace location:location spriteFrameName:@"block_1.png"])) {
    }
    return self;
}
 
@end

One last file. Go to File\New\New File again, choose iOS\Cocoa Touch\Objective-C class, and click Next. Enter CPSprite for “Subclass of”, click Next, name the file LargeBlockSprite.m, and click Save.

Replace LargeBlockSprite.h with the following:

#import "CPSprite.h"
 
@interface LargeBlockSprite : CPSprite {
 
}
 
- (id)initWithSpace:(cpSpace *)theSpace location:(CGPoint)location;
 
@end

Then replace LargeBlockSprite.m with the following:

#import "LargeBlockSprite.h"
 
@implementation LargeBlockSprite
 
- (id)initWithSpace:(cpSpace *)theSpace location:(CGPoint)location {
    if ((self = [super initWithSpace:theSpace location:location spriteFrameName:@"block_2.png"])) {
    }
    return self;
}
 
@end

Ok, phew! Now let’s put these to use by creating a few instance of these sprites and adding them to the layer.

Switch to ActionLayer.h and make the following changes:

// Import at top of file
#import "CatSprite.h"
#import "SmallBlockSprite.h"
#import "LargeBlockSprite.h"
 
// Add inside @interface
CCSpriteBatchNode *batchNode;
CatSprite *cat;

This imports the headers you just made, and adds an instance variable to keep track of the sprite batch node, and one to keep track of the cat sprite.

Then switch to ActionLayer.m and add the following at the end of your init method (right after setting isTouchEnabled = YES):

[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"catnap.plist"];
batchNode = [CCSpriteBatchNode batchNodeWithFile:@"catnap.png"];
[self addChild:batchNode];
 
cat = [[[CatSprite alloc] initWithSpace:space location:ccp(245, 217)] autorelease];
[batchNode addChild:cat];  
 
SmallBlockSprite *block1a = [[[SmallBlockSprite alloc] initWithSpace:space location:ccp(213, 47)] autorelease];
[batchNode addChild:block1a];
 
SmallBlockSprite *block1b = [[[SmallBlockSprite alloc] initWithSpace:space location:ccp(272, 59)] autorelease];
[batchNode addChild:block1b];
 
SmallBlockSprite *block1c = [[[SmallBlockSprite alloc] initWithSpace:space location:ccp(267, 158)] autorelease];
[batchNode addChild:block1c];
 
LargeBlockSprite *block2a = [[[LargeBlockSprite alloc] initWithSpace:space location:ccp(270, 102)] autorelease];
[batchNode addChild:block2a];
cpBodySetAngle(block2a.body, CC_DEGREES_TO_RADIANS(90));
 
LargeBlockSprite *block2b = [[[LargeBlockSprite alloc] initWithSpace:space location:ccp(223, 139)] autorelease];
cpBodySetAngle(block2b.body, CC_DEGREES_TO_RADIANS(90));
[batchNode addChild:block2b];
 
LargeBlockSprite *block2c = [[[LargeBlockSprite alloc] initWithSpace:space location:ccp(214, 85)] autorelease];
[batchNode addChild:block2c];

This creates a sprite batch node with the art from the resources folder, and loads all of the sprite frame info into the cache. It then makes several sprites using the subclasses you just made – which also makes a Chipmunk body/shape for each sprite to “follow” as part of the process.

Of course, to get the sprites to actually follow the Chipmunk bodies, you have to call their update method each frame. So add this to the bottom of your update method:

for (CPSprite *sprite in batchNode.children) {
    [sprite update];
}

Compile and run your project, and you should see your cat sitting across several blocks!

Decorating Chipmunk bodies with Cocos2D Sprites

You can get rid of those extra blocks by commenting out the calls to createBoxAtLocation in your init method too.

Sounds and Destruction!

So far so good, except we want to be able to tap the blocks to destroy them rather than moving them around with mouse joints for this game. We’d also like some sound effects, and to put a background into the scene.

So drag the Sounds folder from the resources for this Chipmunk tutorial into your Xcode project, make sure “Copy items into destination group’s folder (if needed)” is checked, and click Finish.

Then open ActionLayer.m and comment out the calls to cpMouseGrab, cpMouseMove, and cpMouseRelease inside ccTouchBegan/Moved/Ended/Cancelled, because we won’t be using mouse joints anymore.

Once that’s done, make the following changes to ActionLayer.m:

// Add to top of file
#import "SimpleAudioEngine.h"
 
// Add to ccTouchBegan right after commented out call to cpMouseGrab
cpShape *shape = cpSpacePointQueryFirst(space, touchLocation, GRABABLE_MASK_BIT, 0);
if (shape) {
    CPSprite *sprite = (CPSprite *) shape->data;
    [sprite destroy];
    [[SimpleAudioEngine sharedEngine] playEffect:@"poof.wav"];
}

This code checks to see which shape is at the touch location by using the cpSpacePointQueryFirst helper function included with Chipmunk. It then gets the CPSprite associated with that shape by using the data pointer. Remember that we set that up in createBodyAtLocation in CPSprite.

It also plays a sound effect for fun. Speaking of which, go ahead and add the background music, the background art, and preload the sound effects, by adding the following to the bottom of your init method:

CCSprite *background = [CCSprite spriteWithFile:@"catnap_bg.png"];
background.anchorPoint = CGPointZero;
[self addChild:background z:-1];
 
[[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"TeaRoots.mp3" loop:YES];
[[SimpleAudioEngine sharedEngine] preloadEffect:@"sleep.wav"];
[[SimpleAudioEngine sharedEngine] preloadEffect:@"wake.wav"];
[[SimpleAudioEngine sharedEngine] preloadEffect:@"poof.wav"];

Compile and run, and you should now have the start of a game – tap the blocks to destroy them!

Basics of Cat Nap minigame functional!

Polygon Shapes

Cat Nap is coming along well so far, but one of the main problems is the shape for the cat doesn’t match up well at all. You’re using a box sized the same as the cat artwork, but that leaves a lot of transparent space and things don’t look quite right!

In Chipmunk, you aren’t restricted to just simple shapes such as boxes, circles, or segments – you can also use polygon shapes. You just tell Chipmunk the location of each vertex in the polygon, and it works just like any other kind of shape!

But how do you get the vertices? You could open up the cat image in an image editor and measure out the distances, but there’s an easier way – use a tool called Vertex Helper by Johannes Fahrenkrug.

If you don’t have it already, go ahead and download Vertex Helper from its github page. It comes in source format only, so you’ll have to open up the project and compile it to use it. If you are too lazy, you can also purchase it on the Mac App Store :]

Once you have it compiling and running, you should see a window like this:

Vertex Helper Screenshot

Drag the cat_sleepy.png from the “Raw Art” folder in the resources for this Chipmunk tutorial into Vertex Helper, the make the following setting changes:

  • Set Rows/Cols to 1/1
  • Set Type to Chipmunk
  • Set Style to Initialization
  • Click “Edit Mode” in the top toolbar

Then click around the cat to define your vertices. Some very important things to keep in mind when you do:

  • You must click your vertices in clockwise order for Chipmunk. (Note: it’s counter-clockwise for Box2D!)
  • You should aim to keep your vertex count as small as you can. For this cat, I think 4 do just fine.
  • You do not need to connect the first and last points – Vertex Helper will do that automatically (and draw a light gray line to indicate this).
  • Your polygon must be convex. This means that you can’t have any interior angles of greater than 180 degrees, as you can see in the diagram below.

Convex Vs Concave Shapes

Here’s a screenshot for how I defined the vertices for the cat (yours may vary slightly):

Tracing a polygon shape with Vertex Helper

Once you’re done, copy the code from the output box of Vertex Helper, and then put it in a new method inside CatSprite.m as follows:

- (void)createBodyAtLocation:(CGPoint)location {
 
    // Add your vertices from Vertex Helper here
    int num = 4;
    CGPoint verts[] = {
        cpv(-31.5f, 69.5f),
        cpv(41.5f, 66.5f),
        cpv(40.5f, -69.5f),
        cpv(-55.5f, -70.5f)
    };
 
    float mass = 1.0;
    float moment = cpMomentForPoly(mass, num, verts, CGPointZero);
    body = cpBodyNew(mass, moment);
    body->p = location;
    cpSpaceAddBody(space, body);
 
    shape = cpPolyShapeNew(body, num, verts, CGPointZero);
    shape->e = 0.3; 
    shape->u = 0.5;
    cpSpaceAddShape(space, shape);
 
}

As you can see here, it’s quite similar to creating a box shape except it uses slightly different functions (cpMomentForPoly instead of cpMomentForBox, and cpPolyShapeNew instead of cpBoxShapeNew).

If you compile and run, you’ll see it *almost* works, except the shape is way too big!

The cat shape is too big!

This is because you traced the retina-sized art, which is double the size in pixels (but we need points). So divide all of your coordinates by 2, similar to the following:

int num = 4;
CGPoint verts[] = {
    cpv(-31.5f/2, 69.5f/2),
    cpv(41.5f/2, 66.5f/2),
    cpv(40.5f/2, -69.5f/2),
    cpv(-55.5f/2, -70.5f/2)
};

Compile and run yet again, and this time the cat shape should match up much more closely to the actual cat!

Correct sized polygon shape with Chipmunk

Where To Go From Here?

At this point, you understand the basics of Chipmunk and have hands-on experience doing the most important tasks – setting up a basic Chipmunk project, adding bodies and shapes, and decorating them with sprites.

In the Cocos2D Via Minigames workshop that Rod Strougo and I recently gave, we showed how to take the project even further and wrap it up into a complete game, by adding the cat bed, collision detection, and game logic.

However, this Chipmunk tutorial has gone on far enough for now so I’m going to wrap it up here. If you want to learn more, you can:

  • Download the completed CatNap project and take a look at the extra finishing touches
  • Check out the official Chipmunk documentation for more info
  • We have a chapter on Chipmunk in our upcoming Cocos2D book that shows you how to make a Metroid-style platformer jumping level
  • And also stay tuned on the Cocos2D book blog for an upcoming post where Rod will show you how to make the Penguin Toss minigame, which was the lab exercise from the workshop!

If you have any comments or questions about using Chipmunk in your games, please join in on the forum discussion below!

Ray Wenderlich

Ray is an indie software developer currently focusing on iPhone and iPad development, and the administrator of this site. He’s the founder of a small iPhone development studio called Razeware, and is passionate both about making apps and teaching others the techniques to make them.

When Ray’s not programming, he’s probably playing video games, role playing games, or board games.

User Comments

52 Comments

[ 1 , 2 , 3 , 4 ]
  • @bhcho99nz,
    Can't see the YOUTUBE video.

    Does basic Cocos2D work? Can you create a HelloWorld (no Box2D or Chipmunk)? If so, great.

    Here's the steps outlined in Ray and Rod's book "Learning Cocos2D".
    1) Using Finder, we would copy chipmunk from a folder (in the sample code from the book) from Chapter13/external/Chipmunk
    2) We would paste into our text book's project folder such as SpaceViking/libs.
    3) This should create a subfolder named Chipmunk.
    4) Now, drag and drop the new folder into XCODE which will prompt you "copy items"...uncheck this box. You've already made the copy by hand.
    5) One more note from the authors about this drag and drop. You can from within XCODE delete references only for folders other than SRC and INCLUDE
    6) Authors' last step would be to change BUILD SETTINGS -> ALL -> COMBINED -> SEARCH PATH -> HEADER SEARCH PATH...
    add the SpaceViking/libs?/Chipmunk/include/chipmunk
    7) I had to install the templates into XCODE (for new projects) by using Chipmunk Physics "install-template.sh". Open TERMINAL, cd to where you have the chipmunk sdk, and run the command "./install-template.sh"

    Now, try building HelloWorld
    larry
  • Nevermind. I had installed it incorrectly. Thanks for your help! Without any replies I would have given up :D Thanks
    bhcho99nz
  • Hi Ray,

    Finally, tutorials for Chipmunk that work!

    I get a SIGABRT when I add the background image here: [self addChild:background z:-1];

    >>>
    cocos2d: CCTexture2D. Can't create Texture. UIImage is nil
    2011-12-18 09:36:08.764 CatNap[5306:10a03] cocos2d: Couldn't add image:catnap_bg.png in CCTextureCache
    2011-12-18 09:36:08.765 CatNap[5306:10a03] *** Assertion failure in -[ActionLayer addChild:], /Users/jrota/Desktop/Jim/Apps/CatNap/CatNap/libs/cocos2d/CCNode.m:413
    2011-12-18 09:36:08.767 CatNap[5306:10a03] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Argument must be non-nil'
    >>>

    I figured it out...didn't copy over the /Background folder (because you didn't explicitly say so!)...

    Now it works.

    It would be nice to have a start/restart button.


    If I comment out the background image code it compiles and runs fine.
    mijator
  • I got to chapter 10 of the awesome book Learn Cocos2d: http://cocos2dbook.com/book/ and became very down in the dumps as Box2D just would not gel. I jumped out of the book and started on the Box2D tutorials on this site and still...no gel. :(

    Then I thought oh what the hell lets see what this ChipMunk is.....am I glad I did! This has been the most enjoyable well written tutorials I have worked through to date! I'm now off back to the book to see what there is there re CM, hopefully more tricks :)

    I dont know why Box2D evades me but every step of the way with the ChipMunk tutorial it just all made sense!

    Thanks for a fantastic tutorial :D
    elpuerco63
  • Hi! i m here again. I got a problem i am trying to use chipmunk6.x and having problem with it. it is not creating the physics environment. how to enable the chipmunk6.x in my old project. the space manager system is working well. I hope there is no problem with the chipmunk lib attachment.
    I am using the cocos2d old version I just replace the chipmunk lib.

    I thing you tutorial may need to be updated for the new chipmunk physics.
    bipul
  • when i downloaded and ran the code it was not working and showing 201 errors.........

    even when i tried to built it another way it was not showing any error still crashing.... what shall i do?
    umesheklavyasharma
  • Hi Ray, Thanks for this great tutorial, I am trying this, exactly in the step (6. (Optional) Enable debug draw), I am getting those error in drawSpace.c:

    -no member named node in struct cpbody
    -Use of undeclared identifier 'GL_COLOR_ARRAY'
    -/Users/Amine/Movies/CatNap/CatNap/drawSpace.c:139:23: Use of undeclared identifier 'GL_COLOR_ARRAY'

    Could you please help me to resolve those issues, I started today learning cocos2d :D

    Regards
    Vervatovskis
[ 1 , 2 , 3 , 4 ]

Other Items of Interest

Ray's Monthly Newsletter

Sign up to receive a monthly newsletter with my favorite dev links, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

Vote for Our Next Tutorial!

Every week, we alternate between Gaming and Non-Gaming tutorial votes. This week: Non-Gaming!

    Loading ... Loading ...

Last week's winner: How to Make a Simple 2D Game with Metal.

Suggest a Tutorial - Past Results

Hang Out With Us!

Every month, we have a free live Tech Talk - come hang out with us!


Coming up in October: Xcode 6 Tips and Tricks!

Sign Up - October

Our Books

Our Team

Tutorial Team

... 52 total!

Update Team

... 14 total!

Editorial Team

  • Alexis Gallagher

... 22 total!

Code Team

  • Orta Therox

... 3 total!

Subject Matter Experts

  • Richard Casey

... 4 total!