How To Create A Breakout Game with Box2D and Cocos2D 2.X Tutorial: Part 1

Discussion of the official tutorials published on raywenderlich.com. Please only discuss the official tutorials here - for general questions, use the General Discussion forum instead.

How To Create A Breakout Game with Box2D and Cocos2D 2.X Tutorial: Part 1

Postby rwenderlich » Fri Jan 18, 2013 12:00 pm

This is the official thread to discuss the following blog post: How To Create A Breakout Game with Box2D and Cocos2D 2.X Tutorial: Part 1
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
Ray Wenderlich
Blog: http://www.raywenderlich.com
Twitter: http://twitter.com/rwenderlich
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
User avatar
rwenderlich
Team Member
Site Admin
 
Posts: 2221
Joined: Thu Dec 23, 2010 4:14 pm
Has thanked: 28 times
Been thanked: 359 times

Re: How To Create A Breakout Game with Box2D and Cocos2D 2.X

Postby khalid » Sun Jan 20, 2013 11:27 pm

Dear Sir,
Thanks for your nice tutorials,
I am working on this breakout with ARC enabled i faced a few problems I solved some but when it gets to touches began
The project runs fine but as soon I click it gives error and takes me direct to GetMass
It highlights the (return m_mass) in b2Body header file

If you can help me with this
khalid
Uber Haxx0r
 
Posts: 55
Joined: Sun Jan 13, 2013 6:28 pm
Has thanked: 5 times
Been thanked: 1 time

Re: How To Create A Breakout Game with Box2D and Cocos2D 2.X

Postby bcbroom » Mon Jan 21, 2013 3:18 am

I'll admit this is not something I looked into when updating the tutorials. I know that there are some issues with ARC and Cocos2d, and there is a tutorial on getting Cocos to work with ARC here http://www.raywenderlich.com/23854/arc-and-cocos2d-v2-x. You might want to start there if you haven't already.

I'm not sure if Box2D being in c++ causes any issues with ARC.
bcbroom
Team Member
iOS Tutorial Team Member
 
Posts: 11
Joined: Wed May 16, 2012 1:00 am
Has thanked: 0 time
Been thanked: 1 time

Re: How To Create A Breakout Game with Box2D and Cocos2D 2.X

Postby khalid » Mon Jan 21, 2013 7:59 am

here i am going to paste all the code which is in Hello world layer some i do have if you please have a quick look at this. i wanted to upload the project but the max size for the file which is allowed is 256KB so i was not able to upload the project.

but if you want to have a quick look to the project i can email it to you but i don't have your email address here is my email
( afridikhalid@yahoo.com )

// Import the interfaces
#import "HelloWorldLayer.h"

// Needed to obtain the Navigation Controller
#import "AppDelegate.h"

#import "PhysicsSprite.h"


#pragma mark - HelloWorldLayer

@interface HelloWorldLayer()
@end

@implementation HelloWorldLayer

+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];

// 'layer' is an autorelease object.
HelloWorldLayer *layer = [HelloWorldLayer node];

// add layer as a child to scene
[scene addChild: layer];

// return the scene
return scene;
}

