Showing posts with label Breakout. Show all posts
Showing posts with label Breakout. Show all posts

Wednesday, January 28, 2015

[Tutorial] Cocos2d-x: The second game - Breakout - Create and destroy brick (Part 2)

Some tasks in this lesson:

+ Create bricks
+ Process physics collision
+ Check the destruction of bricks, if done, it's WINGAME
+ Check GameOver when the ball falls but not colliding with the paddle

- It seems muck work but it's simple because it's rather like the first game

Let's start!

Step 1 - Create bricks

Open file HelloWorldScene.cpp, add the following code block

for (int i = 0; i < 5; i++) {
static int padding = 100;
auto block = Sprite::create("blocks.png");
auto blockBody = PhysicsBody::createBox(block->getContentSize(), PHYSICSBODY_MATERIAL_DEFAULT);
blockBody->getShape(0)->setDensity(10.0f);
blockBody->getShape(0)->setFriction(0.0f);
blockBody->getShape(0)->setRestitution(1.f);
blockBody->setDynamic(false);
// Create the distance even among the bricks
int xOffset = padding + block->getContentSize().width / 2 +
((block->getContentSize().width + padding)*i);
block->setPosition(xOffset, 450);
blockBody->setContactTestBitmask(0x000001);
block->setPhysicsBody(blockBody);
block->setTag(3);
this->addChild(block);
}

Step 2 - Process the collision - Destroy bricks, Game Over

* Add ContactListener

auto dispatcher = Director::getInstance()->getEventDispatcher();
auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = CC_CALLBACK_1(HelloWorld::onContactBegin, this);  
dispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);

* Build the function onContactBegin

bool HelloWorld::onContactBegin(PhysicsContact& contact)
{
// Get two collided object
auto spriteA = (Sprite*)contact.getShapeA()->getBody()->getNode();
auto spriteB = (Sprite*)contact.getShapeB()->getBody()->getNode();

// Check kinds of objects
int tagA = spriteA->getTag();
int tagB = spriteB->getTag();

if (tagA == 3) // is brick
{

this->removeChild(spriteA,true); // delete brick

//spriteA->removeFromParentAndCleanup(true);
}

if (tagB == 3)  // is brick
{
this->removeChild(spriteB,true); // delete brick

//spriteB->removeFromParentAndCleanup(true);
}

// If the ball collides with the floor and the coordinate Y of the ball is smaller than the paddle, Game Over happens
if ((tagA == 0 || tagB  == 0 )& (ball->getPositionY() <= paddle->getPositionY()))
{
auto gameOverScene = GameOverScene::create();
gameOverScene->getLayer()->getLabel()->setString("You Lose!");
Director::getInstance()->replaceScene(gameOverScene);
}

return true;
}

This class GameOverScene is similar in the first project

Step 2 - check Win game

Build the function Tick() like this, remember that declare prototype function

void HelloWorld::tick(float dt)
{
// a bool variable confirm Win game and the initial value is true;
bool isWin = true;
// Vector bodies get all bodies of world ( ball, edge, paddle body)
Vector<PhysicsBody*> bodies = m_world->getAllBodies();

// Navigate the items in the above vector, check the kinds of objects by Tag, you should study again the "for" command, it has many variants for each special kind of class, you can read advanced C++ about list, vector, queue,etc.

for each(PhysicsBody* body in bodies) // This command will generate error when building android, you should edit as follow:  for (auto body : bodies) , this is the new standard for C++ v.11
{
if (body->getNode()->getTag() == 3) // If there is still  body of bricks, it means you haven't destroyed all yet.
{
isWin = false; // Not Win yet
}
}
// If navigate all isWin but not change, process Win game
if (isWin == true)
{
auto gameOverScene = GameOverScene::create();
gameOverScene->getLayer()->getLabel()->setString("You Win!");
Director::getInstance()->replaceScene(gameOverScene);
}
}

To call Tick() function, you should add this following command
this->schedule(schedule_selector(HelloWorld::tick),0); into the end of init() function

If you use scheduleUpdate(), you should build update(float dt) function

Build and Run now























Posted By Dev Bananaer8:47 PM

[Tutorial] Cocos2d-x: The second game - Breakout (Part 1)

In this game, you must do some following tasks:

+ Add objects into game
+ Set physics attributes ( using Chipmunk for ease )
+ Create the movement of the ball
+ Move the paddle

Step 1 - Add objects into game - Set physics attributes

Create a new project with familiar command:

>cocos new breakout -p com.vn.breakout -l cpp -d f:android/project

And remember to add USING_NS_CC; into HelloWorldScene.h 

Open file HelloWorldScene.h add some following commands in public area

