Outdated Docs > Step by Step Cocos2dxSimpleGame Series > Chapter 7 - Some Icing on the Cake

Chapter 7 - Some Icing on the Cake

The simple game is completed basically, but we could add some adornments to make the game seem more professional.

In this chapter, we will add a new scene. When a certain quantity of monsters are killed, show “You Win” on the screen, and when there is a monster runs out of the left of the screen, show “You Lose”.

Now create two files GameOverScene.cpp and GameOverScene.h in the Classes directory.

GameOverScene.h

For GameOverScene.h:

#ifndef GAMEOVERSCENEH_
#define GAMEOVERSCENEH_

#include "cocos2d.h"

class GameOverLayer : public cocos2d::CCLayerColor
{
public:
GameOverLayer():label(NULL) {};
virtual ~GameOverLayer();
bool init();
CREATEFUNC(GameOverLayer);

void gameOverDone();

CC_SYNTHESIZE_READONLY(cocos2d::CCLabelTTF*, _label, Label);

};

class GameOverScene : public cocos2d::CCScene
{
public:
GameOverScene():layer(NULL) {};
~GameOverScene();
bool init();
CREATEFUNC(GameOverScene);

CC_SYNTHESIZE_READONLY(GameOverLayer*, _layer, Layer);

};

#endif // GAMEOVERSCENEH_

Port Tips:

1.The class member functions could be realized in the .m file without declaration in the header file, but it is illegal in c++, so there is bool init(); in GameOverScene.h.
2. The function node() is convenient for developers because of integration of new, init, and autorelease, etc.. But there is no keyword like self(objc) in c++, so CCLayer::node() and CCScene::node() should be realized in their derived classes. The realization of node() is similar, we construct two macros to make the realization more easy: LAYER_NODE_FUNC and
SCENE_NODE_FUNC. To use the two macros, init() must be realized in the derived classes.
3. About constructors and init(). Cocos2d-x doesn’t port init() of objc to the constructor in c++ directly, because there is no return value in the c++ constructor, in this case, we have to handle the exception with a try-catch, but try-catch is not supported on Android SDK. So, Cocos2d-x initializes the classes in two stages by first calling the constructor and then initialize in init(). This method is also adopted in the interface design of iOS, for example, [[NSString alloc] init], and the utilization of c++ class in Samsung bada.
4. The setter and getter of _label and _layer are realized in @synthesize in objc, and we have constructed some macros in cocos2dx\include\Cocos2dDefine.h to simulate @property and @synthesize. In the codes above, CCX_SYNTHESIZE_READONLY defines the read-only member variable with only a getter and no setter. In c++, the inline function can only be defined in the header file, so @synthesize is realized in the header file naturally.

GameOverScene.cpp

For GameOverScene.cpp:

#include "GameOverScene.h"
#include "HelloWorldScene.h"

using namespace cocos2d;

bool GameOverScene::init()
{
    if( CCScene::init() )
    {
        this->_layer = GameOverLayer::create();
        this->_layer->retain();
        this->addChild(_layer);

        return true;
    }
    else
    {
        return false;
    }
}

GameOverScene::~GameOverScene()
{
    if (_layer)
    {
        _layer->release();
        _layer = NULL;
    }
}


bool GameOverLayer::init()
{
    if ( CCLayerColor::initWithColor( ccc4(255,255,255,255) ) )
    {
        CCSize winSize = CCDirector::sharedDirector()->getWinSize();
        this->_label = CCLabelTTF::create("","Artial", 32);
        _label->retain();
        _label->setColor( ccc3(0, 0, 0) );
        _label->setPosition(ccp(winSize.width/2, winSize.height/2));
        this->addChild(_label);

        this->runAction( CCSequence::create(
                                CCDelayTime::create(3),
                                CCCallFunc::create(this, 
                                callfunc_selector(GameOverLayer::gameOverDone)),
                                NULL));

        return true;
    }
    else
    {
        return false;
    }
}

