Intro to Box2D with Cocos2D 2.X Tutorial: Bouncing Balls

Update 1/9/2013: Fully updated for Cocos2D 2.1-beta4 (original post by Ray Wenderlich, update by Brian Broom). This tutorial helps get you started with Box2D with Cocos2D by showing you how to create a simple app that shows a ball that you can bounce around the screen by rotating your iPhone with the accelerometer. This tutorial […] By Brian Broom.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 2 of this article. Click here to view the first page.

Falling on the Floor

To represent the floor, we create an invisible edge at the bottom of the screen of our iPhone. We do this by completing the following steps.

  • We first create a body definition and specify that the body should be positioned in the lower left corner. Since we don’t change the body type, this will default to a static object, which is what we want.
  • We then use the world object to create the body object.
  • We then create an edge shape for the bottom edge of the screen. This “shape” is actually just a line. Note that we have to convert the pixels into “meters” by using our conversion ratio as we discussed above.
  • We create a fixture definition, specifying the edge shape.
  • We then use the body object to create a fixture object for the shape.
  • Also note that one body object can contain multiple fixture objects!

Add the following code to the init method, after creating the world and before the ball definition.

	// Create edges around the entire screen
	b2BodyDef groundBodyDef;
	groundBodyDef.position.Set(0,0);

	b2Body *groundBody = _world->CreateBody(&groundBodyDef);
	b2EdgeShape groundEdge;
	b2FixtureDef boxShapeDef;
	boxShapeDef.shape = &groundEdge;

	//wall definitions
	groundEdge.Set(b2Vec2(0,0), b2Vec2(winSize.width/PTM_RATIO, 0));
	groundBody->CreateFixture(&boxShapeDef);

Now when we compile and run, the ball will bounce up in the air several times before coming to rest.

Bouncing Ball Screenshot

What About Horizontal Motion?

Now that we have the basics down, lets make something more interesting – an invisible foot that kicks the ball every few seconds. Define a new method in HelloWorldLayer.h:

- (void)kick;

and add the method in HelloWorldLayer.mm:

- (void)kick {
    b2Vec2 force = b2Vec2(30, 30);
    _body->ApplyLinearImpulse(force,_body->GetPosition());
}

ApplyLinearImpulse puts a force on the ball, making it move. How fast the ball moves is based on its mass (from the density property we set earlier). Try different values for density, and for the force to find values you like. The coordinate system is the same as Cocos2d, with positive x and y being up and to the right.

Add this line to the init method to run the kick method every 5 seconds.

    [self schedule:@selector(kick) interval:5.0];

If you build and run the project now, the ball will fly offscreen after it is kicked. Let’s go ahead and define the other walls. Find the wall definitions section of the init method, and add the following lines. Note: Each wall needs two lines of code, one to Set (define) the coordinates, and one to add the edge as a fixture of the ground object.

    groundEdge.Set(b2Vec2(0,0), b2Vec2(0,winSize.height/PTM_RATIO));
    groundBody->CreateFixture(&boxShapeDef);
        
    groundEdge.Set(b2Vec2(0, winSize.height/PTM_RATIO),
                   b2Vec2(winSize.width/PTM_RATIO, winSize.height/PTM_RATIO));
    groundBody->CreateFixture(&boxShapeDef);
        
    groundEdge.Set(b2Vec2(winSize.width/PTM_RATIO, winSize.height/PTM_RATIO),
                   b2Vec2(winSize.width/PTM_RATIO, 0));
    groundBody->CreateFixture(&boxShapeDef);

Now you can build and run the project and watch the ball bounce around your screen.

Integrating Touch

Since our HelloWorldLayer is still a cocos2d layer, we can use all the tools we have learned for touch events. To show how they interact with Box2d, lets change our app so that when we touch the screen, it kicks the ball to the left.

To enable touch events, add this line to the init method in HelloWorldLayer.mm:

    [self setTouchEnabled:YES];

and add this method to handle the events

- (void)ccTouchesBegan:(UITouch *)touch withEvent:(UIEvent *)event {
    b2Vec2 force = b2Vec2(-30, 30);
    _body->ApplyLinearImpulse(force, _body->GetPosition());
}

Just like before, we are using the ApplyLinearImpulse method to add a force to the ball. Using a negative x value for the force will push it to the left.

A Note On The Simulation

As promised let’s talk about those density, friction, and restitution variables that we set on the ball.

  • Density is mass per unit volume. So the more dense an object is, the more mass it has, and the harder it is to move.
  • Friction is a measure of how hard it is for objects to slide against each other. This should be in the range of 0 to 1. 0 means there is no friction, and 1 means there is a lot of friction.
  • Restitution is a measure of how “bouncy” an object is. This should usually be in the range of 0 to 1. 0 means the object will not bounce, and 1 means the bounce is perfectly elastic, meaning it will bounce away with the same velocity that it impacted an object.

Feel free to play around with these values and see what difference it makes. Try to see if you can make your ball more bouncy!

Finishing Touches

It would be cool if we could get the ball to bounce around the screen as we tilt our device around. For one thing that will help us test that we’ve got all the boundaries working! This is quite easy to do. Add the following to your init method:

[self setAccelerometerEnabled:YES];

Then add the following method somewhere in the file:

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
 
    // Landscape left values
    b2Vec2 gravity(acceleration.y * 30, -acceleration.x * 30);
    _world->SetGravity(gravity);    
}

Finally, click on the project target at the top of the Project Navigator sidebar. Make sure your target (Box2D) is selected, and on the Summary tab. In the Supported Interface Orientations section, click on the ‘Landscape Right’ button to deselect it. The Landscape Left button should be the only one selected (dark grey). We don’t want iOS to change the orientation of the app when the phone is rotated.

Supported Interface Orientations setting for the accelerometer section.

Landscape Left only

All we’re doing here is setting the gravity vector in the simulation to be a multiple of the acceleration vector. Give it a compile and run (on your device), and you should be able to bounce your ball all around the screen!

Note: Accelerometer data is only available running on a physical device, which requires a paid Apple developer account and a developer certificate installed. See the iOS Provisioning Portal at developer.apple.com.

Where To Go From Here?

Here’s a project with the all of the above code.

If you want to learn more about Box2D, check out the tutorial series on How To Create A Breakout Game with Box2D and Cocos2D!

Brian Broom

Contributors

Brian Broom

Author

Over 300 content creators. Join our team.