Cocos2D on the Mac – Part 2 (Physics)

Adding in the Physics

In the last post you learned how to create a Cocos2D game for the Mac. For this post I am going to cover how you can add the Box2D Physics engine to your Cocos2D Mac games. It is really pretty easy, here you will learn how to get Box2D integrated into your project and mess with gravity, next week I will cover more about the Box2D Debug Renderer. I’ve tried to make this post somewhat brief, let me know in the comments what else you would like to see as well as any questions.

The TestBed for Box2D includes the Box2D Debug Render Engine for iOS using OpenGL ES. Since we are on the Mac, you want to exclude these for the time being, the next post will show you how to add the older OpenGL Debug Render Engine.

Step 2 – Change the Header Search Path

If you try to compile now you will get a ton of compile errors, over 2000K, since your code does not know where to find the Box2D classes. Fortunately this is easy to fix.

Click on your Project, and then the Info button, and search for “Header Search Path”
Add a header search path to the actual folder location for your Box2D source files (that you copied in Step 1). Be sure to check the recursive checkbox.

Step 3 – Changing to Objective-C++

Since Box2D code is in C++, your Objective-C files have to be Objective-C++, which just means you can mix and match Objective-C and C++ code. Simple rename all of your .m files to .mm
In your games you only need to change the .m files to .mm for any that include Box2D or classes which themselves include Box2D (or any C++).

You should be able to Build your project now without any errors. Test it to make sure everything is good before moving to Step 5.

Step 5 – Creating the Box2D world and ground bodies
Here you are going to add some lines to the init method to setup Box2D, and create ground bodies on the edges of the screen. Without ground bodies your box2d bodies/objects will just fall out of view.
Add this inside the init method:

Note the call to [self scheduleUpdate]. This will call the update method in Step 8 where the physics simulation will occur.

Step 6 – Adding the Box2D shape to the Sprites
Add the addNewSpriteWithCoords method above the init method in HelloWorldScene.mm, it builds on the same method you wrote on the previous post, adding a Box2D body for each Penguin.

Normally you want your bodies to be able to sleep, in this example we don’t because if you left the penguins at rest, changing the gravity would have no effect of them. In other words, having bodies sleep saves CPU cycles, but if you have a world with few collisions (like this example), then you have to be careful not to get your objects stuck. This being an example, the simplest solution is just to not let physics bodies sleep.

Step 7 – Add the handler for the Mouse and Arrow Keys
In this example the arrow keys change the gravity. If you press up, everything will be pulled towards the sky. Be sure to try out the arrow keys, especially with a few penguins on the screen.

Step 8 – Update Method to simulate the physics
Add this method above init to update the physics simulation and the positions of sprites associated to physics bodies. This is the same update method found in the Cocos2D iOS Box2D Templates.

-(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());
}
}
}

That’s it! Build and Run and click somewhere on the window. You will see a Penguin fall down to the bottom. Try using the arrow keys to have some fun with gravity.