post

Cocos2d Example – Bouncing Ball

In this example, we will use Cocos2d and ChipMunk physics engine to implement a bouncing ball. A ball falls towards the ground because of the force of gravity. The basic idea of ChipMunk is that you define some physical objects (including bodies and shapes, but they are invisible) in the space, then ChipMunk will simulate what happens to these objects. You should setup a callback function to update these objects’ visual representation (e.g., a sprite created with image).

Step 1Create a Cocos2d Application and name it with “BouncingBall”. We assume you have installed Cocos2d project template properly.
1

Step 2Add this image to Resources Group.

Step 3Define the class BallLayer, which is a subclass of Layer. The codes are shown below:
// BallLayer.h

#import “cocos2d.h”
#import “Layer.h”
#import “chipmunk.h”

@interface BallLayer : Layer {
Sprite* ballSprite;
cpSpace* space;
}
@end
// BallLayer.m

#import “BallLayer.h”

void updateShape(void* ptr, void* unused){

cpShape* shape = (cpShape*)ptr;

Sprite* sprite = shape->data;

if(sprite){

cpBody* body = shape->body;

[sprite setPosition:cpv(body->p.x, body->p.y)];

}

}

@implementation BallLayer

-(void)tick:(ccTime)dt{

cpSpaceStep(space, 1.0f/60.0f);

cpSpaceHashEach(space->activeShapes, &updateShape, nil);

}

-(void)setupChipmunk{

cpInitChipmunk();

space = cpSpaceNew();

space->gravity = cpv(0,-2000);

space->elasticIterations = 1;

[self schedule: @selector(tick:) interval: 1.0f/60.0f];

cpBody* ballBody = cpBodyNew(200.0, INFINITY);

ballBody->p = cpv(150, 400);

cpSpaceAddBody(space, ballBody);

cpShape* ballShape = cpCircleShapeNew(ballBody, 20.0, cpvzero);

ballShape->e = 0.8;

ballShape->u = 0.8;

ballShape->data = ballSprite;

ballShape->collision_type = 1;

cpSpaceAddShape(space, ballShape);

cpBody* floorBody = cpBodyNew(INFINITY, INFINITY);

floorBody->p = cpv(0, 0);

cpShape* floorShape = cpSegmentShapeNew(floorBody, cpv(0,0), cpv(320,0), 0);

floorShape->e = 0.5;

floorShape->u = 0.1;

floorShape->collision_type = 0;

cpSpaceAddStaticShape(space, floorShape);

}

-(id)init{

self = [super init];

if(nil != self){

ballSprite = [Sprite spriteWithFile:@"ball.png"];

[ballSprite setPosition:CGPointMake(150, 400)];

[self add:ballSprite];

[self setupChipmunk];

}

return self;

}

@end

In class BallLayer, we defined a pointer ballSprite to point to a ball sprite that is initialized in init method. We also defined a cpSpace pointer space which points to a ChipMunk space. In init method, we invokedsetupChipmunk function to setup ChipMunk stuff.

In setupChipmunk method, we first created a Chipmunk space and assigned some paremeters. (Note: The parameter elasticIterations should be greater than 1 if you want the ball bounces off the ground). We usesschedule:interval: method to schedule a selector tick: with an interval time. tick: function will callcpSpaceStep to update the space. In addition, cpSpaceHashEach function will call updateShape on each active shape. You will have chance to update the sprite’s (i.e., the ball’s) position in updateShape function (updateShape function is the callback function we metioned at the begining of this tutorial).

Next, the ball’s body and shape are created. We add ball’s shape to the ChipMunk space.  In this case, we used segment to describe the shape of the ground and set the thickness of segment to be 0. Because the ground doesn’t move, the function cpSpaceAddStaticShape is used to add the shape of ground to the space. (Note: You can adjust the elasticity value (i.e., parameter e) of ball and ground to determine how high the ball can bounce).

Step 4: The project template has created MyScene class by default. We need to make the following modifications:

// MyScene.h

#import

#import “Scene.h”

#import “BallLayer.h”

@interface MyScene : Scene {

BallLayer* ballLayer;

}

@property (nonatomic, retain) BallLayer* ballLayer;

@end

// MyScene.m

#import “MyScene.h”

@implementation MyScene

@synthesize ballLayer;

-(void)dealloc{

[ballLayer release];

[super dealloc];

}

-(id)init{

self = [super init];

if(nil != self){

BallLayer* layer = [[BallLayer alloc]init];

self.ballLayer = layer;

[layer release];

[self add:ballLayer];

}

return self;

}

@end

Step 5: In BouncingBallAppDelegate.m file, applicationDidFinishLaunching method, change the following code:

[director setLandscape:YES];

to

[director setLandscape:NO]; 

Build&Go. You will see the following result:

Update: You can download the sourcecodes from here. In addition, in the codes above, -> was not displayed properly, now fixed.

Posted on 10th May 2009 in iPhone Development  •  No comments yet

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>