void GameOverLayer::gameOverDone()
{
    CCDirector::sharedDirector()->replaceScene(HelloWorld::scene());
}

GameOverLayer::~GameOverLayer()
{
    if (_label)
    {
        _label->release();
        _label = NULL;
    }
}

There are two objects in GameOverScene.cpp, one scene and one layer. A scene can involve several layers. In this game, there is only one layer, and in its center, a label with the words “You Win” or “You Lose” will be showed for three seconds.

Port Tips

  1. Pay attention to GameOverLayer._label and GameOverScene._layer, they are declared in objc with @property (nonatomic, retain), it means that they are retained, so they should be released in dealloc. Similarly, there is retain() in init() of GameOverLayer and GameOverScene, and release() should be called in ~GameOverLayer() and ~GameOverScene() respectively.

  2. NSAutoReleasePool is also ported in cocos2d-x. This Garbage Collector is good for c++ programming, and the utility is the same as in iOS, more information refers to http://developer.apple.com/library/ios/#documentation/cocoa/reference/foundation/Classes/NSAutoreleasePool_Class/Reference/Reference.html.
    In cocos2d-x, we should call release() in two cases:

• The object is newed by ourself, for example, CCSprite *sprite = new CCSprite();
• The object is created by a static function, for example, CCSprite *sprite = CCSprite::spriteWithFile(...), in this case, we don’t need to release, but when sprite->retain() is called, then sprite->release() should be called too.

Then return to the issues, the GameOverScene should be called in some conditions: a certain number of monsters are killed or there is one monster escaped.

We add a variable in HelloWorldScene to count how many monsters are killed by the hero.

// cpp with cocos2d-x
protected:
int _projectilesDestroyed;

And Initialize it in HelloWorld::HelloWorld(),

// cpp with cocos2d-x
_projectilesDestroyed = 0;

Include GameOverScene.h in HelloWorldScene.cpp,

// cpp with cocos2d-x
#include "GameOverScene.h"   

After removeChild(target) in the targetsToDelete for loop of HelloWorld::update(), add the codes below to check the win condition.

// cpp with cocos2d-x
_projectilesDestroyed++;                       
if (_projectilesDestroyed >= 5)
{
  GameOverScene *gameOverScene = GameOverScene::create();
  gameOverScene->getLayer()->getLabel()->setString("You Win!");
  CCDirector::sharedDirector()->replaceScene(gameOverScene);
}

Add the codes below to check the failure condition in the “if (sprite->getTag() == 1)” conditional of spriteMoveFinished(),

// cpp with cocos2d-x
GameOverScene *gameOverScene = GameOverScene::create();
gameOverScene->getLayer()->getLabel()->setString("You Lose :[");
CCDirector::sharedDirector()->replaceScene(gameOverScene);  

Notice on Android

To compile correctly on Android, please don't forget to add GameOverScene.cpp into your Android.mk, like this:
<pre>
LOCAL_SRC_FILES := AppDelegate.cpp \
HelloWorldScene.cpp \
GameOverScene.cpp
</pre>
Many developers forget to do this step and meet compilation error on android.

Notice on Linux

To compile correctly on Linux, add GameOverScene.cpp to the Makefile in your proj.linux directory:
<pre>
SOURCES = main.cpp \
../Classes/AppDelegate.cpp \
../Classes/GameOverScene.cpp \
../Classes/HelloWorldScene.cpp
</pre>

Enjoy it

Now, everything is ready, compile and run, all kinds of effects will be showed, monsters everywhere, bullets everywhere, high background music and a prompt when you win or lose.

The whole game is completed now, cheers!

iPhone
android
win32

IOSWinScene.png (111.8 kB) huangrh, 2011-04-15 03:14

androidWinScene.png (57.9 kB) huangrh, 2011-04-15 03:14

Win32LoseScene.png (14.1 kB) huangrh, 2011-04-15 03:14

Sign up for our newsletter to keep up with the latest developments, releases and updates for Cocos2d-x.