Mar 172011
 

I received a few requests for a simple Mario-like platformer tutorial. So I am keeping my promise. The sample is far from a full fledged Mario clone, but I hope it it can at least start you off in the right direction. This tutorial builds upon concepts covered in “Beginning Box2d Physics Engine” and “Side Scrolling the Background in Box2d and Cocos2d”, so I suggest reading them first.

What’s Covered?

I will be covering the following topics in this tutorial.

  • Simple object oriented game design
  • User input / touch detection
  • Applying forces to game objects to make it move and jump
  • Collision detection

Simple Object Oriented Game Design

The example app will be a very rudimentary platformer, with some platforms and the player represented by a circle. Again, I am creating the physics world by reading in the tile map designed in the program Tiled as described in my previous tutorial. The newest version of Tiled at the time of this writing is 0.6.0, and you must go into preferences and set gzip as the default compression or Cocos2d will fail to load the tile map file. The player will be able to move to the right (moving to the left is left to the reader as an exercise) and jump. The app has only two objects. The first is the player object and the other is the platform object. Both the player and the platform object will inherit from the general GameObject class. The general GameObject class inherits from Cocos2d’s CCSprite object and has a property called “type” which is used to distinguish between a player and a platform. Having our objects inherit from the same parent object (GameObject) will make it easier to identify objects when we handle collision detection.

Here is the code for the GameObject class. Notice that it inherits from CCSprite and that we initialize the default type to kGameObjectNone (there is an enum defined in Constants.h, which is not shown here but will be included in the sample source).

// GameObject.h
#import "cocos2d.h"
#import "Constants.h"
 
@interface GameObject : CCSprite {
    GameObjectType  type;
}
 
@property (nonatomic, readwrite) GameObjectType type;
@end
 
////////////////////////////////////////////////////////
 
// GameObject.m
@implementation GameObject
@synthesize type;
 
- (id)init
{
    self = [super init];
    if (self) {
        type = kGameObjectNone;
    }
 
    return self;
}
 
- (void)dealloc
{
    [super dealloc];
}
@end

The next one shown is the Player class. Note that the extension for the Player class is Player.mm (two m’s). Do you see the Box2d’s b2Body object that is declared? Box2d is written in C++ not Objective-C, so this is the reason we must make the Player class support both Objective-C and C++ by naming the extension with two m’s. With only one, you will see a lot of errors during compilation. You can see that the type is set to kGameObjectPlayer. You will see the “type” come into play when we discuss collision detection later.

The Player class will be in charge of creating the Box2d physics object and adding itself into the physics world when the createBox2dObject method is called. We set the custom user data (playerBodyDef.userData) to “self” so that we can access the Cocos2d object from the Box2d’s contact listener. It also has methods to make the Player move to the right and jump, which will also be discussed later in the tutorial.

// Player.h
#import "cocos2d.h"
#import "Box2D.h"
#import "GameObject.h"
 
@interface Player : GameObject {
    b2Body          *body;
}
 
-(void) createBox2dObject:(b2World*)world;
-(void) jump;
-(void) moveRight;
 
@property (nonatomic, readwrite) b2Body *body;
@end
 
///////////////////////////////////////////////////////
 
// Player.mm
#import "Player.h"
#import "Constants.h"
 
@implementation Player
@synthesize body;
 
- (id) init {
	if ((self = [super init])) {
		type = kGameObjectPlayer;
	}
	return self;
}
 
-(void) createBox2dObject:(b2World*)world {
    b2BodyDef playerBodyDef;
	playerBodyDef.type = b2_dynamicBody;
	playerBodyDef.position.Set(self.position.x/PTM_RATIO, self.position.y/PTM_RATIO);
	playerBodyDef.userData = self;
	playerBodyDef.fixedRotation = true;
 
	body = world->CreateBody(&playerBodyDef);
 
	b2CircleShape circleShape;
	circleShape.m_radius = 0.7;
	b2FixtureDef fixtureDef;
	fixtureDef.shape = &circleShape;
	fixtureDef.density = 1.0f;
	fixtureDef.friction = 1.0f;
	fixtureDef.restitution =  0.0f;
	body->CreateFixture(&fixtureDef);
}
 
-(void) moveRight {
    b2Vec2 impulse = b2Vec2(7.0f, 0.0f);
    body->ApplyLinearImpulse(impulse, body->GetWorldCenter());		
}
 
-(void) jump {
    b2Vec2 impulse = b2Vec2(4.0f, 15.0f);
    body->ApplyLinearImpulse(impulse, body->GetWorldCenter());		    
}
@end

As for the platform object, there isn’t a specific Platform object. For convenience, we simply allocate a GameObject object and specifically set the type to kGameObjectPlatform (see makeBox2dObjectAt method in GameScene way below).

User Input / Touch Detection

The following two lines inside GameScene’s init method are responsible for enabling the touch input. The swallowsTouches argument on line 3 says that whatever touches that GameScene receives is “swallowed” or ends in GameScene and is not further propagated.

1
2
3
// Inside GameScene's init method
self.isTouchEnabled = YES;
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];

The method below is called when the mouse is clicked in the simulator or the screen is touched on the device. We get the location of the touch, and if the touch is on the left half of the screen, we move the player to the right. If the touch is on the right half of the screen, we make the player jump. We are not using it in this tutorial, but if you need it, then there is also a complimentary method to detect when the touch has ended. Note that this code is for a single touch, not multi-touches.