-(id) init
{
if( (self=[super init])) {

// enable events
CGSize winSize = [CCDirector sharedDirector].winSize;

self.isTouchEnabled = YES;


// Create a world
b2Vec2 gravity = b2Vec2(0.0f, 0.0f);
_world = new b2World(gravity);

// Create edges around the entire screen
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0, 0);
_groundBody = _world->CreateBody(&groundBodyDef);

b2EdgeShape groundBox;
b2FixtureDef groundBoxDef;
groundBoxDef.shape = &groundBox;

groundBox.Set(b2Vec2(0,0), b2Vec2(winSize.width/PTM_RATIO, 0));
_bottomFixture = _groundBody->CreateFixture(&groundBoxDef);

groundBox.Set(b2Vec2(0,0), b2Vec2(0, winSize.height/PTM_RATIO));
_groundBody->CreateFixture(&groundBoxDef);

groundBox.Set(b2Vec2(0, winSize.height/PTM_RATIO), b2Vec2(winSize.width/PTM_RATIO, winSize.height/PTM_RATIO));
_groundBody->CreateFixture(&groundBoxDef);

groundBox.Set(b2Vec2(winSize.width/PTM_RATIO, winSize.height/PTM_RATIO), b2Vec2(winSize.width/PTM_RATIO, 0));
_groundBody->CreateFixture(&groundBoxDef);


// Create sprite and add it to the layer
CCSprite *ball = [CCSprite spriteWithFile:@"ball.png"];
ball.position = ccp(100, 100);
ball.tag = 1;
[self addChild:ball];


// Create ball body
b2BodyDef ballBodyDef;
ballBodyDef.type = b2_dynamicBody;
ballBodyDef.position.Set(100/PTM_RATIO, 100/PTM_RATIO);
b2Body *ballBody = _world->CreateBody(&ballBodyDef);
ballBody->SetUserData((__bridge void*)ball);

// Create circle shape
b2CircleShape circle;
circle.m_radius = 26.0 /PTM_RATIO;

// Create shape definition and add to body
b2FixtureDef ballShapeDef;
ballShapeDef.shape = &circle;
ballShapeDef.density = 1.0f;
ballShapeDef.friction = 0.f;
ballShapeDef.restitution = 1.0f;
_ballFixture = ballBody->CreateFixture(&ballShapeDef);

b2Vec2 force = b2Vec2(10,10);
ballBody->ApplyLinearImpulse(force, ballBodyDef.position);


// Create paddle and add it to the layer
CCSprite *paddle = [CCSprite spriteWithFile:@"paddle.png"];
paddle.position = ccp(winSize.width /2, 50);
[self addChild:paddle];

// Create paddle body
b2BodyDef paddleBodyDef;
paddleBodyDef.type = b2_dynamicBody;
paddleBodyDef.position.Set(winSize.width/2/PTM_RATIO, 50/PTM_RATIO);
b2Body *paddleBody = _world->CreateBody(&paddleBodyDef);
paddleBody->SetUserData((__bridge void*)paddle);

// Create paddle shape
b2PolygonShape paddleShape;
paddleShape.SetAsBox(paddle.contentSize.width/PTM_RATIO/2, paddle.contentSize.height/PTM_RATIO/2);

// Create shape definition and add to body
b2FixtureDef paddleShapeDef;
paddleShapeDef.shape = &paddleShape;
paddleShapeDef.density = 10.0f;
paddleShapeDef.friction = 0.4f;
paddleShapeDef.restitution = 0.1f;
_paddleFixture = paddleBody->CreateFixture(&paddleShapeDef);


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

}
return self;
}


-(void) dealloc
{
delete _world;
_world = NULL;

}

-(void)tick:(ccTime) dt {
_world->Step(dt, 10, 10);
for (b2Body *b = _world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *sprite = (__bridge CCSprite *)b->GetUserData();
sprite.position = ccp(b->GetPosition().x * PTM_RATIO, b->GetPosition().y *PTM_RATIO);

sprite.rotation = -1 *CC_RADIANS_TO_DEGREES(b->GetAngle());
}
}
}


-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if (_mouseJoint != NULL) return;
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);

}
}



-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if (_mouseJoint == NULL) return;

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

_mouseJoint->SetTarget(locationWorld);
}

-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (_mouseJoint) {
_world->DestroyJoint(_mouseJoint);
_mouseJoint = NULL;
}
}


-(void)ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
if (_mouseJoint) {
_world->DestroyJoint(_mouseJoint);
_mouseJoint = NULL;
}
}
khalid
Uber Haxx0r
 
Posts: 55
Joined: Sun Jan 13, 2013 6:28 pm
Has thanked: 5 times
Been thanked: 1 time

Re: How To Create A Breakout Game with Box2D and Cocos2D 2.X

Postby nicopasso » Mon Feb 04, 2013 2:09 pm

Hi, nice tutorial!! The Box2D world is amazing!!!

But I've a problem :)

in ccTouchesBegan method the _paddleFixture->TestPoint check returns always false...

