How To Create A Breakout Game with Box2D and Cocos2D 2.X Tutorial: Part 1

Update 1/9/2013: Fully updated for Cocos2D 2.1-beta4 (original post by Ray Wenderlich, update by Brian Broom). Box2D is a powerful physics library that comes with the Cocos2D game programming library for the iPhone. There’s a lot you can do with it, and a great way to start learning about how it works is to create […] By Brian Broom.

Leave a rating/review
Save for later
Share

Simple Breakout Game Screenshot

Simple Breakout Game Screenshot

Simple Breakout Game Screenshot

Update 1/9/2013: Fully updated for Cocos2D 2.1-beta4 (original post by Ray Wenderlich, update by Brian Broom).

Box2D is a powerful physics library that comes with the Cocos2D game programming library for the iPhone. There’s a lot you can do with it, and a great way to start learning about how it works is to create a simple game with it!

In this tutorial, we are going to create a simple Breakout game step by step, complete with collision detection, a ball bouncing with physics effects, dragging the paddle via touches, and win/lose screens. (Jump to part two of the series.)

If you are new to Cocos2D or Box2D, it may help to go through the intro to Cocos2D tutorial and/or intro to Box2D tutorial before proceeding with this tutorial.

Allright, time for some Breakout!

An Ever-Bouncing Ball

Start by creating a new project with the cocos2d v2.x cocos2d iOS with Box2d template, and name your project “Box2DBreakout”. Clear out the template code and so you have an empty project to start with – see the intro to Box2D tutorial for instructions on how to do that.

Once you have a nice clean project, add the following import to the top of HelloWorldLayer.h:

#import "Box2D.h"

And add the following member variables to the HelloWorldLayer class:

b2World *_world;
b2Body *_groundBody;
b2Fixture *_bottomFixture;
b2Fixture *_ballFixture;

Just as in the previous tutorial, Box2D uses an internal unit of “meters” instead of pixels. We will use the same ratio to convert from pixels to “meters” that we discussed then, and this should already be defined in HelloWorldLayer.h.

Then add the following code to your init method of HelloWorldLayer.mm:

CGSize winSize = [CCDirector sharedDirector].winSize;

// Create a world
b2Vec2 gravity = b2Vec2(0.0f, 0.0f);
_world = new b2World(gravity);

// Create edges around the entire screen
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0,0);
_groundBody = _world->CreateBody(&groundBodyDef);

b2EdgeShape groundBox;
b2FixtureDef groundBoxDef;
groundBoxDef.shape = &groundBox;

groundBox.Set(b2Vec2(0,0), b2Vec2(winSize.width/PTM_RATIO, 0));
_bottomFixture = _groundBody->CreateFixture(&groundBoxDef);

groundBox.Set(b2Vec2(0,0), b2Vec2(0, winSize.height/PTM_RATIO));
_groundBody->CreateFixture(&groundBoxDef);

groundBox.Set(b2Vec2(0, winSize.height/PTM_RATIO), b2Vec2(winSize.width/PTM_RATIO, 
    winSize.height/PTM_RATIO));
_groundBody->CreateFixture(&groundBoxDef);

groundBox.Set(b2Vec2(winSize.width/PTM_RATIO, winSize.height/PTM_RATIO), 
    b2Vec2(winSize.width/PTM_RATIO, 0));
_groundBody->CreateFixture(&groundBoxDef);

Again, this is the same code that we had in our previous Box2D tutorial to create a bounding box around the screen. However, this time we set the gravity to zero, because in our breakout game there will not be any gravity! Also note we store a pointer to the bottom fixture for future reference (we’ll need it to keep track of when the ball hits the bottom of the screen).

Now download a copy of the image of a bouncy ball, and a retina version I created and drag it into the Resources folder of your project, making sure “Copy items into destination group’s folder (if needed)” is checked.

Let’s add a sprite for the ball into the layer. Add the following right after the last bit of code you added:

// Create sprite and add it to the layer
CCSprite *ball = [CCSprite spriteWithFile:@"ball.png"];
ball.position = ccp(100, 100);
ball.tag = 1;
[self addChild:ball];

There should be no surprises here, we’ve been doing this for a while now. Note that we set a tag on the ball for identification purposes (you’ll see why later in the tutorial).

Next let’s create a body for the shape:

// Create ball body 
b2BodyDef ballBodyDef;
ballBodyDef.type = b2_dynamicBody;
ballBodyDef.position.Set(100/PTM_RATIO, 100/PTM_RATIO);
ballBodyDef.userData = ball;
b2Body * ballBody = _world->CreateBody(&ballBodyDef);

// Create circle shape
b2CircleShape circle;
circle.m_radius = 26.0/PTM_RATIO;