// GameScene.mm
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {    
    CGPoint location = [touch locationInView:[touch view]];
    location = [[CCDirector sharedDirector] convertToGL:location];
    if (location.x <= screenSize.width / 2) {
        [player moveRight];        
    } else {
        [player jump];
    }
    return TRUE;
}
 
-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
    CCLOG(@"Touch ended");
}

Applying Forces to Game Objects to Make it Move and Jump

To make the player move and jump, we apply a force to the player object. Recall that the Player class has the createBox2dObject method which should be called to add a physics object representing the player into the physics world. To move the player to the right, we simply tell Box2d to apply a positive ‘x’ force to the physics object that represents the player. And to make it jump, we apply a positive ‘x’ force along with a positive ‘y’ force to the physics object. In this case, we are applying an impulse force (it’s a sudden burst of force) but you are not limited to it (please see the Box2d manual for information on other kind of forces). All the rest is handled by the Box2d physics engine. Once the force has been applied, we update the player’s position in the main game loop with the new position provided to us by the physics engine (see the complete GameScene source further down, inside the update method).

-(void) moveRight {
    b2Vec2 impulse = b2Vec2(7.0f, 0.0f);
    body->ApplyLinearImpulse(impulse, body->GetWorldCenter());		
}
 
-(void) jump {
    b2Vec2 impulse = b2Vec2(4.0f, 15.0f);
    body->ApplyLinearImpulse(impulse, body->GetWorldCenter());		    
}

Collision Detection

For our simple example, only two objects exist in the world (player and platform). In order to detect when the player has made contact with the platform and when the player has lost contact with the platform, we must set up a contact listener and tell Box2d to use said contact listener. The contact listener is a C++ class which inherits from Box2d’s b2ContactListener class.

The two functions that we are most interested in are BeginContact and EndContact. As the function name suggests, BeginContact is called whenever two objects in the world make contact with each other. And EndContact is called as soon as the contact is broken. You see that a b2Contact object is passed to the functions, which can be used to get the user data. The b2Contact object has two function calls GetFixtureA() and GetFixtureB() which can be used to return the two Box2d bodies involved in the collision, and subsequently the user data (our GameObject objects) stored in them. Recall that all the objects in our app is inherited from the GameObject class, so we can safely cast the user data for both to GameObjects. Once we have the two GameObjects, we can check the “type” property of each of the objects to check whether it is the player or the platform. It is important to remember that no guarantee is made as to which object of the two objects is the player object or the platform object. It is up to us to determine their types, so both objects must be checked to see if it is one or the other.

To help keep the code cleaner and easier to read, there are two macros called IS_PLAYER(x,y) and IS_PLATFORM(x,y) which test whether either one of the the objects is a player or a platform. For this simple example, a simple message is printed to the console when the contact is made or lost. In a real game, you could, for example, play a sound effect when two objects collide. Also, please remember that although it is tempting to implement game logic that alters the physics world inside a contact callback, this is not allowed. The Box2d manual states that…

…for example, you may have a collision that applies damage and try to destroy the associated actor and its rigid body. However, Box2D does not allow you to alter the physics world inside a callback because you might destroy objects that Box2D is currently processing, leading to orphaned pointers (http://www.box2d.org/manual.html)

// ContactListener.h
#import "Box2D.h"
 
class ContactListener : public b2ContactListener {
public:
	ContactListener();
	~ContactListener();
 
	virtual void BeginContact(b2Contact *contact);
	virtual void EndContact(b2Contact *contact);
	virtual void PreSolve(b2Contact *contact, const b2Manifold *oldManifold);
	virtual void PostSolve(b2Contact *contact, const b2ContactImpulse *impulse);
};
 
/////////////////////////////
 
// ContactListener.mm
#import "ContactListener.h"
#import "Constants.h"
#import "GameObject.h"
 
#define IS_PLAYER(x, y)         (x.type == kGameObjectPlayer || y.type == kGameObjectPlayer)
#define IS_PLATFORM(x, y)       (x.type == kGameObjectPlatform || y.type == kGameObjectPlatform)
 
 
ContactListener::ContactListener() {
}
 
ContactListener::~ContactListener() {
}
 
void ContactListener::BeginContact(b2Contact *contact) {
	GameObject *o1 = (GameObject*)contact->GetFixtureA()->GetBody()->GetUserData();
	GameObject *o2 = (GameObject*)contact->GetFixtureB()->GetBody()->GetUserData();
 
	if (IS_PLATFORM(o1, o2) && IS_PLAYER(o1, o2)) {
        CCLOG(@"-----> Player made contact with platform!");
    }
}
 
void ContactListener::EndContact(b2Contact *contact) {
	GameObject *o1 = (GameObject*)contact->GetFixtureA()->GetBody()->GetUserData();
	GameObject *o2 = (GameObject*)contact->GetFixtureB()->GetBody()->GetUserData();
 
	if (IS_PLATFORM(o1, o2) && IS_PLAYER(o1, o2)) {
        CCLOG(@"-----> Player lost contact with platform!");
    }
}
 
void ContactListener::PreSolve(b2Contact *contact, const b2Manifold *oldManifold) {
}
 
void ContactListener::PostSolve(b2Contact *contact, const b2ContactImpulse *impulse) {
}

You then register the contact listener when you set up the physics world.

 contactListener = new ContactListener();
 world->SetContactListener(contactListener);

Wrap-up and Loose Ends

Below is the code for the GameScene class. If certain things look unfamiliar to you, please refer to the previous two tutorials that I mentioned in the beginning of the article. If you have read those tutorials, then things should be familiar except for the contact listener registration code and the touch detection code, which I have already explained earlier in the tutorial.

You can find the complete source code for download and the demo video at the end of the tutorial.

// GameScene.h
 
#import "cocos2d.h"
#import "Box2D.h"
#import "GLES-Render.h"
#import "ContactListener.h"
 
@class Player;
 
@interface GameScene : CCLayer
{
    CGSize screenSize;
	b2World* world;
	GLESDebugDraw *m_debugDraw;
	CCTMXTiledMap *tileMapNode;	
    Player *player;
    ContactListener *contactListener;
}
 
+(id) scene;
@end
 
///////////////////////////////////////////////
 
// GameScene.mm
#import "GameScene.h"
#import "Constants.h"
#import "Player.h"
#import "GameObject.h"
 
@interface GameScene(Private) 
-(void) setupPhysicsWorld;
@end
 
@implementation GameScene
 
+(id) scene
{
	// 'scene' is an autorelease object.
	CCScene *scene = [CCScene node];
 
	// 'layer' is an autorelease object.
	GameScene *layer = [GameScene node];
 
	// add layer as a child to scene
	[scene addChild: layer];
 
	// return the scene
	return scene;
}
 
- (void) makeBox2dObjAt:(CGPoint)p 
			   withSize:(CGPoint)size 
				dynamic:(BOOL)d 
			   rotation:(long)r 
			   friction:(long)f 
				density:(long)dens 
			restitution:(long)rest 
				  boxId:(int)boxId {
 
	// Define the dynamic body.
	//Set up a 1m squared box in the physics world
	b2BodyDef bodyDef;
//	bodyDef.angle = r;
 
	if(d)
		bodyDef.type = b2_dynamicBody;
 
	bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);
 
    GameObject *platform = [[GameObject alloc] init];
    [platform setType:kGameObjectPlatform];
	bodyDef.userData = platform;
 
	b2Body *body = world->CreateBody(&bodyDef);
 
	// Define another box shape for our dynamic body.
	b2PolygonShape dynamicBox;
	dynamicBox.SetAsBox(size.x/2/PTM_RATIO, size.y/2/PTM_RATIO);
 
	// Define the dynamic body fixture.
	b2FixtureDef fixtureDef;
	fixtureDef.shape = &dynamicBox;	
	fixtureDef.density = dens;
	fixtureDef.friction = f;
	fixtureDef.restitution = rest;
	body->CreateFixture(&fixtureDef);
}
 
 
 