I don't understand why...can you help me? thanks

EDIT:
I'm an idiot... :shock:
I wrote the code of ccTouchesMoved in ccTouhcesCancelled and viceversa.
Now all works perfect!!! :D
nicopasso
Team Member
Hacker
 
Posts: 10
Joined: Wed Jun 27, 2012 2:27 pm
Has thanked: 0 time
Been thanked: 1 time

Re: How To Create A Breakout Game with Box2D and Cocos2D 2.X

Postby cocoscoder » Tue May 21, 2013 9:13 pm

How would I make only one sprite/body respond to touches using the mouseJoint. I would like the to move the ball only regardless where I am touching on the screen.
cocoscoder
n00b
 
Posts: 1
Joined: Tue May 21, 2013 9:07 pm
Has thanked: 0 time
Been thanked: 0 time

Postby Obelisk » Sat Jun 21, 2014 1:14 pm

As for me, I'm using Cocos2dx v3.0 and everything is working fine (The translating code into C++ is quite easy too, thanks to the Cocos2dx dev team ^^).

But now I'm facing a problem. My project is compiled and run fine on phone, but when testing on Windows 7 it always crash the very first time I click (which I believe a "touch").

Debugger showed me that the whole b2mouseJoint seem not be initialized at all, and the paddleFixture->TestPoint always false is the cause of that... but I really don't get it: even if it is false, the program should run fine , just nothing happen to the paddle, right?

Please give me some clue if you experienced this. Here's my code:

-----------------------------------------------------------------

#include "HelloWorldScene.h"

Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::create();

// 'layer' is an autorelease object
auto layer = HelloWorld::create();

// add layer as a child to scene
scene->addChild(layer);

// return the scene
return scene;
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !Layer::init() )
{
return false;
}

Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();

/////////////////////////////
// 2. add a menu item with "X" image, which is clicked to quit the program
// you may modify it.

// add a "close" icon to exit the progress. it's an autorelease object
auto closeItem = MenuItemImage::create("CloseNormal.png", "CloseSelected.png",
CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));

closeItem->setPosition(Vec2(origin.x - closeItem->getContentSize().width/2 + visibleSize.width,
origin.y + closeItem->getContentSize().height/2));

// create menu, it's an autorelease object
auto menu = Menu::create(closeItem, NULL);
menu->setPosition(Vec2::ZERO);
this->addChild(menu, 1);

/////////////////////////////
// 3. add your codes below...

// add a label shows "Hello World"
// create and initialize a label

auto label = LabelTTF::create("Hello World", "Arial", 24);

// position the label on the center of the screen
label->setPosition(Vec2(origin.x + visibleSize.width/2,
origin.y + visibleSize.height - label->getContentSize().height));

// add the label as a child to this layer
this->addChild(label, 1);

// add "HelloWorld" splash screen"
//auto sprite = Sprite::create("HelloWorld.png");

// position the sprite on the center of the screen
//sprite->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));

// add the sprite as a child to this layer
//this->addChild(sprite);

// Add sprites of objects to the layer
ball = Sprite::create("Ball.png");
ball->setPosition((visibleSize.width - ball->getContentSize().width)/2,
(visibleSize.height - ball->getContentSize().height)/2); // Center of the window
this->addChild(ball);

Sprite* paddle = Sprite::create("Paddle.png");
paddle->setPosition((visibleSize.width - paddle->getContentSize().width)/2, 50); // Bottom of window
this->addChild(paddle);

// Create a world
//b2Vec2 gravity = b2Vec2(0.0f, -9.8f); // Gravity of Earth
b2Vec2 gravity = b2Vec2(0.0f, 0.0f); // Gravity of some God-live planets
world = new b2World(gravity);

// Ball body and shape
b2BodyDef ballBodyDef;
ballBodyDef.type = b2_dynamicBody;
ballBodyDef.position = b2Vec2(ball->getPosition().x/PTM_RATIO,
ball->getPosition().y/PTM_RATIO);
ballBodyDef.userData = ball;
body = world->CreateBody(&ballBodyDef);

