If you're new here, you may want to subscribe to my RSS feed or follow me on Twitter. Thanks for visiting!
This is the second and final part of a tutorial on how to create a simple breakout game using the Box2D physics library that comes with Cocos2D. If you haven’t already, make sure you go through part 1 first!
We left off with a box that bounces around the screen and a paddle we could move with our fingers. Let’s start adding in some game logic by making the player lose if the ball hits the bottom of the screen!
Box2D and Collisions
To find out when a fixture collides with another fixture in Box2D, we need to register a contact listener. A contact listener is a C++ object that we give Box2D, and it will call methods on that object to let us know when two objects begin to touch and stop touching.
The trick to a contact listener, however, is according to the Box2D User Manual, you cannot perform any operation that alters game physics within the callback. Since this is something we will probably want to do (such as destroy an object when two objects collide), instead we will just keep references to the collisions so we can deal with them later.
Another tricky bit is we can’t just store references to the contact points that are sent to the listener, because they are reused by Box2D. So we have to store copies of them instead.
Ok enough talk, let’s try this out for ourselves!
When We’ve Hit Rock Bottom
Note that in this section we’re going to be using some C++ and the standard template library (STL) a bit. If you are unfamiliar with C++ or the STL, don’t worry about it too much – you can just copy and paste the code, it is general purpose and should work in your projects as well.
Ok. Click on your Classes folder and add a new file (File\New File), click “Cocoa Touch Class” on the left, and choose “Objective-C class”, verifying that “Subclass of NSObject” is selected, then click Next. Name your object MyContactListener, and click finish.
Right click on MyContactListener.m and rename the file to MyContactListener.mm. This is because we are actually creating a C++ class in this file, and the convention when you are using C++ in a file is to have the file end with mm.
Then replace the contents of MyContactListener.h with the following file:
#import "Box2D.h" #import <vector> #import <algorithm> struct MyContact { b2Fixture *fixtureA; b2Fixture *fixtureB; bool operator==(const MyContact& other) const { return (fixtureA == other.fixtureA) && (fixtureB == other.fixtureB); } }; class MyContactListener : public b2ContactListener { public: std::vector<MyContact>_contacts; MyContactListener(); ~MyContactListener(); 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); }; |
Here we define the structure that we will use to keep track of the data we’re interested in from the contact notifications. Again, we need to store a copy because the contact points passed in are reused. note we have to declare an equality operator here, because we’re going to use a the find() method to look for matching objects in the vector, which requires this method.
After that we declare our contact listener class, which derives from b2ContactListener. We just declare the methods we need to implement, as well as a STL vector that we will use to buffer our contact points.
Now replace the contents of MyContactListener.mm with the following:
#import "MyContactListener.h" MyContactListener::MyContactListener() : _contacts() { } MyContactListener::~MyContactListener() { } void MyContactListener::BeginContact(b2Contact* contact) { // We need to copy out the data because the b2Contact passed in // is reused. MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() }; _contacts.push_back(myContact); } void MyContactListener::EndContact(b2Contact* contact) { MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() }; std::vector<MyContact>::iterator pos; pos = std::find(_contacts.begin(), _contacts.end(), myContact); if (pos != _contacts.end()) { _contacts.erase(pos); } } void MyContactListener::PreSolve(b2Contact* contact, const b2Manifold* oldManifold) { } void MyContactListener::PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) { } |
We initialize our vector in the constructor. Then the only two methods we actually implement are BeginContact and EndContact. In BeginContact we make a copy of the fixtures that just collided, and store them in our vector. In EndContact, we look to see if the contact point is in our vector and remove it if so.
Ok, now let’s put this to use. Switch over to HelloWorldScene.h and make the following modifications:
// Add to top of file #import "MyContactListener.h" // Add inside @interface MyContactListener *_contactListener; |
Then add the following code to your init method:
// Create contact listener _contactListener = new MyContactListener(); _world->SetContactListener(_contactListener); |
Here we create our contact listener object, and call a method on the world object to set the contact listener.
Next add the cleanup code to dealloc before we forget:
delete _contactListener; |
And finally add the following code to the bottom of your tick method:
std::vector<MyContact>::iterator pos; for(pos = _contactListener->_contacts.begin(); pos != _contactListener->_contacts.end(); ++pos) { MyContact contact = *pos; if ((contact.fixtureA == _bottomFixture && contact.fixtureB == _ballFixture) || (contact.fixtureA == _ballFixture && contact.fixtureB == _bottomFixture)) { NSLog(@"Ball hit bottom!"); } } |
This iterates through all of the buffered contact points, and checks to see if any of them are a match between the ball and the bottom of the screen. For now, we just log this out with a NSLog message because it’s time to check if it’s working!
So compile and run in debug mode, and switch over to your console by clicking Run\Console, and whenever the ball intersects the bottom you should see a message in your log that reads “Ball hit bottom!”
Adding a game over scene
Add the GameOverScene.h and GameOverScene.mm files that we developed in the how to make a simple game with Cocos2D tutorial. Note that you’ll have to rename GameOverScene.m to GameOverScene.mm since we’re dealing with C++ code now or you will get compilation errors.
Then add the import to the top of your HelloWorldScene.mm file:
#import "GameOverScene.h" |
Then replace the NSLog statement with the following code:
GameOverScene *gameOverScene = [GameOverScene node]; [gameOverScene.layer.label setString:@"You Lose :["]; [[CCDirector sharedDirector] replaceScene:gameOverScene]; |
Allright, we’re getting somewhere! But what fun is a game where you can’t win?
Adding some blocks
Download a copy of a block image I made and drag it to the Resources folder of your project, making sure “Copy items into destination group’s folder (if needed)” is checked.
Then add the following code to your init method:
for(int i = 0; i < 4; i++) { static int padding=20; // Create block and add it to the layer CCSprite *block = [CCSprite spriteWithFile:@"Block.jpg"]; int xOffset = padding+block.contentSize.width/2+ ((block.contentSize.width+padding)*i); block.position = ccp(xOffset, 250); block.tag = 2; [self addChild:block]; // Create block body b2BodyDef blockBodyDef; blockBodyDef.type = b2_dynamicBody; blockBodyDef.position.Set(xOffset/PTM_RATIO, 250/PTM_RATIO); blockBodyDef.userData = block; b2Body *blockBody = _world->CreateBody(&blockBodyDef); // Create block shape b2PolygonShape blockShape; blockShape.SetAsBox(block.contentSize.width/PTM_RATIO/2, block.contentSize.height/PTM_RATIO/2); // Create shape definition and add to body b2FixtureDef blockShapeDef; blockShapeDef.shape = &blockShape; blockShapeDef.density = 10.0; blockShapeDef.friction = 0.0; blockShapeDef.restitution = 0.1f; blockBody->CreateFixture(&blockShapeDef); } |
You should understand this code pretty well by now. We create a body just the same way we did for the paddle, except this time we do it in a loop so we can easily create four blocks along the top. Also notice that we set the tag on the block sprite to 2, for future reference.
Compile and run this code, and you should now have blocks you can mess around with your ball!
Destroying the Blocks
To be a true breakout game, we need to destroy the blocks when the ball intersects them. Well we’ve already added the code to keep track of collisions, so all we need to do is modify the tick method!
Modify the code you added in the tick method to be the following:
std::vector<b2Body *>toDestroy; std::vector<MyContact>::iterator pos; for(pos = _contactListener->_contacts.begin(); pos != _contactListener->_contacts.end(); ++pos) { MyContact contact = *pos; if ((contact.fixtureA == _bottomFixture && contact.fixtureB == _ballFixture) || (contact.fixtureA == _ballFixture && contact.fixtureB == _bottomFixture)) { GameOverScene *gameOverScene = [GameOverScene node]; [gameOverScene.layer.label setString:@"You Lose :["]; [[CCDirector sharedDirector] replaceScene:gameOverScene]; } b2Body *bodyA = contact.fixtureA->GetBody(); b2Body *bodyB = contact.fixtureB->GetBody(); if (bodyA->GetUserData() != NULL && bodyB->GetUserData() != NULL) { CCSprite *spriteA = (CCSprite *) bodyA->GetUserData(); CCSprite *spriteB = (CCSprite *) bodyB->GetUserData(); // Sprite A = ball, Sprite B = Block if (spriteA.tag == 1 && spriteB.tag == 2) { if (std::find(toDestroy.begin(), toDestroy.end(), bodyB) == toDestroy.end()) { toDestroy.push_back(bodyB); } } // Sprite B = block, Sprite A = ball else if (spriteA.tag == 2 && spriteB.tag == 1) { if (std::find(toDestroy.begin(), toDestroy.end(), bodyA) == toDestroy.end()) { toDestroy.push_back(bodyA); } } } } std::vector<b2Body *>::iterator pos2; for(pos2 = toDestroy.begin(); pos2 != toDestroy.end(); ++pos2) { b2Body *body = *pos2; if (body->GetUserData() != NULL) { CCSprite *sprite = (CCSprite *) body->GetUserData(); [self removeChild:sprite cleanup:YES]; } _world->DestroyBody(body); } |
Ok, let’s explain this. We go through the contact points again, but this time after we check for collisions between the ball and the bottom of the screen, we take a look at the bodies that are colliding. We can get to the bodies by calling the GetBody() method on the fixtures.
Once we have the bodies, we check to see if they have user data. If they do, we cast them to sprites – because we know that’s what we’ve set the user data to.
Then we look to see what sprites are colliding based on their tags. If a sprite is intersecting with a block, we add the block to a list of objects to destroy.
Note that we add it to a list to destroy rather than destroying the body right away. This is because if we destroy the body right away, the world will clean up a lot of pointers leaving us with garbage data in our contact listener. Also note that we only should add it to the list if it isn’t there already!
Finally, we go through the list of bodies we want to delete. Note that we not only have to destroy the body from Box2D’s world, we also have to remove the sprite object from our Cocos2D scene.
Give it a compile and run, and you should now be able to destroy bricks! Yay!
Winning the Game
Next we need to add some logic in to let the user actually win the game. Modify the beginning of your tick method to read as follows:
- (void)tick:(ccTime) dt { bool blockFound = false; _world->Step(dt, 10, 10); for(b2Body *b = _world->GetBodyList(); b; b=b->GetNext()) { if (b->GetUserData() != NULL) { CCSprite *sprite = (CCSprite *)b->GetUserData(); if (sprite.tag == 2) { blockFound = true; } //... |
All we’re doing here is looking to see if we ever come across a block while we’re iterating through the objects in the scene – if we do find one we set the blockFound variable to true – otherwise it is false.
Then add the following code at the end of the function:
if (!blockFound) { GameOverScene *gameOverScene = [GameOverScene node]; [gameOverScene.layer.label setString:@"You Win!"]; [[CCDirector sharedDirector] replaceScene:gameOverScene]; } |
Here we just display a game over scene if no blocks were found. Give it a compile and run, and see if you can win the game!
Finishing Touches
The game is quite cool, but we need some sound of course! You can download the awesome background music I made and a cool blip sound I made to use. As usual, drag them to your resources folder once you’ve downloaded them.
By the way – I made the sound effect with an awesome program called cfxr that one of our commenters – Indy – pointed out. Thanks Indy this program pwns!
Anyway – once you’ve added the files to your project, add the following to the top of HelloWorldScene.mm:
#import "SimpleAudioEngine.h" |
And the following to your init method:
[[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"background-music-aac.caf"]; |
And finally the following at the end of your tick method:
if (toDestroy.size() > 0) { [[SimpleAudioEngine sharedEngine] playEffect:@"blip.caf"]; } |
And there you have it – your own simple breakout game with Box2D physics!
Gimme The Code!
Here’s the full code for the Cocos2D and Box2D Breakout Game that we’ve made in this tutorial.
Where To Go From Here?
Obviously this is a quite simple implementation of breakout, but now that you have this working there’s a lot more you can do. You could extend this code to give the blocks hit points and make the ball have to hit them a number of times before they are destroyed. You could add new blocks, let the paddle shoot lasers toward the blocks, whatever you dream up!
Let me know if you have any tips or suggestions for better ways to do things, and hope this comes in handy!
Category: iPhone








Aha
Hi,
Thanks again. Could I ask, why are we removing fixtures from the vector in EndContact? If we have ended a contact, we must have had a contact collision so why are we removing fixtures which have been involved in a collision?
Also, how do we know the collision mechanism has finished with all fixtures when the tick method is called?
Regards
indy
Hey Indy!
Well, the vector in our contact listener is meant to hold objects that are currently colliding. BeginContact is called when two objects begin to collide, so we should put things into the vector then. EndContact is called when two objects are no longer colliding, so we should remove things from the vector then.
As for your second question, I haven’t looked into the Cocos2D source to see the exact order of operations, but I suspect that the world->Step call ends up making the appropriate calls to ContactListener for that step, so the vector will be all set up for us by the time we start processing the data.
Hi,
Thanks…over thinking again ;-)
If 2 objects collide and get added to the vector, you want to delete one object (for example). Just because the collision ended, and the fixtures moved apart -they have still collided at some point, and so you still need to remove them…I am trying to understand if two objects can collide, be added to the vector, move apart, be removed from the vector – before the vector is processed and a collision is therefore missed…!
My head hurts
i
Hey Indy,
No definitely a good question you’re asking. I looked into the source code, and unless I’m missing something, I think it’s working like I suspected.
In our tick method, we call _world->Step() and then process the collisions. If you look into the source code for the world’s Step method, you’ll see it calls b2ContactManager::Collide, which detects any objects that collide and calls b2Contact::Update for any objects that are colliding, which then calls listener->BeginContact().
When this is complete, our vector should contain all objects that are colliding at that point in time. So if two objects are colliding they would be in this vector, and we would process them in our tick() method right afterwards, and they wouldn’t move apart until the next call to the tick() method (and hence _world->Step()).
Hi,
Thanks Ray. So this would only be an issue if you had your physics tick being called at a different rate to your collision detection tick!?
Keep up the good work.
Regards
i
I have a problem installing this in my iPhone device
It runs in the simulator not on the device
Any idea?
@Indy: Yep exactly! :]
@Local: Jared from the bouncing balls tutorial had the same problem, apparently it is an SDK issue, and he fixed it by setting the gcc compiler to 4.0 instead of 4.2.
Hi Ray
Very good tutorials. You did it man. Thanks.
I’ve gone through with both simple & this game coding… made me so happy. I’ve searched numerous times for a few things on regarding the cocos2d but in vain. I never got any clue till now from any where. All other tutorials were very basic. So when I saw your tutorials I couldn’t stop myself from asking you for some help. Actually I’m stuck at this point (my question) while coding for my on going project.
Actually I’ve been asked for a racing car game. So my question is:
How to move background(here is road) from top to bottom (continuously) in a fashion that it can look like road is coming closer & closer. Also while moving the set of sprites, their Y axes will in crease towards downward and not upward?
We can find some examples come with Cocos2d where sprite is moving with scale factor. But here is an obstacle (for me) that their Y axes are increasing in both directions… upward and downward.
Here is the sample game I’ve to make similar for iPhone. I’m avidly waiting of your reply.
http://www.mindjolt.com/games/crazy-cabbie
Thanks
@Jami – Thanks! Re: your question, not sure if it’s the best way, but you can set the vertices for the corners of the sprite quad to whatever you’d like, so you could stretch the stripes to get the effect you’re looking for. See this thread on the Cocos2D forums:
http://www.cocos2d-iphone.org/forum/topic/3967
Best of luck with your game!
just so anyone knows if you are looking for a good way to start making your game with a menu and box2D look at the code in these youtube videos on this guys blog, took me a while to find and thought i’d share
http://icodeblog.com/2009/01/15/iphone-game-programming-tutorial-part-1/
Hi Ray,
Love your tutorials mate! Keep them up.
My question is not particularly related to the game in this tutorial, but more so about cocos2d and box2d. I’m currently creating a game with no left and right edges on the window – which means any bodies that move beyond these points will disappear.
What I wanted to ask was, if my game character were to disappear on the right side, how would I ‘screen wrap’ them on to the left hand side, and vice versa? Bear in mind that my character will be subject to gravity and certain velocities, so I would need it to follow the same trajectory once it ‘screen wraps’. I hope that makes sense. Any feedback would be greatly appreciated mate.
Kind regards.
@Noah: You can use the SetTransform() method on a b2Body to “warp” it somewhere else across the screen for situations like this. It will maintain its velocity, etc.
Best of luck! :]
oops sorry wrong link, here it is
http://paulsonapps.wordpress.com/2010/03/01/iphone-cocos2d-day-1-menu-animated-sprite/
Hi Ray,
Nice tutorial, For my upcoming game, i somehow do not want to use actual physics, but fake physics, so it has funny elements in the game. Do you know a good place or tutorial for ball bouncing, collision, vectors which i could look at for making this fake physics engine ?
I do not want the overhead of Box2d too, just want to make it simple.
Thanks in advance
Hi,
thank´s for your great tutorials. I have got one questions. I would like to change the texture of the block sprite at runtime, but if I try to do it like this:
ock.texture=[[CCTextureCache sharedTextureCache] addImage:@”Block.jpg”];
I just change the last block. My question is, how can I access the other blocks??
@BlazeBit – I haven’t come across any tutorials like that (but then again, haven’t really looked for it either). If you find something good, let me know! :]
@Hugo – One solution is to just keep each block you add to the screen in an array, then you can loop through and update them.
Thanks for your reply Ray. I found some Maths and Physics tutorials, not bad, but need the time to read through this :
http://chortle.ccsu.edu/VectorLessons/vectorIndex.html
I have created 4 sprites . I am using below code to delete sprite on tap. But only some sprites are deleted on tap. is there any issue with the code below??
Thanks
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
// Choose one of the touches to work with
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
b2Vec2 convertedLocation = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);
std::vectortoDestroy;
std::vector::iterator pos;
for(pos = _contactListener->_contacts.begin(); pos != _contactListener->_contacts.end(); ++pos) {
MyContact contact = *pos;
b2Body *bodyA = contact.fixtureA->GetBody();
b2Fixture *bodyAfix = contact.fixtureA;
if (bodyA->GetUserData() != NULL ) {
CCSprite *spriteA = (CCSprite *) bodyA->GetUserData();
int j = spriteA.tag;
NSLog(@”Tag delete:%d”,j);
if (bodyAfix->TestPoint(convertedLocation)) {
if (std::find(toDestroy.begin(), toDestroy.end(),bodyA) == toDestroy.end()) {
toDestroy.push_back(bodyA);
}
}
}
}
std::vector::iterator pos2;
for(pos2 = toDestroy.begin(); pos2 != toDestroy.end(); ++pos2) {
b2Body *body = *pos2;
if (body->GetUserData() != NULL) {
CCSprite *sprite = (CCSprite *) body->GetUserData();
[self removeChild:sprite cleanup:YES];
}
_world->DestroyBody(body);
}
@Kumar: It sounds like you want to delete sprites based on tap, but the code as-written is looking through the *contacts* (which is the list of sprites that are colliding with other sprites).
If you want to delete sprites on tap, it’s as simple as just checking which sprites your tap intersects with, then removing those sprites and their associated bodies.
@Ray …
i have used below stmt to check if sprite intersects.
if (bodyAfix->TestPoint(convertedLocation))
{
}
Main problem i have is below loop detect only certain sprites …
for(pos = _contactListener->_contacts.begin(); pos != _contactListener->_contacts.end(); ++pos) {
i tried to print sprites tag (chk prev comment ) . i get only some sprite tags, not all .
CCSprite *spriteA = (CCSprite *) bodyA->GetUserData();
int j = spriteA.tag;
NSLog(@”Tag delete:%d”,j);
Amazing tutorial series. The only thing I can say is: these series accelerated my learning process, and I’m already programming a prototype :)
Thanks!
@Kumar: Looping through the objects from the contact listener should show you just the ones that are currently colliding – is this what you want to do, or are you trying to get all of the sprites?
@Alfred: w00t awesome! What kind of game are you making?
another great tutorial set I must say Ray, I have one question for you, Sometimes when I’m playing it will bounce back and forth and take forever to get down or up or sometimes it will just be straight and wont move at all. My question is, Is there a way to prevent this? like if it hits the same points a set amount of times it changes the angle or puts a corner there? Its just annoying and I actually like playing these kind of games lol.
Hi, if I want to keep the cat and car’s position(not remove the objects) when the collide detection happened, how to do this?
thanks
@Syn: Yeah I noticed that back when I was working on this as well. At some point I had put some code in there to check if the vector was close to straight up or straight to the side, and would apply an impulse to move the ball in a different direction if that happened. Not sure if there’s a better way to do it, but that’s what I tried at the time!
@peng: It looks like you may have meant to leave the comment on this tutorial?
http://www.raywenderlich.com/606/how-to-use-box2d-for-just-collision-detection-with-cocos2d-iphone
Anyway if you want to keep the position upon the collision, you can just replace the code that deletes the objects with whatever you want to do. But there is one trick: you’ll need to keep track that you have already processed the collision of the objects, otherwise your code will get called multiple times for the same collision (since this code is being called in the update loop). The way I did this in one of my games was to keep an array on the sprite object of what objects I’ve already seen collisions for and ignore the collision if I’ve already seen it, but how you do it depends on your particular game’s needs.
Thanks tutorials!
And, I have a question about ball size and Collision check.
I resize the ball
CCSprite *ball = [CCSprite spriteWithFile:@"Ball.jpg"
rect:CGRectMake(0, 0, 6, 6)];
and tried to check collision like this
if(contact.fixtureObject == _bottomFixture && contact.fixtureBullet == _bulletFixture)
{
NSLog(@”hit the bottom”);
}
But when ball hits bottom, console shows like this
2010-07-21 17:58:03.914 Box2DBreakout[10652:207] hit the bottom
2010-07-21 17:58:04.080 Box2DBreakout[10652:207] hit the bottom
Can someone help me?
Hi Ray,
I want to know how would you use the paddle with the accelerometer? Would you have to create a Paddle.h and have the accelerometer setup in that file and also, the paddleBodyDef stuff to?
Thanks Ray for you tutorials!
I was messing around with the tutorial (which is great by the way, thank you!) and when my ball collides with two blocks at the exact same time the game crashes. It’s very difficult to reproduce, but it happens every time. How would you process the multiple collisions at the same time?
@KevinKoss: You could do that, or you could just put the accelerometer callback in the HelloWorldLayer class and update the paddle position based on that there.
@Bryce: I just reduced the padding between blocks in the sample project to 0 to make it easier to hit 2 blocks at once, and couldn’t get it to crash here. Have you looked at the backtrace to see what the issue is?
Hi Ray,
Yeah I try that now, but I having a hard time making the paddle to move. I have this in didAccelerate
float acelx = -acceleration.y;
movement = acelx * 40; //movement as an instance variable
In the -(void) tick: (ccTime) dt section I have this
for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
{
if (b->GetUserData() != NULL) {
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());
if (myActor.tag == 3) {
//tag 3 is my paddle
//movement comes from accelerometer
myActor.position = ccp(myActor.position.x + movement, myActor.position.y);
}
I have debug turned on and I can see that both body and paddle image are connected but when I run it on the device it shows the paddle image moves within the bodydef but the b2body does not move.
Which do I move the b2body or bodydef or fixture? I’m a little confused.
I hope you can help
Thanks
kevin
I think I know now… :D
You have to apply force to move the paddle because its part of the physic simulation b2World. So, how would apply force to move left or right for the paddle?
Thanks
kevin
Hey Ray, These Tutorials are amazing!
I have one question that has been hanging over my head for a while. If I wanted to create different screens for levels or more importantly a menu, how would i go about doing that? would you suggest making a new scene for the menu and create objects that are buttons that allow the user to select other levels (or screens)? I think the menu part of an application is important and would appreciate it a ton if you could help me out with my problem!
and by the way, i just bought the Level Me Up app! You don’t know how often i wished my life had skills that were measurable with exp. it has made my life. Thank you.
@Kevin: To be honest I’m not sure off the top of my head, it’s been a while since I’ve played with Box2D now heh. Did you ever figure this out?
@Kyle: Thanks for the kind words, and for checking out Level Me Up too, I’m so glad you like it! I use it to track my iOS dev skills too hehe.
To answer your question, there’s a built-in class to create a menu in Cocos2D called CCMenu. For an example of how to use it, check out the MenuTest example that comes with Cocos2D, or the Tom the Turret sample game that comes with Cocos2D that Steve Oldmeadow and I put together a while back. It’s super easy don’t worry!
And to answer your other question, yeah usually I put the main menu on it’s own scene, as it just makese sense that way…
hello
i have a problem with ccTouchesBegan
- (void)ccTouchesBegan:(UITouch *)touches withEvent:(UIEvent *)event {
if (_mouseJoint != NULL) return;
_paddleBody=body2;
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);
if (_paddleFixture->TestPoint(locationWorld)) {
b2MouseJointDef md;
md.bodyA = groundBody;
md.bodyB = _paddleBody;
md.target = locationWorld;
md.collideConnected = true;
md.maxForce = 1000.0f * _paddleBody->GetMass();
_mouseJoint = (b2MouseJoint *)_world->CreateJoint(&md);
_paddleBody->SetAwake(true);
}
}
on the line
location = [[CCDirector sharedDirector] convertToGL:location];
i have such error
(gdb) continue
Program received signal: “EXC_BAD_ACCESS”.
Previous frame inner to this frame (gdb could not unwind past this frame)
Previous frame inner to this frame (gdb could not unwind past this frame)
and i do not get the reasone why
Help me, please
@andrew: At a quick glance, I don’t see any issues with the above code… but here’s the typical ways to track down the cause of an error like that:
1) Set the NSZombieEnabled argument in your executable options, which sometimes helps narrow down the cause
2) Run with Apple Instruments such as leaks to look for memory issues
3) Tried and true “comment out code till it works” then backtrack from there :]
Just to let everybody know if you get an error “ISO C++ forbids declaration of ‘MyContactListener’ with no type” – Make sure you have: #import “MyContactListener.h” at the top of HelloWorldScene.h
@Joni: Thanks for sharing the tip for others! :]
Darned C++ :)))) If it wasn’t for it I’d be rocking the App Store with Physics games :)))
Doing another of your tuts Ray and it’s just great, thanks
@Marin: Ha ha yeah there is quite a bit of C++ in Box2D :] Thanks for the kind words! :]
Hey ray,
I was wondering how could I change the paddle position manually? (paddle sprite + body + everything).
Like in normal sprites I would just :
paddle.position = ccp(x,y);
Thanks :).
@Jake: AFAIK, you’re not really supposed to change the position of objects manually in Box2D or weird things will happen with the physics simulation. Instead, you should apply impulses/forces/etc.
Hey Ray,
I copied the code EXACTLY from your tutorial up to the “Ball hit bottom!” part, but I’m getting errors that say, “ISO C++ forbids declaration of ‘MyContactListener’ with no type. Help?
Hey ray. :)
These are amazing tutorials.. :)
I want to know how would to knock down blocks when hit by a ball? Using box2d for sure..
I am pretty sure about you are the best guy to ask about it.. :)
@Jim: First thing I’d check is that your file is saved as MyContactListener.mm, not MyContactListener.m, in order for the compiler to recognize the usage of C++. If that fails, try comparing your code to the sample code to try to narrow it down.
@Quaso: Lol actually not sure if I am, since it’s been a while since I’ve used Box2D… but offhand, maybe try applying a force (simulating gravity) on the blocks once they’re hit by the ball.
Hi Ray,
Awesome tutorials mate – really special and helping me so much in dev’ing my first iPad game, so thankyou thankyou!
Just wondering if you’d be able to go through the ContactListener syntax a bit – I have a book on C++ but I can’t find out what is going on syntax wise.
For instance, in the HelloWorldScene when we are looking for contacts, you use the following:
” std::vector::iterator pos; ”
do you think it is in the scope of this post to dig a little deeper into the C++ stuff. I’d really like to understand properly what’s going on so that I can take what you’ve given us can be expand on it bigger projects.
Looking forward to hearing your thoughts. Cheers Ray!
@Emile: I’ll keep that in mind for future tutorials, but for right now I think a detailed explanation of the C++ syntax would be beyond the scope of this tutorial. Unfortunately using Box2D effectively does require a decent amount of C++ knowledge. If there are any specific questions you have, I’d be glad to help out though.
In the example you posted, that is a declaration of an iterator for a vector (an array-like collection type in the C++ standard template library). An iterator is an object you can use to cycle through all of the elements in a standard template library collection.
Hi Ray,
Great tuts! thanks a lot for posting these I know It must be lots of work, they have really helped me out.
I have a question I really hope you can help cause I’m stuck, really stuck.
I’m creating all elements as individual classes (objects) sub-classes of CCSprite.
I have all my touch events set up and everything.
Now, what I want is to be able to add a simple box that is static (not affected by gravity at this point) and then throw it (then physics kick in), then drag it again and throw it, and son on…
How could I do this? (the simplest way, without using mousejoints if possible…)
I just cant wrap my head around on how to do this.
Thanks a lot!!!
Hi again!,
I thought of an easier way to explain my question:
How can I drag a staticBody? (Static bodies is my game are obstacles, again, hopefully not using mousejoints if possible.)
Thank you!
@Mark: IMHO mouse joints are the easiest (and preferred) way of dragging bodies. If you’re looking for another example of how to do that other than the tutorials on this site, you can try the Box2D testbed for another example (see iPhoneTest.mm, MouseDown and MouseMove).
Great tutorials! It really helps me a lot ^_^
But just one question (just like Jimmy did), I did as the tutorials gose till the “When We’ve Hit Rock Bottom” part. Then I ran the demo, hoping to get the “Ball hit bottom!” message once the ball hit the bottom of the screen.
But what I get is: sometimes the console outputs “Ball hit bottom!” once (that’s right) while sometimes it outputs twice (in random?).
Then I downloaded the full code you wrote, then replaced the “You lose scene” part by “NSLog(@”Ball hit bottom!”)”. And I got the same result.
So I guess is there something wrong in the MyContactListener part?
Again, thanks for your wonderful tutorials ^_^
Hi Ray,
your tutorials are awesome! However, I am not sure why you store the bodies to destroy in a std::vector. I am refering to the following part of the code:
// Sprite A = ball, Sprite B = Block
if (spriteA.tag == 1 && spriteB.tag == 2) {
if (std::find(toDestroy.begin(), toDestroy.end(), bodyB)
== toDestroy.end()) {
toDestroy.push_back(bodyB);
}
}
Later on, you comment: “note that we only should add it to the list if it isn’t there already!”. I thought immediately that a set data structure fits nicely and would simplify the code a bit. These are the necessary changes:
//in HelloWorldScene.mm
#import
//…
- (void) tick: (ccTime) dt {
//declare the datastructure as std::set instead of std::vector
std::settoDestroy;
//…
// Sprite A = ball, Sprite B = Block
if (spriteA.tag == 1 && spriteB.tag == 2) {
toDestroy.insert(bodyB);
}
// Sprite B = block, Sprite A = ball
else if (spriteA.tag == 2 && spriteB.tag == 1) {
toDestroy.insert(bodyA);
}
//change the iterator for destruction to a set iterator
std::set::iterator pos2;
for(pos2 = toDestroy.begin(); pos2 != toDestroy.end(); ++pos2) {
//destroy bodies
}
//…
}
Maybe I miss some aspect you have considered but the code above works fine for me.
Oh, unfortunately the angle brackets have been swallowed…
I’ll repost the relevant lines once again using bars instead of angle brackets:
#import |set|
std::set|b2Body *|toDestroy;
std::set|b2Body *|::iterator pos2;
The rest of the code is not affected by the formatter as far as I can see.
Hello Ray,
Firstly, thanks a ton for these awesome tutorials! I’m an aspiring iPhone developer, and these things are gold to me.
However, I’m running into a problem. I’ve done everything in the Breakout tutorials with the exception of the Game Over and You Won portions. The program crashes when the ball contacts the brick.
After some commenting, I isolated the problem to the “world -> DestroyBody(body);” line after towards the end of the tick method. Without this line, the code runs fine, except, of course, that the bodies don’t get destroyed. Do you have any ideas what might be causing this?
I am getting the following error if the ball moves very close to the left bottom corner (0,0):
Assertion failed: (0 <= index && index < m_count), function GetVertex, file libs/Box2D/Collision/b2Distance.h, line 103.
Could you let me know how to fix it?
Thanks,
Great tutorial!
I am trying to modify the code to add a fireball, so that if it hits a brick, the brick is eliminated but the ball keeps going. Do you have any idea how to implement this?
I guess I should implement the contact listener and do something when they contact with each other but I’ve no idea.
Hi,
I have a Problem. I want a Sprite, that has an box2d body, to rotate with depending on an action. But I also want to have the physical objects like the ball in there.
So that the ball bounce if he touches the paddle.
An Idea how to do this?
Thanks
A little Addition: With the paddle I mean the rotating sprite.
I have followed the tutorial and get a load of errors=[
So I decided to download your code and imported the files in to xcode and I recieve these errors this is the a cleaned build fail of your downloadable code.
this is a image of my errors
http://s580.photobucket.com/albums/ss250/Krups/?action=view¤t=Screenshot2010-11-08at232634.jpg&newest=1
Thanks
@SuperSuRabbit: Well, the contact listener just reports the active contacts, so it is possible for the ball to be hitting the bottom in more than one frame, which is why you’d see it twice.
@Daniel: You are right, the set data structure does work better in this situation. I used vector out of habit heh.
@Bryce: Awesome, I’m really glad they are helpful! :] As for the issue, my first guess would be that the world pointer might be null. Try printing it out or checking with the debugger to see.
@Jason: Hm have not seen that happen before. Maybe try the Box2D forums?
@Hao: Probably the easiest thing is to make the brick a sensor, so it doesn’t affect the movement of the fireball. You can detect the collisions either with the contact listener as shown above, or checking the current contacts on the b2Body.
@coasterfreak: I’m not quite sure what your question is…
@Krups: You have to update both of the targets to be the latest version of the SDK. Ctrl-click on each target, choose Get Info, go to Build\Architectures\Base SDK, and set it to iOS Device 4.1.
Thanks for your reply, I got another question, is there any way to control the speed of the ball? As the paddle hits the ball, the ball bounces depending on how hard the paddle hits it, but if I wish to limit the speed, how to do this? Is overriding the “PostSolve” method helpful?
Thanks!
It is a great tutorial that make the learning curve of Box2D not so steep for me. Through this serials I have grasped the basic of Cocos2D and Box2D. When I played the resulting game I found a problem that sometimes the ball did not fall and moved back and forth forever at certain height owing that the gravity is set to zero. I tried to fix this problem by giving it a small value such as 0.05. Will it cause any problem? In addition, I hope I could be given the chance to translate this serials into Chinese to share with the those who are eager to learn Box2D but not well versed in English.
@Hao: You can use SetLinearVelocity() to set the speed to your maximum limit if it goes over. Check here for a discussion how:
http://www.box2d.org/forum/viewtopic.php?f=8&t=911
@Benjie: No problem to set the gravity if that is the effect you want in your game. As far as translation goes, if you are interested in translating a post from my blog email me and I’ll send you my translation policy.
Thanks for your reply. Up to now, I still can not find your email adderess. What I wanted is to translate this serials, so I hope you can send me the tranlation policy to the email at benjielin@gmail.com. Many thanks!
@Benjie: Sent! For future reference, you can reach me via the contact form on my site.
Hi Ray,
Another great tutorial :)
but i have an issue with the collisions, some times the ball collides with the brick and “bounce” back and some times it just continous on the same path in both cases there is a collision for sure…
how can i make sure the the phisics is sorted before i delete the brick.
Thanks,
Guy.
Hello Ray, and thank you for the tutorial!
I am observing a strange thing while running your code. You create 4 blocks and you use a constant padding value to create a gap between them. What I see on the screen, this gap is not always of the same width! In particular, the 4th block is 2 gaps away from the 3rd block…
My guess is Box2d causes this behavior. If I only create block sprites and place them on the screen and don’t connect any bodies to the sprites, I get gaps of the same width between the blocks.
Thanks!
Greets from Latvia.
@guy: One way is to set a flag on a brick when the ball collides with it, but don’t delete it till after the ball stops colliding with the brick (i.e. has bounced away).
@Ilja: Whoops, nope that was my own mistake. When setting the Box2D position for the blocks, it should be this:
Before the xOffset was just an int, so it was having a rounding error.
@Ray: yes it solves the problem and now I can add more blocks and it all looks good. Thank you for your help!
Hi,
thanks ray, thats what i did, just wanted to make sure its the right way and i’m not missing something :)
Thanks again,
Guy.
Ray,
another thing i am worried about. I have slightly modified your code: added more blocks, made them smaller etc. I didn’t introduce any randomness though. What I get every time I run the simulation is different behavior for the ball and (or) the blocks. The ball seems to hit the blocks by the slightly different angle every time I do restart, (or) the blocks move slightly different each time.
I do believe it’s not my modifications which causes it, i don’t have any randomness in my code (no random stuff in your code either as far as i am concerned). What do you think it is? Round-off errors in core of Box2D? But why are they different each time?
Simply awesome tutorials…. i cant wait to start working on it…
Thanx a lot :)