- (void) drawCollisionTiles {
	CCTMXObjectGroup *objects = [tileMapNode objectGroupNamed:@"Collision"];
	NSMutableDictionary * objPoint;
 
	int x, y, w, h;	
	for (objPoint in [objects objects]) {
		x = [[objPoint valueForKey:@"x"] intValue];
		y = [[objPoint valueForKey:@"y"] intValue];
		w = [[objPoint valueForKey:@"width"] intValue];
		h = [[objPoint valueForKey:@"height"] intValue];	
 
		CGPoint _point=ccp(x+w/2,y+h/2);
		CGPoint _size=ccp(w,h);
 
		[self makeBox2dObjAt:_point 
					withSize:_size 
					 dynamic:false 
					rotation:0 
					friction:1.5f 
					 density:0.0f 
				 restitution:0 
					   boxId:-1];
	}
}
 
- (void) addScrollingBackgroundWithTileMap {
	tileMapNode = [CCTMXTiledMap tiledMapWithTMXFile:@"scroller.tmx"];
	tileMapNode.anchorPoint = ccp(0, 0);
	[self addChild:tileMapNode];
}
 
 
// initialize your instance here
-(id) init
{
	if( (self=[super init])) {
 
		// enable touches
		self.isTouchEnabled = YES;
 
		screenSize = [CCDirector sharedDirector].winSize;
		[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];   
 
		[self setupPhysicsWorld];
 
		[self addScrollingBackgroundWithTileMap];
		[self drawCollisionTiles];
 
		player = [Player spriteWithFile:@"Icon-Small.png"];        
		player.position = ccp(100.0f, 180.0f);
		[player createBox2dObject:world];
 
		[self addChild:player];
 
        // Start main game loop
		[self scheduleUpdate];
	}
	return self;
}
 
-(void) setupPhysicsWorld {
    b2Vec2 gravity = b2Vec2(0.0f, -9.8f);
    bool doSleep = true;
    world = new b2World(gravity, doSleep);
 
    m_debugDraw = new GLESDebugDraw(PTM_RATIO);
    world->SetDebugDraw(m_debugDraw);
    uint32 flags = 0;
    flags += b2DebugDraw::e_shapeBit;
    m_debugDraw->SetFlags(flags);
 
    contactListener = new ContactListener();
    world->SetContactListener(contactListener);
}
 