// Paddle body and shape
b2BodyDef paddleBodyDef;
paddleBodyDef.type = b2_dynamicBody;
paddleBodyDef.position = b2Vec2(paddle->getPosition().x/PTM_RATIO,
paddle->getPosition().y/PTM_RATIO);
paddleBodyDef.userData = paddle;
paddleBody = world->CreateBody(&paddleBodyDef);

// Physical shape of objects. Better the same as their respective graphical shape
b2CircleShape circle;
circle.m_radius = (68.0/2)/PTM_RATIO;
b2FixtureDef ballShapeDef;
ballShapeDef.shape = &circle;
ballShapeDef.density = 1.0f;
ballShapeDef.friction = 0.2f;
ballShapeDef.restitution = 1.0f;
body->CreateFixture(&ballShapeDef);

b2PolygonShape rect;
rect.SetAsBox((paddle->getContentSize().width/PTM_RATIO)/2,
(paddle->getContentSize().height/PTM_RATIO)/2);
b2FixtureDef paddleShapeDef;
paddleShapeDef.shape = ▭
paddleShapeDef.density = 10.0f;
paddleShapeDef.friction = 0.4f;
paddleShapeDef.restitution = 0.1f;
paddleFixture = paddleBody->CreateFixture(&paddleShapeDef);

// Create edge around the entire screen
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0, 0);

groundBody = world->CreateBody(&groundBodyDef);
b2EdgeShape groundEdge;
b2FixtureDef boxShapeDef;
boxShapeDef.shape = &groundEdge;

// Wall definition
groundEdge.Set(b2Vec2(0, 0), b2Vec2(visibleSize.width/PTM_RATIO, 0));
groundBody->CreateFixture(&boxShapeDef);
groundEdge.Set(b2Vec2(0, 0), b2Vec2(0, visibleSize.height/PTM_RATIO));
groundBody->CreateFixture(&boxShapeDef);
groundEdge.Set(b2Vec2(visibleSize.width/PTM_RATIO, 0), b2Vec2(visibleSize.width/PTM_RATIO, visibleSize.height/PTM_RATIO));
groundBody->CreateFixture(&boxShapeDef);
groundEdge.Set(b2Vec2(0, visibleSize.height/PTM_RATIO), b2Vec2(visibleSize.width/PTM_RATIO, visibleSize.height/PTM_RATIO));
groundBody->CreateFixture(&boxShapeDef);

// Using acceleromater. The deprecated message for Scene isn't used here
Device::setAccelerometerEnabled(true);
auto accelerateListener = EventListenerAcceleration::create(CC_CALLBACK_2(HelloWorld::onAcceleration, this));
this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(accelerateListener, this);

// Using touch
auto touchListener = EventListenerTouchAllAtOnce::create();
touchListener->onTouchesBegan = CC_CALLBACK_2(HelloWorld::onTouchesBegan, this);
touchListener->onTouchesMoved = CC_CALLBACK_2(HelloWorld::onTouchesMoved, this);
touchListener->onTouchesEnded = CC_CALLBACK_2(HelloWorld::onTouchesEnded, this);
this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(touchListener, this);

// Initialize interval vars
tickInterval = 1.0/60.0;
kickInterval = 2.0;

// Update the graphic to the physic every 1/60 sec
this->schedule(schedule_selector(HelloWorld::tick), tickInterval);

// Apply force to the ball every 2 sec
this->schedule(schedule_selector(HelloWorld::kick), kickInterval);

return true;
}

void HelloWorld::menuCloseCallback(Ref* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
return;
#endif

Director::getInstance()->end();

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
}

void HelloWorld::tick(float dt) {
world->Step(tickInterval, 10, 10);
for (b2Body* b = world->GetBodyList(); b; b = b->GetNext()) {
if (b->GetUserData() != NULL) {
Sprite* ballData = (Sprite*)b->GetUserData();
ballData->setPosition(Vec2( b->GetPosition().x * PTM_RATIO,
b->GetPosition().y * PTM_RATIO ));
ballData->setRotation(-1 * CC_RADIANS_TO_DEGREES(b->GetAngle()));
}
}
}

