Box2D Tutorial for iOS: How to Use Box2D For Just Collision Detection With Cocos2D iPhone

A Box2D tutorial for iOS on how to use Box2D for just collision detection, in order to make detecting collisions for polygon shapes easy and accurate. By Ray Wenderlich.

Leave a rating/review
Save for later
Share

Cats vs. Car!

Cats Versus Car Screenshot

When making a game with Cocos2D, sometimes you may find yourself wanting to use Cocos2D actions to move your objects instead of using the Box2D physics engine. However that doesn’t mean you can’t still make use of the great collision detection support in Box2D!

This tutorial will show you how to use Box2D for just collision detection – not physics – step by step. We will create a simple demo of a car driving around the screen, laughing merrily as it runs over cats. Yes I know, I can be sadistic sometimes ;]

While we’re doing this, along the way we’ll also coves a couple new and interesting concepts, such as using sprite sheets, the Zwoptex utility, Box2D debug drawing, and the new VertexHelper utility.

This tutorial assumes you have gone through the other Box2D and Cocos2D tutorials, or that you have equivalent knowledge.

And before I forget – special credit goes to Kim from the comments section for suggesting writing this tutorial!

Sprites and Sprite Sheets

Before we begin, we’re going to take a brief detour to talk about sprites and sprite sheets.

So far when we have been using Cocos2D, we have been using the CCSprite class directly and passing in individual sprite images. But according to the Cocos2D best practices page, it’s a lot more efficient to use sprite sheets instead.

Sprite Sheet Example

The above is an example of a sprite sheet, part of a sprite sheet included in the Cocos2D sample code. Sprite sheets are basically one big image that can be chopped-up into sub images. To specify where each sub-image lies within the sprite sheet, you have to give Cocos2D the coordinates for each image. For example, here’s what it looks like to pull out the first four sprites from that sprite sheet:

CCSpriteSheet *sheet = [CCSpriteSheet 
    spriteSheetWithFile:@"grossini_dance_atlas.jpg" capacity:1];
CCSprite *sprite1 = [CCSprite spriteWithTexture:sheet.texture rect:
    CGRectMake(85*0, 121*1, 85, 121)];
CCSprite *sprite2 = [CCSprite spriteWithTexture:sheet.texture rect:
    CGRectMake(85*1, 121*1, 85, 121)];
CCSprite *sprite3 = [CCSprite spriteWithTexture:sheet.texture rect:
    CGRectMake(85*2, 121*1, 85, 121)];
CCSprite *sprite4 = [CCSprite spriteWithTexture:sheet.texture rect:
    CGRectMake(85*3, 121*1, 85, 121)];

As you can imagine, writing a lot of code like that with hard-coded coordinates can be quite tedious. Luckily, Robert Payne has written an incredibly handly web tool called Zwoptex that makes both creating sprite sheets and importing the coordinates into Cocos2D extremely easy.

Creating Our Sprite Sheet

Before we begin, you’ll need some images to work with. You can either use the car and cat images created by my lovely wife, or use your own.

Next, load up a web browser to Zwoptex. You will see a big blank screen that looks something like this:

Zwoptex Screenshot

Once it’s loaded up, inside Zwoptex click File, and then Import Images. Select the car and cat images that you downloaded and click select, and your images should appear on top of each other. Drag your images apart a bit so you can see them more clearly.

Note that the images have been automatically cropped to remove extra white space. This isn’t what we want (you’ll see why later), so drag a box around both of the images to select them and click Modify\Untrim Selected Images.

Now let’s get the images nice and straightened. Click Arrange\Complex by Height (no spacing) and they will line up nicely for you.

Finally, let’s get the canvas size down to a reasonable size. Click Modify\Canvas Width and set the width to 128px. Do the same with Modify\Canvas Height and set the height to 64px. Your screen should now look something like this:

Zwoptex Screenshot with Finished Spritesheet

Finally, time to export our sprite sheet and coordinates! Click on File\Export Texture and save the sprite sheet as “sprites.jpg”. Then click on File\Export Coordinates and save the coordinates as “sprites.plist”. Note that it is important that both the sprite sheet and coordinates have the same filename (before the extension), as the sprite sheet code assumes that they do.

Just for fun, open up sprites.plist. You can see that what Zwoptex did is automatically fill up a property list with the original names of each sprite, and the coordinates for each sprite. We can provide this to Cocos2D instead of typing in the coordinates manually!

Coordinates Property List Screenshot

Adding Our Sprites From the Sprite Sheet

Ok time to write some code!

