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