void HelloWorld::kick(float dt) {
b2Vec2 force = b2Vec2(100, 100);
body->ApplyLinearImpulse(force, body->GetPosition(), true);
}

void HelloWorld::onAcceleration(Acceleration* acc, Event* anEvent) {
// Landscape left values
b2Vec2 accGravity = b2Vec2(acc->y * 30, -acc->x * 30);
world->SetGravity(accGravity);
}

void HelloWorld::onTouchesBegan(const std::vector& touches, Event *touchEvent) {
if (mouseJoint != NULL) {
CCLOG("mouseJoint != NULL. Returned.");
return;
}

Touch* myTouch = new Touch();
for( auto &item: touches) {
myTouch = item;
}

Point location = myTouch->getLocationInView();
location = Director::getInstance()->convertToGL(location);
b2Vec2 worldLoc = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);

CCLOG("Touch began at x = %f, y = %f", location.x, location.y);

if (paddleFixture->TestPoint(worldLoc)) {
CCLOG("Tested point. Now init the mouseJoint.");
b2MouseJointDef mouseJointDef;
mouseJointDef.bodyA = groundBody;
mouseJointDef.bodyB = paddleBody;
mouseJointDef.target = worldLoc;
mouseJointDef.collideConnected = true;
mouseJointDef.maxForce = 1000.0f * paddleBody->GetMass();

mouseJoint = (b2MouseJoint*)world->CreateJoint(&mouseJointDef);
paddleBody->SetAwake(true);
}
}

void HelloWorld::onTouchesMoved(const std::vector& touches, Event *touchEvent) {
if (mouseJoint == NULL) {
return;
}

Touch* myTouch = new Touch();
for( auto &item: touches) {
myTouch = item;
}

Point location = myTouch->getLocationInView();
location = Director::getInstance()->convertToGL(location);
b2Vec2 worldLoc = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);

CCLOG("Touch moved to x = %f, y = %f", location.x, location.y);

CCLOG("before setting");
mouseJoint->SetTarget(worldLoc);
CCLOG("after setting");
}

void HelloWorld::onTouchesEnded(const std::vector& touches, Event *touchEvent) {
if (mouseJoint != NULL) {
world->DestroyJoint(mouseJoint);
mouseJoint = NULL;
}
}

void HelloWorld::onTouchesCancelled(const std::vector& touches, Event *touchEvent) {

}
------------------------------------------------------------------------------
Obelisk
n00b
 
Posts: 4
Joined: Mon Jul 01, 2013 9:40 am
Has thanked: 0 time
Been thanked: 0 time

Re: How To Create A Breakout Game with Box2D and Cocos2D 2.X

Postby Obelisk » Sat Jun 21, 2014 5:33 pm

Thank you all if you've ever read my post. I've just solved it by a little trying.

For some reasons (that I'm very eager to hear the explains from you pros) when run on Windows PC my mouseJoint was created but all empty by itself. When touched, the HelloWorld layer called its callback OnTouchesBegan and immediatly return (due to the checking result), so the mouseJoint remained empty (that means no m_bodyB of its has existed yet).

That's why the SetTarget, of which the detail code is

-----------------------------------------------------------
void b2MouseJoint::SetTarget(const b2Vec2& target)
{
if (m_bodyB->IsAwake() == false)
{
m_bodyB->SetAwake(true);
}
m_targetA = target;
}
-----------------------------------------------------------

has thrown out an error and cause crashing. I've comment the code that check "mouseJoint != NULL" in my OnTouchesBegan and the program run fine on Windows PC.

The strange is, as I said, when run in Windows platform, the mouseJoint is created, just empty, but on phone (Galaxy S2, Cyanogen mod - Android 4.3 FYI) it is NOT created at all... ???
Obelisk
n00b
 
Posts: 4
Joined: Mon Jul 01, 2013 9:40 am
Has thanked: 0 time
Been thanked: 0 time


Return to Official Tutorials

Who is online

Users browsing this forum: No registered users and 14 guests