-(void) draw {
	glDisable(GL_TEXTURE_2D);
	glDisableClientState(GL_COLOR_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 
	world->DrawDebugData();
 
	// restore default GL states
	glEnable(GL_TEXTURE_2D);
	glEnableClientState(GL_COLOR_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}
 
- (void) update:(ccTime)dt {
	//It is recommended that a fixed time step is used with Box2D for stability
	//of the simulation, however, we are using a variable time step here.
	//You need to make an informed choice, the following URL is useful
	//http://gafferongames.com/game-physics/fix-your-timestep/
 
	int32 velocityIterations = 8;
	int32 positionIterations = 1;
 
	// Instruct the world to perform a single step of simulation. It is
	// generally best to keep the time step and iterations fixed.
	world->Step(dt, velocityIterations, positionIterations);
 
 
	//Iterate over the bodies in the physics world
	for (b2Body* b = world->GetBodyList(); b; b = b->GetNext()) {
		if (b->GetUserData() != NULL) {
			//Synchronize the AtlasSprites position and rotation with the corresponding body
			CCSprite *myActor = (CCSprite*)b->GetUserData();
			myActor.position = CGPointMake( b->GetPosition().x * PTM_RATIO, 
							b->GetPosition().y * PTM_RATIO);
			myActor.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
		}	
	}	
 
	b2Vec2 pos = [player body]->GetPosition();
	CGPoint newPos = ccp(-1 * pos.x * PTM_RATIO + 50, self.position.y * PTM_RATIO);	
	[self setPosition:newPos];
}
 
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {    
    CGPoint location = [touch locationInView:[touch view]];
    location = [[CCDirector sharedDirector] convertToGL:location];
    if (location.x <= screenSize.width / 2) {
        [player moveRight];        
    } else {
        [player jump];
    }
	return TRUE;
}
 
// on "dealloc" you need to release all your retained objects
- (void) dealloc {
    // in case you have something to dealloc, do it in this method
 
    delete contactListener;
    delete world;
    world = NULL;
 
    delete m_debugDraw;
 
    // don't forget to call "super dealloc"
    [super dealloc];
}
@end

Demo video of the Simple Platformer in action

Download source: SimplePlatformer.zip

Happy Saint Patrick’s Day! I wrote this tutorial while knocking back some Guinness, so I must blame alcohol if you see any glaring mistakes :)

If you enjoyed this post, make sure you subscribe to my RSS feed!

  63 Responses to “Simple Platformer Using Cocos2d and Box2d with Collision Detection”

  1. Thanks for the tut, i will be trying this out!

  2. Thanks so much, must of took quite a while but I’ll be trying this out later tonight. I’ve tried doing the gravity with just cocos2d and some tiled methods but its not working. Thanks alot!!

  3. How would i go about replacing the circle with my own image, i know it must be
    -(void) createBox2dObject:(b2World*)world {
    b2BodyDef playerBodyDef;
    playerBodyDef.type = b2_dynamicBody;
    playerBodyDef.position.Set(self.position.x/PTM_RATIO, self.position.y/PTM_RATIO);
    playerBodyDef.userData = self;
    playerBodyDef.fixedRotation = true;

    body = world->CreateBody(&playerBodyDef);

    b2CircleShape circleShape;
    circleShape.m_radius = 0.7;
    b2FixtureDef fixtureDef;
    fixtureDef.shape = &circleShape;
    fixtureDef.density = 1.0f;
    fixtureDef.friction = 1.0f;
    fixtureDef.restitution = 0.0f;
    body->CreateFixture(&fixtureDef);
    }

    but if i put fixturedef.shape = player (//this is a CCSprite) it gives me errors, cant mix ccsprite and b2shape

    • Hi Mike. If you look in the init method of GameScene, you’ll see:

      player = [Player spriteWithFile:@"Icon-Small.png"];

      Change Icon-Small.png with your own image file. That should do it!

      • but wouldnt that just make my image ( mario for example) inside the circle. I want mario to do the colliding with the tiles, thanks for the reply. This information is very hard to come by.

        • The green circle is the Box2d physics object. It’s showing right now because we enabled Box2d’s debug drawing (see setupPhysicsWorld method). When you are ready to release the game, you will disable it, and you won’t see that circle anymore. The thing that collides with the objects aren’t the Cocos2d sprites, but rather the Box2d objects. The sprites are just “skin” that goes on top of the Box2d objects to make it look pretty.

          What most people do to represent their characters in game is to make a capsule object in Box2d — that is, a circle as the base, a rectangle to represent the body, and a circle on top to represent the head. And then skin that object to make it look like Mario, for instance.

          • Ok, Thanks for clearing that up, I’m attempting to add this into my code now. Thanks again for the replies and this great tutorial.

          • Sure! Please me know when you release the game. I would be interested in checking it out :-)

  4. hey again, So erm I’ve tried adding this to my code but get some errors I’ve never seen before so I thought I’ld try copy your code in a new project and work from there.

    The thing is how do I make this circle not visible at all, and wouldn’t using a square work better for collision, sorry but I’m totally new to Box2d :P . Ive changed the player = icon XXX to what i want it to be, but this makes my sprite stand in the middle

    Thanks in advance

    • bah, Just figured out that the circle is only there for debugging lol, same goes for the green boxes, commenting that out sorts it. Now on to build my level!! BTW this is a uni project, but I’ll happily send you want I’ve made once its finished.

      • Which University do you attend, and what is the class called? That’s really cool that they’re assigning Cocos2d and Box2d programming assignments on the iPhone! I’d love to see your finished project.

        As for why the base is a circle and not a square, it’s to circumvent certain issues. Let’s say the player’s base was a square and that you have two platforms of the same height right adjacent to each other. For all intents and purposes, it should form one long platform but to box2d it’s two platforms. So the player’s base (that is a square) goes over the part where the two rectangles meet, there may be issues because the lower right corner of the player’s circle may hit the upper left corner of the 2nd platform.

        So its standard practice to use a capsule shape. If you search the interwebs, you should be able to find more info on it.

  5. I’m studying in london, University of wesminter. Well the projects was meant to be developed in a language which I had not used before, and I had heard about cocos2d which i thought would be a good idea. So I had to buy a wonderfully expensive iMac lol. I’ve got another question if you dont mind….

    I had my dpad on a hudlayer like this..;

    hudLayer = [[CCLayer alloc] init];

    [self addChild:hudLayer z:998];

    dPadRight =[CCSprite spriteWithFile:@"RightDPad.png"];
    dPadRight.position = ccp(130,40);
    [hudLayer addChild:dPadRight z:2];

    How do you go about using layers with box2d, I’m guessing its not working because it has something to do with the box2d world?..

    • Ah, I see.

      Box2d is a physics engine, and the physics world is separate from Cocos2d. The hudLayer you added is a Cocos2d object which you add to Cocos2d a node. You only define box2d objects and add it to the box2d world if you want that object to be simulated by the physics world.

      For what you are doing with the dpad stuff, you’ll want to intercept the user input (touch or mouse click if on the simulator) on the hud layer and figure out if the touch location on is the location where your dPadRight is positioned (130, 40) and take action accordingly.

  6. Well the dpad is on the screen, for some reason deleting the code and typing it again made a huge diference >.> even though its the same thing. Well I’ve got my dpad on the screen but…..

    1- its scrolling with the screen, so its not stationary
    2- its not recognizing the touches for some reason :S, i want the player to move while the user has their finger down on dpadleft/dpadright. This is the code im using for it;

    -(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
    CGPoint location = [touch locationInView:[touch view]];
    location = [[CCDirector sharedDirector] convertToGL:location];

    ///////////////Creates a box around dpadright to check if it gets pressed//////////////////
    CGRect MoveableLeftRect = CGRectMake(dPadLeft.position.x – (dPadLeft.contentSize.width/2),
    dPadLeft.position.y – (dPadLeft.contentSize.height/2),
    dPadLeft.contentSize.width,
    dPadLeft.contentSize.height);
    /////////////if touch is with the box coordinates then run moveLight Function////////////////

    if (CGRectContainsPoint(MoveableLeftRect, location)){
    //(CGRectContainsPoint(MoveableLeftRect, locationLeft)) {

    moveLeft = TRUE;

    }
    //if (moveLeft == TRUE) {

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

    //}

    ///////////////Creates a box around dpadright to check if it gets pressed/////////////////////////
    CGRect MoveableRightRect = CGRectMake(dPadRight.position.x – (dPadRight.contentSize.width/2),
    dPadRight.position.y – (dPadRight.contentSize.height/2),
    dPadRight.contentSize.width,
    dPadRight.contentSize.height);
    /////////////if touch is with the box coordinates then run moveRight Function////////////////
    if (CGRectContainsPoint(MoveableRightRect, location)) {

    moveRight = TRUE;

    }

    if (moveRight == TRUE) {

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

    }

    // if (location.x <= screenSize.width / 2) {
    // [player moveRight];
    // } else {
    // [player jump];
    // }
    return true;

    }

    and this is the dosomething function

    -(void)dosomething:(ccTime)dt{

    if (moveLeft==TRUE) {
    Ppayer.position = ccp(player.position.x -100*dt, player.position.y);

    if (player.position.x < 16) {
    player.position = ccp(16, player.position.y);

    }
    }

    if (moveRight==TRUE) {
    player. = ccp(player.position.x +100*dt, player.position.y);

    }

    }

    sorry for the wall of text lol, think you could help me out with what I'm doing wrong?

    • I have to leave for work soon, but really quickly, the reason your dpad is scrolling is because it is on the same layer as the layer that scrolls.

      This is the structure you will want to have:

      layer (dpad)
      |
      +— child layer (where player and platforms reside)

      The child layer will scroll, but not the dpad layer. You’ll want to add the layer with the player and the platform as a child of the dpad layer. Make sure you have set the isTouchedEnabled to true, and when you receive the input, call the method on the child layer to move the player, which will scroll the child layer. Because the dpad layer is on a separate layer, it will not scroll.

      Good luck!

      • Hello, Min. I made the game layer as a child of my HUD (Controller) layer. Could you tell me the specific code i need in order to “call the method on the child player to move my player”? Do you mean that i need to call the method on the HUD layer from the child layer or opposite?

        Here is the function that I am using as a respond to the selector on my button (from SneakyInput) that sits inside my HUD Layer.

        -(void)jumpButtonPressed:(float)delta {

        // pressed
        if (rightButton.active == YES){

        // CALL METHOD HERE? <—————— Check this!
        // Button is pressed at the moment
        CCLOG(@"Touch input is working!");
        }

        else{
        // Button is NOT pressed at the moment. Do nothing here!
        }

        }

        • xMawiel,

          From your HUDLayer, call the jump method of the child object. If you have jumpButtonPressed inside the HUDLayer, then something like this.

          - (void) jumpButtonPressed:(float)deta {
          if (rightButton.active) {
          [player jump];
          }
          }

  7. Hmm. this code here which is in update is counter acting to my code, because he moves like 1 pixel then goes back 1 pixel….. not moving in other words. If i un comment it, the player moves but scrolling stops. Any idea why, or what i have to do to this code, as you saw about I’m using ‘dt’ for how ever long the user has their finger down to move the player. I’ve tried everything to this code.


    int32 velocityIterations = 8;
    int32 positionIterations = 1;

    // Instruct the world to perform a single step of simulation. It is
    // generally best to keep the time step and iterations fixed.
    world->Step(dt, velocityIterations, positionIterations);

    //Iterate over the bodies in the physics world
    for (b2Body* b = world->GetBodyList(); b; b = b->GetNext()) {
    if (b->GetUserData() != NULL) {
    //Synchronize the AtlasSprites position and rotation with the corresponding body
    CCSprite *myActor = (CCSprite*)b->GetUserData();
    myActor.position = CGPointMake( b->GetPosition().x * PTM_RATIO,
    b->GetPosition().y * PTM_RATIO);
    myActor.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
    }
    }

    b2Vec2 pos = [player body]->GetPosition();
    CGPoint newPos = ccp(-1 * pos.x * PTM_RATIO + 50, self.position.y * PTM_RATIO);

  8. Wow cool tutorial, just what ive been after :)

  9. Hey Min,

    Thanks for the Tutorial. it helped me a lot, I do have a problem that I cannot figure out and would hope you have an answer. I’m trying to remove the player sprite from my game after the ball hits the ground and becomes a sleep. I tried couple different things like removeChild and stuff but I get an EXC_BAD_ACCESS and I guess my code is trying to access the ball somewhere but can’t figure out where. Is there a way to delete the ball object and not get that error. Thanks!

    • Never mind, it was a memory management fuck up on my side. I wasn’t retaining an object that I was removing. Anyways thanks for the great tutorial and keep em coming :)

  10. Hey there, great tutorial. The sample code has been a huge help in getting my own game development up and running. I just have a quick question about the player controls.

    I have the player moving left/right when you touch either side of the screen. However I was looking to tie these actions to two buttons – left and right respectively (a little similar to the D-Pad that Mike talked about above me). I am unsure whether adding these as Sprites or MenuItems would be best, and how I would go about checking whether they had been pressed by the user?

    Do you have any idea how I would implement this into your code? Any help would be appreciated, thanks.

  11. I’ve been looking for some source like this for a long time and I’d just like to thank you for making a perfect example.
    I’ve used your old tutorial to adapt this into an autoscrolling game (basically moveRight is automatic).
    My question to you is, how can you make the player jump only when in contact with the platforms.
    I noticed in ContactListener.mm you have a CCLog telling xcode when the player leaves and retouches the platform.
    I was hoping there was a way to use a BOOL, then compare it in the GameScene.
    Thank you for any help you can provide.

    • Hi Alex,

      Great! I’m happy to hear that you found it useful. Yes, you can definitely have a global boolean variable that is set to true when the player makes contact with the platform and set to false when the player loses contact with the platform. That is one way.

      The other way is to create a boolean member variable inside the Player class to keep track of it. Notice in BeginContact and EndContact (in ContactListener.mm), you can get access to the GameObject objects (the two objects colliding with one another). The only thing you’d have to figure out is which one of the objects (o1 or o2) is the player object. Because the Player class inherits from the GameObject class, you can test for the type by checking the type member variable. So you can do something like this:

      Player *player = (Player*)(o1.type == kGameObjectPlayer ? o1 : o2);

      After you have the player, you can set the boolean variable:

      player.isInContactWithPlatform = YES;

      And whenever a jump is performed, just check that variable. Hope this helps!

      Warm regards,
      Min

      • Thank you Min, that did the trick just nicely.
        I really appreciate how fast you replied to my question.
        The next thing I plan to implement is different jump distances depending on the duration the touch is held.
        I’ll let you know how I get on/ask more questions if I get stuck…

  12. Hey Min, it’s me again.
    As I said in my other post I have being trying to modify jump distances depending on the duration the touch is held.
    I have managed to get it to jump when ccTouchEnded but I want it to work on ccTouchBegan.
    If you look at this link:

    http://stackoverflow.com/questions/5799796/touchbegan-timestamp

    Scroll down to the answer to where it says, “Jump and boost the jump while the touch is ongoing up to x milliseconds (suggestion from grapefrukt).”

    I’m just not quite sure how to do this…
    I’m guessing we would need something that counts the milliseconds when the ccTouchBegan. In Player, we will need something that fetches the millisecond value and times it by the jump impulse, or something like that.
    I’m sorry to bother you with this, but it would be great if you could take a look and see what you think.

    • Alex,

      I’m doing this in my game, and I can tell you that the way I do it. I’m not counting time at all. I use the physics engine to help me out. On the initial jump, an impulse force is applied that propels the player upward. When the screen is touched and held, I continually apply a vertical force to make the player feel more “floaty”.

      Hope this helps!

      Warm regards,
      Min

      • Hmmm, I shall have a mess around with your theory and try and get something working.
        From what you’ve said, it seems to me that you must loop the touch event in some way whilst it is held.
        Each completion of the loop applies the vertical force.
        I’m also guessing when the touch ends the loop breaks and thus no more vertical force can be applied.
        I’m sorry if that sounds like rambling to you, I’m actually completely new to game development and box2D so thank you for helping me out.
        Please tell me if I’m on the wrong lines.

        Thanks again, Alex.

        • Hi Alex,

          Not at all. I’m new to it too :)

          Yes, that’s exactly what I’m doing. The important thing to remember is that you do not want to apply an impulse force, but rather a regular force (ApplyForce() instead of ApplyLinearImpulse()).

          Warm regards,
          Min

  13. Ok, Min, I did it! :D
    I don’t know if this is how you did it but here goes…

    In ccTouchBegan:

    canJumpHigher = YES;

    [player jump];
    id action1 = [CCDelayTime actionWithDuration:1];
    id action2 = [CCCallFunc actionWithTarget:self selector:@selector(jumpHigher)];
    id action3 = [CCDelayTime actionWithDuration:1];
    id action4 = [CCCallFunc actionWithTarget:self selector:@selector(jumpHigher)];

    [self runAction: [CCSequence actions: action2, action3, action4, action5, nil]];

    The CCSequence boosts the jump twice more, giving me a small, medium and large jump. I then added:

    canJumpHigher = NO;

    To my ccTouchEnded and then compared the BOOL in jumpHigher.

    So what do you think?

    • It’s not quiet how I did it. But if it works, then hey! It’s all good! :)

      The way I do it, I don’t call any Cocos2d methods. I apply a Box2d force to my player physics object. And then just update the sprite’s position and angle with the one calculated by the physics engine.

      • Wow, I think your method sounds much more impressive.
        The limitation with mine is getting the angle to look more like a fluid jump than a simple boost.
        You make it sound so simple there, but I wouldn’t know where to start.
        So, if I can assume your app is a very complex version of your simple platformer, do you carry out the box2d force in the Player or GameScene class. Same question again, but for updating the sprite’s position and angle? I’m guessing that is in the GameScene as you set the original position in the init and updated it in the update(ccTime)dt.

        Thanks again, for all the replies.
        Btw, I tried finding your apps on iTunes UK, but couldn’t find your company.

        • It’s pretty simple, actually. I literally just continue calling ApplyForce on the player’s physics object as long as the screen is held down. You can carry out the box2d force wherever you want — you can call it in GameScene directly, or encapsulate that method within the player class. What is important is that the player’s physics object gets the force applied.

          We were going through some internal problems with the company, so we removed all apps from sale. But hopefully it’ll be back up soon, along with the new game that I’m working on based on the simple tutorial that I posted here (and yes, it’s a more fleshed out version of the simple platformer).

          Good luck!

          • So I looked into ApplyForce and found various code.
            One I’ve tried is:

            b2Vec2 force = b2Vec2(4.0f, 10.0f);
            body->ApplyForce(force, body->GetWorldCenter());

            I’m currently still using my CCSequence, so I called the ApplyForce in jumpHigher, but the player doesn’t move at all… I’ve tried different variations of the above code and no force seems to be applied…

            When you say “calling ApplyForce”, does that mean in your ccTouchBegan, you are calling the [player jump]. Then in the jump void, do you have a check BOOL to see if the touch has been let go, if not ApplyForce to Player’s physics object.

            One thing I’m stumped on, is how you can continuously call the ApplyForce. Does your ccTouchBegan have [player jump], multiple times? (Although, I don’t think that would work).

            Thanks again for your time Min.
            My iPhone Company is also a partnership with a friend of mine.
            However, for a while now, it seems I do most of the work, yet he still gets 50% cut.
            It annoys me, when I’ve worked very hard on the applications.
            What I’m trying to say is, I understand your situation as I too, have internal problems with a partner that’s not pulling their weight, but at the end of the day, their also my best friend.

            Could you email a reply to me?
            That way, I can stop spamming your blog…

            Alex.

          • I would appreciate to know the answer as well.

  14. thank you very much for those excellent rare tutorials , you helped me a LOT

  15. i would to ask. how can i access the GameScene function from this function?

    void ContactListener::BeginContact(b2Contact *contact) {
    GameObject *o1 = (GameObject*)contact->GetFixtureA()->GetBody()->GetUserData();
    GameObject *o2 = (GameObject*)contact->GetFixtureB()->GetBody()->GetUserData();

    if (IS_PLATFORM(o1, o2) && IS_PLAYER(o1, o2)) {
    CCLOG(@”—–> Player made contact with platform!”);
    i want to pass value to gamescene. or access game scene function.
    }
    }

    • There are multiple ways to achieve this –

      You can store a reference back to the gane scene in your game object or you can make GameScene a singleton.

      • Thanks, but now i had a problem. i try adding the joystick. Then when i hold the joystick the i will update the velocity. and move the character. The problem occurs when the impulse keep adding to the character and it moves very2 fast.
        -(void) tick: (ccTime) dt
        {
        float vx = ((HelloWorld *)parent_).joystick.velocity.x;
        if (vx!=0) {
        [_player moveCharacter:vx*5];
        }
        }
        -(void) moveCharacter:(float)movement {
        b2Vec2 impulse = b2Vec2(7.0f, 0.0f);
        body->ApplyLinearImpulse(impulse, body->GetWorldCenter());
        }
        -(void) jump {
        b2Vec2 impulse = b2Vec2(0.0f, 15.0f);
        body->ApplyLinearImpulse(impulse, body->GetWorldCenter());
        }

        then i change the to SetLinearVelocity. it solve the problem but now my character when it jumping and i move the joystick. the character will flying and didn’t go down until i release the joystick. Is there any suggestion or the best way to sove this?

        -(void) moveCharacter:(float)movement {
        b2Vec2 impulse = b2Vec2(7.0f, 0.0f);
        body->SetLinearVelocity(impulse);
        }

        • Ash,

          I would recommend taking a look at the ApplyForce function in box2d. It applies a constant amount of force over time, and not an impulse force instantaneously.

  16. Great tutorial. I could use some help with it though. Instead of looking where the finger is on the screen, I want to know what the player sprite has been touched and use that for movement. It was working fine, but once I added the scrolling, the problem arose that the screen touch location is no longer the world touch location, so the sprite is bounding box and touch location aren’t realizing they intersect. How can I go about fixing this?


    -(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
    {
    fingerLocation = [Helper locationFromTouch:touch];

    //Check if this touch is on a player's sprite
    BOOL isTouchHandled = CGRectContainsPoint([sprite boundingBox], fingerLocation);

    if (isTouchHandled) {
    CCLOG(@"player touchBegan");
    touched = YES;
    }

    return isTouchHandled;
    }

    Thank you so much,
    –Stephanie

    • Hi Stephanie,

      You may want to take a look at the TouchTest example in the Cocos2d testbed (it should be part of the Cocos2d distribution). You’ll see how to make a sprite receive touch events directly.

      You implement the CCTargetedTouchDelegate.

      @interface Paddle : CCSprite {
      }

      And then inside the Paddle implementation, you can intercept touches directly in ccTouchBegan.

      Hope this helps!

  17. Hi,

    thanks for this great bit of source code. Ive been playing with it extensively, and I would like to know if its ok if I base a game i am thinking about making, off of some of this code? Your code has helped me build a decent physics engine for a platformer.

    Thanks a lot

    Scott

  18. [...] Simple Platformer Using Cocos2d and Box2d with Collision Detection [...]

  19. This was done with the Xcode 3 IDE I assume. Any advice on where to start creating this using the Xcode 4 IDE and the cocos2d templates for it?

  20. Hey good tute i have already done a similar thing but i have an issue. I don’t know box2d all that well and i have set my levels up as there own CCLayer Class referencing it back the the main world as you will which loads levels briliantly but when i want to remove a level and add another it removes all tiles but leaves my object layer box2d bodies all around still (as they are part of the world not the layer i assume). So my question is without removing the entire world and restarting is there anyway to remove only the platform bodys from my world to load a new level?

    I may just have to use a game manager and reload world, levels and characters from scratch but if i didnt it would be nice to know. Thanks in advance.

    • Michael, you should be able to just destroy the box2d objects and recreate them.

      • Do you have any code for this?
        I have been trying to use

        for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
        {
        if (b->GetUserData() == platform) {
        //Synchronize the AtlasSprites position and rotation with the corresponding body
        world -> DestroyBody(b);
        }
        }

        Which successfully removes a single platform and then i load my next platforms but all the others except the one it removed are still there as Box2d Bodys.

        Im sure it is something i am not getting with how to call box2d bodys but im not sure.

        Thanks for your help.

        • Hi Michael,

          I’m confused. You said that “…but all the others except the one it removed are still there”. They are there because you didn’t remove it (which you said above). You need to remove them all if you want to clear out the whole thing.

          • Yup my issue is how to call all of them to remove them. im trying to cycle through all bodies and remove the ones with user data as platform? but only the one is being removed. what is the correcct way to call all of them and remove them?

          • I see. The problem is probably the line where you do if (b->GetUserData() == platform).

            Try checking the class type. Example: [myObject isKindOfClass:[Platform class]]

          • Excellent. Working perfectly thanks for your help Min.

            if anyone else wants to know i used the following code in my level dealloc method

            for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
            {

            if ([b->GetUserData() isKindOfClass:[Platform class]]) {
            //Synchronize the AtlasSprites position and rotation with the corresponding body
            world -> DestroyBody(b);
            }
            }

            So now i just load a subclass of CClayer to load my platform objects with reference to the main world then to load a new one i simply remove the child then re ad with reference to a new tiled map. This tute has made it easy stuff

  21. [...] Simple platforme game using cocos2d and box2d with collision detection: LINK [...]

  22. I was implementing this in cocos2dx and i got an error

    HEAP[Review2.win32.exe]: Heap block at 02D2B9F8 modified at 02D2BBE8 past requested size of 1e8
    Windows has triggered a breakpoint in Review2.win32.exe.

    This may be due to a corruption of the heap, which indicates a bug in Review2.win32.exe or any of the DLLs it has loaded.

    This may also be due to the user pressing F12 while Review2.win32.exe has focus.

    The output window may have more diagnostic information.
    The program ‘[1944] Review2.win32.exe: Native’ has exited with code 0 (0×0).

    Can some one help me wat does this mean ?

  23. For some reason, I cannot get these lines to work :/

    void ContactListener::BeginContact(b2Contact *contact) {

    GameObject *o1 = (GameObject*)contact->GetFixtureA()->GetBody()->GetUserData();
    GameObject *o2 = (GameObject*)contact->GetFixtureA()->GetBody()->GetUserData();

    if (IS_PLATFORM(o1, o2) && IS_PLAYER(o1, o2)) {
    CCLOG(@”Contact with platform y’all!”);
    }
    }

  24. [...] everyone! A few months have passed since I posted Simple Platformer Using Cocos2d and Box2d with Collision Detection. I have received many positive feedbacks and interest on the tutorial. I am glad that it has been [...]

  25. great tutorial !!

    I have a scroll endless game ,

    if I want the tilemap scroll endless , what should I do ?
    or , is anyway to know if the player hit the ground’s left edge , and the game stop ,player drop down ?

  26. This is the penalize Simple Platformer Using Cocos2d and Box2d with Collision Detection | Uchidacoonga journal for anyone who wants to essay out out virtually this topic. You observe so such its nearly wearying to represent with you (not that I really would want…HaHa). You definitely put a new twirl on a theme thats been typed nigh for age. Respectable nonsense, but large!

  27. Hi, great tutorial…. Two asks…

    I can make this in isometric map to detect player collision in the walls?
    I can read a polygon/polyline objects?

    Thanks…

  28. Great tutorial thank you.

    I have one question. If I want to change the sprite depending if the player is touching the platform or in the air… How would I do that?

 Leave a Reply

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>