// Create shape definition and add to body
b2FixtureDef ballShapeDef;
ballShapeDef.shape = &circle;
ballShapeDef.density = 1.0f;
ballShapeDef.friction = 0.f;
ballShapeDef.restitution = 1.0f;
_ballFixture = ballBody->CreateFixture(&ballShapeDef);

This should look familiar as well from our last tutorial. As a refresher, to create a body we need to create a body definition, then a body object, then a shape, then a fixture definition, and finally a fixture object.

Note that we set the parameters a bit differently this time: we’ve set the restitution to 1.0, meaning the when the ball collides with an object the collision will be perfectly elastic. In plain English, this means that the ball will bounce back with equal force to the impact.

Also note that we store the ball fixture for future reference (same reason as why we stored the bottom fixture).

Update: Also note that the ball is set to have no friction. Thanks to Steve Oldmeadow for pointing out that this is important in this case so that the ball bounces nicely off the walls, preventing the ball from frequently getting stuck bouncing back and forth in a straight up-down or left-right angle.

Ok, now to get the ball rolling (bouncing, actually). Add the following after the above:

b2Vec2 force = b2Vec2(10, 10);
ballBody->ApplyLinearImpulse(force, ballBodyDef.position);

This applies an impulse (you can think of it like a propulsion from a jet pack thruster) to the ball to get it to start moving in a particular direction (in this case, diagonally up to the right). We need this to get the ball moving in the first place!

One last thing for the init method: add the tick scheduling:

[self schedule:@selector(tick:)];

And then the tick method itself!

- (void)tick:(ccTime) dt {
    _world->Step(dt, 10, 10);    
    for(b2Body *b = _world->GetBodyList(); b; b=b->GetNext()) {    
        if (b->GetUserData() != NULL) {
            CCSprite *sprite = (CCSprite *)b->GetUserData();                        
            sprite.position = ccp(b->GetPosition().x * PTM_RATIO,
                                    b->GetPosition().y * PTM_RATIO);
            sprite.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
        }        
    }
    
}

Again no surprises with these two since we did the same thing in the last tutorial.

One last thing and then we’re ready to try it out: the cleanup method!

- (void)dealloc {
    
    delete _world;
    _groundBody = NULL;
    [super dealloc];
    
}

Ok, let’s try it out! When you compile and run the project, you should see a ball continuously bouncing around the screen – cool!

Ball Bouncing Screenshot

Adding the Paddle

It wouldn’t be a breakout game if we didn’t have a paddle. Download a copy of a graphic of a paddle, and the corresponding retina version I made and drag it to the Resources folder of your project, making sure “Copy items into destination group’s folder (if needed)” is checked.

Then add the following member variable to HelloWorld in HelloWorldLayer.h:

b2Body *_paddleBody;
b2Fixture *_paddleFixture;

And then construct the paddle body in your init method:

// Create paddle and add it to the layer
CCSprite *paddle = [CCSprite spriteWithFile:@"paddle.png"];
paddle.position = ccp(winSize.width/2, 50);
[self addChild:paddle];

// Create paddle body
b2BodyDef paddleBodyDef;
paddleBodyDef.type = b2_dynamicBody;
paddleBodyDef.position.Set(winSize.width/2/PTM_RATIO, 50/PTM_RATIO);
paddleBodyDef.userData = paddle;
_paddleBody = _world->CreateBody(&paddleBodyDef);

// Create paddle shape
b2PolygonShape paddleShape;
paddleShape.SetAsBox(paddle.contentSize.width/PTM_RATIO/2, 
                     paddle.contentSize.height/PTM_RATIO/2);

// Create shape definition and add to body
b2FixtureDef paddleShapeDef;
paddleShapeDef.shape = &paddleShape;
paddleShapeDef.density = 10.0f;
paddleShapeDef.friction = 0.4f;
paddleShapeDef.restitution = 0.1f;
_paddleFixture = _paddleBody->CreateFixture(&paddleShapeDef);

I’m not going to explain this much because you should be a pro at creating bodies by this point. However, note a few differences this time:

  • When you create a CCSprite, you don’t need to specify the size of the sprite if you don’t want to. If you give it the filename, it can automatically determine the size.
  • Note that instead of using a circle shape, we use a polygon shape this time. We use a helper method to create the shape in the form of a box. Note: the height and width of the box are measured from the center point, so we use half of the actual values.
  • Note that there is an alternate SetAsBox method that allows you to specify the position of the shape relative to the body, which comes in handy when constructing complex shapes. However we don’t need to use that here, since we just want the shape centered on the body.
  • We make the paddle more dense than the ball, and tweak the other parameters as well.
  • We are storing paddleBody and paddleFixture for future reference.

If you compile and run this you’ll see our paddle in the scene, and the ball will bounce off it:

Paddle Added Screenshot

However this isn’t much fun, because we can’t move paddle yet!

Brian Broom

Contributors

Brian Broom

Author

Over 300 content creators. Join our team.