Reza Ghobadinic

Scene Creation

In this post we will write classes that inherit from cocos2d::Scene class, show some sprite images and switch themselves with each other every two seconds.

Creating Scene Classes

Lets make two similar scene classes and call them SceneA and SceneB. They inherit directly from cocos2d::Scene and will have one sprite object that shows an image (Logo.png and Menu.png for A and B). Every two seconds, they will replace themselves with the other one.

#ifndef SceneA_h
#define SceneA_h

#include "cocos2d.h"
#include "SceneB.h"

class SceneA : public cocos2d::Scene
{
public:
    static cocos2d::Scene* createScene(); // Returns a Scene instance pointer
    virtual bool init();                  // Initializes the class
    CREATE_FUNC(SceneA);                  // Makes a create() method
                                          // Returns a pointer to an instance of itself
    void nextScene(float delta);          // Our scheduler to call the next scene
};

#endif

The cpp file will be:

#include "SceneA.h"

USING_NS_CC;

Scene* SceneA::createScene()
{
    return SceneA::create();
}

bool SceneA::init()
{
    if ( !Scene::init() )
    {
        return false;
    }
    
    auto sprite = Sprite::create("Logo.png");
    sprite->setPosition(512, 384);
    this->addChild(sprite);
    
    scheduleOnce(SEL_SCHEDULE(&SceneA::nextScene), 2);
    
    return true;
}

void SceneA::nextScene(float delta)
{
    auto director = Director::getInstance();
    auto scene = SceneB::createScene();
    director->replaceScene(scene);
}

Running And Repcaling Scenes

Remember I said the first scene always starts running with a call to runWithScene()? Good! Because that is how it starts.

runWithScene();                           // Use to run the first scene

That is why you have these lines somewhere in the AppDelegate class:

auto director = Director::getInstance();  // Get the instance of the director
auto scene = SceneA::createScene();       // Create your scene
director->runWithScene(scene);            // Call it to run only your FIRST scene.
                                          // Don't call it if there is already a running scene.

But after that, if you want to run a new scene, you should switch the running scene with a new one using replaceScene().

replaceScene();                           // Use to replace the running scene with a new scene

That is why we have these lines in our scene classes:

auto director = Director::getInstance();  // Get the instance of the director
auto scene = SceneB::createScene();       // Create your new scene
director->replaceScene(scene);            // Run to replace your scene with the new scene
auto scene = HelloWorld::createScene();

with:

auto scene = SceneA::createScene();

Download Source

More About Scene Methods

replaceScene() is not the only method in the Director class that works on scenes. There are more:

// Director Class Methods

runWithScene()                   // Call it to run only your FIRST scene.
                                 // Don't call it if there is already a running scene.

replaceScene()                   // Replace the running scene with a new one

pushScene(Scene* scene)          // Suspends the execution of the running scene, pushing it on the stack of suspended scenes.
popScene()                       // Pops out a scene from the stack.
popToRootScene()                 // Pops out all scenes from the stack until the root scene in the queue.
                                 // This scene will replace the running one. Internally it will call popToSceneStackLevel(1).
popToSceneStackLevel(int level)  // Pops out all scenes from the stack until it reaches level.
                                 // If level is 0, it will end the director. If level is 1, it will pop all scenes until it reaches to root scene.
                                 // If level is <= than the current stack level, it won't do anything.
getRunningScene()                // Gets current running Scene.
drawScene()                      // Draw the scene. This method is called every frame. Don't call it manually.

// GLView Class Methods

renderScene()                    // Renders a Scene with a Renderer This method is called directly by the Director.

// Node Class Methods

getScene()                       // Returns the Scene that contains the Node.
setScene()                       // Set the scene,this method shall not be invoked manually.

Out of these, the pushScene() and popScene() are the most interesting ones. They work similar to the replaceScene() but instead of destroying and deleting the old scene, they just use a stack to push and pop the older scenes into and out of.

The rest are quite self explanatory I think!

The CREATE_FUNC() Helper

CREATE_FUNC() that you saw in the header file of the scene class is a predefined Cocos2d-x C++ directive that automates making a create() method for the class to reduce the code size and save you some time. You can have a look at its definition here:

#define CREATE_FUNC(__TYPE__) \
static __TYPE__* create() \
{ \
    __TYPE__ *pRet = new(std::nothrow) __TYPE__(); \
    if (pRet && pRet->init()) \
    { \
        pRet->autorelease(); \
        return pRet; \
    } \
    else \
    { \
        delete pRet; \
        pRet = nullptr; \
        return nullptr; \
    } \
}

If you replace __Type__ with your class name and remove the #define line, you will see what it really is. A static member method that returns an instance of itself or nullptr if it fails. Nothing fancy!

static SceneA* create()
{
    SceneA *pRet = new(std::nothrow) SceneA();
    if (pRet && pRet->init())
    {
        pRet->autorelease();
        return pRet;
    }
    else
    {
        delete pRet;
        pRet = nullptr;
        return nullptr;
    }
}

You could just write this yourself and not bother with the CREATE_FUNC() at all.

Exit mobile version