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.)

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:

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:

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:

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:

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!

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!

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:

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:

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

Moving The Paddle

So let’s get moving! Moving the paddle is going to require touches, so enable touches in your init method:

self.touchEnabled =YES;

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

b2MouseJoint *_mouseJoint;

Now let’s implement the touch methods! Let’s start with ccTouchesBegan:

First, we convert the touch location to our Cocos2D coordinates (convertToGL) and then to our Box2D coordinates (locationWorld).

Then we use a method on our paddle fixture object that we’ve stored away to see if the touch point is within the fixture.

If it is, we create something called a “mouse joint.” In Box2D, a mouse joint is used to make a body move toward a specified point – in this case where the user is tapping.

When you set up a mouse joint, you have to give it two bodies. The first isn’t actually used, but the convention is to use the ground body. The second is the body you want to move – in our case the paddle.

Then you specify where you want the target to move – in our case where the user is tapping.

Then you tell Box2D that when bodyA and bodyB collide, treat it as a collision, rather than ignoring it. This is very important. When I was trying to get this working, I didn’t have this set, so when I was moving the paddle with my mouse it wouldn’t collide with the edges of the screen, and my paddle would fly off screen sometimes! This was very confusing and frustrating until I discovered this simple way to fix it :]

You then specify the max force with which to move the body. If you reduce this amount, the body will react more slowly to your mouse movements (which may be what you want sometimes!). But here we want the paddle to respond rather quickly to movements.

Finally we add the joint to the world, and store away the pointer for future reference. We also set the body to awake. We need to do this because if the body is asleep and we don’t awaken it, it won’t respond to the movements!

The beginning of this method is the same as ccTouchesBegan – we get the location of the touch in Box2D coordinates. The only thing we do here is update the target of the mouse joint (i.e. where we want the body to move) to be the current location of the touch.

The first thing we do is specify the axis to be a vector along the x axis, but not at all along the y axis. We then specify the ever important collideConnected value so our paddle will correctly bounce against the edge of the screen rather than flying into never-never land.

We then initialize the joint specifying the paddle and the ground body and create the joint!

Give it a compile and run and now you should only be able to move the paddle back and forth instead of anywhere you want:

Finishing Touches

Now, as you’ve been playing around with this so far you may have noticed that sometimes the ball can get super-fast or super slow, depending on how you hit it with the paddle.

Update: The first time I tried to fix this, I tried to adjust the velocity of the ball directly by calling SetLinearVelocity. However, as Steve Oldmeadow also pointed out (thanks Steve!), this is a bad idea as it messes up the collision simulations, and it’s better to indirectly affect the velocity by increasing the linear damping. So that’s what we’ll do!

Add the following code to the tick method, after getting the user data:

Gimme The Code!

What’s Next?

So far, we have a ball that bounces around the screen and a paddle we can move around via touch. In the next tutorial in the series, we pick it up from here and add some bricks that get destroyed when the ball collides into them, and some win/lose logic!

Brian has been tinkering with computers since writing basic programs on IBM PC (with Two! floppy drives). He has done web, database, C++, ruby, and now iOS development. Brian has spent the last few years as a computer science teacher and trainer.

To join the discussion, enable your javascript or head over to the forum over here

User Comments

7 Comments

Dear Sir,
Thanks for your nice tutorials,
I am working on this breakout with ARC enabled i faced a few problems I solved some but when it gets to touches began
The project runs fine but as soon I click it gives error and takes me direct to GetMass
It highlights the (return m_mass) in b2Body header file

I'll admit this is not something I looked into when updating the tutorials. I know that there are some issues with ARC and Cocos2d, and there is a tutorial on getting Cocos to work with ARC here http://www.raywenderlich.com/23854/arc-and-cocos2d-v2-x. You might want to start there if you haven't already.

here i am going to paste all the code which is in Hello world layer some i do have if you please have a quick look at this. i wanted to upload the project but the max size for the file which is allowed is 256KB so i was not able to upload the project.

but if you want to have a quick look to the project i can email it to you but i don't have your email address here is my email
( afridikhalid@yahoo.com )

As for me, I'm using Cocos2dx v3.0 and everything is working fine (The translating code into C++ is quite easy too, thanks to the Cocos2dx dev team ^^).

But now I'm facing a problem. My project is compiled and run fine on phone, but when testing on Windows 7 it always crash the very first time I click (which I believe a "touch").

Debugger showed me that the whole b2mouseJoint seem not be initialized at all, and the paddleFixture->TestPoint always false is the cause of that... but I really don't get it: even if it is false, the program should run fine , just nothing happen to the paddle, right?

Thank you all if you've ever read my post. I've just solved it by a little trying.

For some reasons (that I'm very eager to hear the explains from you pros) when run on Windows PC my mouseJoint was created but all empty by itself. When touched, the HelloWorld layer called its callback OnTouchesBegan and immediatly return (due to the checking result), so the mouseJoint remained empty (that means no m_bodyB of its has existed yet).