Box2D Tutorial for iOS: How to Use Box2D For Just Collision Detection With Cocos2D iPhone
A Box2D tutorial for iOS on how to use Box2D for just collision detection, in order to make detecting collisions for polygon shapes easy and accurate. By Ray Wenderlich.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Box2D Tutorial for iOS: How to Use Box2D For Just Collision Detection With Cocos2D iPhone
25 mins
Fine Tuning the Bounding Boxes
As you may have noticed, the problem with the current setup is the shapes for the Box2D objects do not accurately represent the shapes of the sprites. For some games this is good enough, but there’s an extra degree of realism if we can define a shape that matches up somewhat to the actual shape of the sprite object.
In Box2D, you can define the vertices for shapes yourself by specifying the point for each vertex. However, hard coding all of these points is error-prone and time intensive. Luckily, Johannes Fahrenkrug has just released a neat tool called VertexHelper that makes defining these vertices and importing them into Box2D a snap.
Go ahead and visit the above site and download VertexHelper. Is is a Mac application with source code, so you’ll have to open VertexHelper.xcodeproj and compile and run the app. When you run the app you will see a screen like the following:
Go ahead and drag sprites.jpg into VertexHelper on top of the “Drop Sprite Image here” label, and in the Rows/Cols section set the number of rows to 1 and the number of columns to 2. VertexHelper will automatically draw lines on the image showing how the image is divided up.
Note that of course the image must be equally spaced for this to work – this is why we told Zwopple not to auto-chop the images earlier in the tutorial.
Next, click the check box for “Edit Mode” up top and start to define your vertices by clicking in counter-clockwise order around the sprites for each image. Note that Box2D will automatically close up the last point you click with the first point, so no need to connect them yourself.
Another very important thing to note pointed out by toadkick in the comments section that I wasn’t aware of at first. When you are defining the vertices, you need to make sure that the polygon you create is convex. This means that none of the internal angles can be greater than 180 degrees, or in more simple terms, there can be no “indentations.” If you are interested in more info on this, check out this great page that shows you a Javascript demo of convex vs. concave polygons.
Finally, note that Box2D defines a variable b2_maxPolygonVertices that limits how many vertices you can add per shape, which defaults to 8. You can change this in b2Settings.h if you need to, but for now just make sure that you draw a border around each sprite with at most 8 vertices.
Once you have that complete, in the type dropdown choose Box2D, and for the Style pick “Initialization”. In the box to the right it will put a bunch of code which we’ll be able to copy and paste into our project.
Ok so let’s fix our shapes up in our project! Open up HelloWorldScene.mm and modify the addBoxBodyForSprite method according to this template. Start by commenting out the spriteShape.SetAsBox call and then follow the instructions in the comments below:
/*spriteShape.SetAsBox(sprite.contentSize.width/PTM_RATIO/2,
sprite.contentSize.height/PTM_RATIO/2);*/
if (sprite.tag == 1) {
// Uncomment this and replace the number with the number of vertices
// for the cat that you defined in VertexHelper
//int num = 6;
//b2Vec2 verts[] = {b2Vec2(4.5f / PTM_RATIO, -17.7f / PTM_RATIO),
//b2Vec2(20.5f / PTM_RATIO, 7.2f / PTM_RATIO),
//b2Vec2(22.8f / PTM_RATIO, 29.5f / PTM_RATIO),
//b2Vec2(-24.7f / PTM_RATIO, 31.0f / PTM_RATIO),
//b2Vec2(-20.2f / PTM_RATIO, 4.7f / PTM_RATIO),
//b2Vec2(-11.7f / PTM_RATIO, -17.5f / PTM_RATIO)};
// Then add this
//spriteShape.Set(verts, num);
} else {
// Do the same thing as the above, but use the car data this time
}
A side note: Again, toadkick pointed out that it’s better to use the “Initialization” style and the b2PolygonShape::Set method rather than the “Assignment” style so that Box2D can automatically compute the centroid and the normals for the shape for us.
Once you have that done, compile and run your project. You should notice that the debug draw shapes around the sprites now match up much better, and the collisions are much more realistic!
Now you can see the true power of using Box2D for collision detection – defining bounding shapes like that would be a bit more tricky to do yourself.
Of course, in our case tailoring the bounding shape has the unfortunate side effect of letting a few cats scurry away that would have been squashed with our simple box method! ;]
And That’s A Wrap!
Here’s a sample project with all of the code we’ve developed in the above tutorial.
Note that this is only one way of doing collision detection with Box2D. Lam from the Box2D forums has pointed out another way where you can use functions such as b2CollidePolygons instead of using this method. If you are looking for just a quick collision check rather than going through all of the above setup, you might want to check out Lam’s method.
I’m really interested in hearing how other developers have used Box2D and Cocos2D in their projects – or are planning to use it – do you use Box2D for physics, or just for collision detection, or not at all? And if you use Box2D for collision detection, which method do you use?