Create a new project in XCode, choose the cocos2d-0.99.1 Box2d Application template, and name the project Box2DCollision. Then clear out the sample code to get an empty starting point like the way we did in the bouncing balls tutorial.

Also, make sure you add the following to the top of your HelloWorldScene.mm:

#define PTM_RATIO 32.0

If you’re confused what that means or why you need it, check out the bouncing balls tutorial for more information.

Next, let’s add the sprite sheet and coordinates property list into our project. Drag sprites.jpg and sprites.plist into the Resources folder of your project, verifying that “Copy items into destination group’s folder (if needed)” is checked.

Then, add the following member variable to the HelloWorld class in HelloWorldScene.h:

 CCSpriteSheet *_spriteSheet;

Now let’s modify the init method in HelloWorldScene.mm to load up our sprite sheet and property list. Modify your init method to look like the following:

- (id)init {
 
    if ((self=[super init])) {
        
        // Create our sprite sheet and frame cache
        _spriteSheet = [[CCSpriteSheet spriteSheetWithFile:@"sprites.jpg" 
            capacity:2] retain];
        [[CCSpriteFrameCache sharedSpriteFrameCache] 
            addSpriteFramesWithFile:@"sprites.plist"];
        [self addChild:_spriteSheet];
        
        [self spawnCar];
        [self schedule:@selector(secondUpdate:) interval:1.0];
        
    }
    return self;
    
}

The first thing we do is to create a sprite sheet, which is an object that efficiently draws all of its CCSprite children. For this to work, they obviously must all share the same texture. When we add our car and cat image to the scene, we will add them as children of the CCSpriteSheet. Special thanks to Victor from the comments section for pointing this out!

Then we use CCSpriteFrameCache to load up our sprite sheet and give it the property list. This function actually looks for a image with the same name, which is why it was important to name the sprite sheet “sprites.jpg” since the property list was named “sprites.plist.”

After that we call a function to spawn a car into the scene, and a periodic 1 second update function, which we are about to write.

We’ll start with spawning the car. Let’s have him move in a triangle pattern across the middle of the screen, repeating forever. Add the following function to HelloWorldScene.mm above the init method:

- (void)spawnCar {
 
    CCSprite *car = [CCSprite spriteWithSpriteFrameName:@"car.jpg"];
    car.position = ccp(100, 100);
    car.tag = 2;
    
    [car runAction:[CCRepeatForever actionWithAction:
                    [CCSequence actions:
                     [CCMoveTo actionWithDuration:1.0 position:ccp(300,100)],
                     [CCMoveTo actionWithDuration:1.0 position:ccp(200,200)],
                     [CCMoveTo actionWithDuration:1.0 position:ccp(100,100)],
                     nil]]];
    
    [_spriteSheet addChild:car];
    
}

Note that to create our Sprite, we use the method spriteWithSpriteFrameName rather than spriteWithFile. This tells it to use the part of the sprite sheet texture representing the Car image.

Also note that instead of adding the car as a child of the HelloWorld layer, we add it as a child of the sprite sheet for more efficient drawing.

The rest of this function should be familiar to you at this point. So let’s spawn some cats! Add the following methods above the spawnCar method:

- (void)spawnCat {
    
    CGSize winSize = [CCDirector sharedDirector].winSize;
    
    CCSprite *cat = [CCSprite spriteWithSpriteFrameName:@"cat.jpg"];
    
    int minY = cat.contentSize.height/2;
    int maxY = winSize.height - (cat.contentSize.height/2);
    int rangeY = maxY - minY;
    int actualY = arc4random() % rangeY;
    
    int startX = winSize.width + (cat.contentSize.width/2);
    int endX = -(cat.contentSize.width/2);
    
    CGPoint startPos = ccp(startX, actualY);
    CGPoint endPos = ccp(endX, actualY);
    
    cat.position = startPos;
    cat.tag = 1;
    
    [cat runAction:[CCSequence actions:
                    [CCMoveTo actionWithDuration:1.0 position:endPos],
                    [CCCallFuncN actionWithTarget:self 
                        selector:@selector(spriteDone:)],
                    nil]];
    
    [_spriteSheet addChild:cat];
    
}

- (void)spriteDone:(id)sender {
    
    CCSprite *sprite = (CCSprite *)sender;
    [_spriteSheet removeChild:sprite cleanup:YES];
    
}

- (void)secondUpdate:(ccTime)dt {
    
    [self spawnCat];
    
}

Again you should be familiar with all of the above code by now. Compile and run the code, and if all goes well you should see a car moving around the screen, with cats moving right to left. But the cats are getting away scott free! We’ll have to do something about that.

Screenshot of our project so far

Contributors

Over 300 content creators. Join our team.