Sprite* ball; 
Sprite* paddle;
Sprite* edgeSp;

PhysicsWorld* m_world; 

void setPhyWorld(PhysicsWorld* world){ m_world = world; };
// Touch event
void onTouchMoved(Touch *touch, Event *event);
void onTouchEnded(Touch *touch, Event *event);

bool onTouchBegan(Touch *touch, Event *event);
OK
Open file HelloWorldScene.cpp, edit createScene() function a bit like this:

auto scene = Scene::createWithPhysics();
scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
Vect gravity(0.0f, 0.0f); // Vector gia tốc =0
scene->getPhysicsWorld()->setGravity(gravity);
auto layer = HelloWorld::create();
layer->setPhyWorld(scene->getPhysicsWorld());

 you delete all init() function but this:

 if ( !Layer::init() )
    {
        return false;
    }

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

//---Delete all here

return true;

Add the following long code block into the deleted area

edgeSp = Sprite::create();
auto boundBody = PhysicsBody::createEdgeBox(visibleSize, PHYSICSBODY_MATERIAL_DEFAULT, 3);// Create physics body
boundBody->getShape(0)->setRestitution(1.0f); 
boundBody->getShape(0)->setFriction(0.0f);
boundBody->getShape(0)->setDensity(1.0f);
edgeSp->setPosition(Point(visibleSize.width / 2, visibleSize.height / 2)); // Set the position and the centre of Box in the center of the screen
edgeSp->setPhysicsBody(boundBody); // Set physics Body
boundBody->setContactTestBitmask(0x000001); // This is the important command, if not available, there is nothing happening when colliding
this->addChild(edgeSp); // Add into Layer
edgeSp->setTag(0); // Tag==0, to check object when colliding belongs to some kind

ball = Sprite::create("Ball.png", Rect(0, 0, 52, 52));
ball->setPosition(100, 100);
auto ballBody = PhysicsBody::createCircle(ball->getContentSize().width / 2.); // The physics body circle shape
ballBody->getShape(0)->setRestitution(1.0f);
ballBody->getShape(0)->setFriction(0.0f);
ballBody->getShape(0)->setDensity(1.0f);
ballBody->setGravityEnable(false); // Not set acceleration
Vect force = Vect(1010000.0f, 1010000.0f); // Create a force Vector to act with the direction of 45 degree, because x = y 
ballBody->applyImpulse(force); // Push a force into the ball edge
ball->setPhysicsBody(ballBody); // Set Physics body
ballBody->setContactTestBitmask(0x000001); //
ball->setTag(1);
this->addChild(ball);

// Similar with the ball
paddle = Sprite::create("Paddle.png");
auto paddleBody = PhysicsBody::createBox(paddle->getContentSize(), PHYSICSBODY_MATERIAL_DEFAULT);
paddleBody->getShape(0)->setRestitution(1.0f);
paddleBody->getShape(0)->setFriction(0.0f);
paddleBody->getShape(0)->setDensity(10.0f);
paddleBody->setGravityEnable(false);
paddleBody->setDynamic(false); // Set static when reacting, no restitution, no changing position
paddle->setPosition(visibleSize.width / 2, 50);
paddle->setPhysicsBody(paddleBody);
paddleBody->setContactTestBitmask(0x000001); // With reaction 
ball->setTag(2);
this->addChild(paddle);

Add the code block to create a Listener to catch Touch events ( using to control the paddle ) before the command: Return true;

auto touchListener = EventListenerTouchOneByOne::create();
touchListener->setSwallowTouches(true);
touchListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
touchListener->onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this);
touchListener->onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this);

_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);

Step 2 - Create the movement of the ball

Create the first movement for the ball by the following command ( in the above init() function created)

Vect force = Vect(1010000.0f, 1010000.0f); // Create a force Vector with 45 degree, because x = y

ballBody->applyImpulse(force); // Push a force into the ball edge

Step 3 - Move the paddle

Build 3 Touch functions, because we only use the onTouchMoved function to move so the other Touch functions we leave empty:

bool HelloWorld::onTouchBegan(Touch* touch, Event* event)
{
return true; // Not use but must return True
}

void HelloWorld::onTouchEnded(Touch* touch, Event* event)
{
// Not use
}

// Use to move the paddle simplest
void HelloWorld::onTouchMoved(Touch* touch, Event* event){
Point touchLocation = this->convertToWorldSpace(this->convertTouchToNodeSpace(touch));
// To be simple, use this command: Point touchLocation = touch->getLocation();
paddle->setPositionX(touchLocation.x); // Set the position horizontal of the paddle follow the Touch point
}

OK! Build and run now!



Posted By Dev Bananaer8:20 AM

Choose an Android item