User interface layer. Correct way to derive from CCLayer. Using multiple layers in one scene at once

Hello.

I want to make my user interface a class that derives from CCLayer.
I want to do this so that my user interface can be portable, and so that I can easily reproduce it in every scene along with other layers I might need, e.i. background layer, game layer e.t.c….

I want to know if the following way is the correct way to do it. Or am I missing something?

UserInterfaceLayer.h:

class UserInterfaceLayer : public CCLayer
{
    public:
    virtual bool init();

    LAYER_NODE_FUNC(UserInterfaceLayer);
}; 

UserIinterfaceLayer.cpp:

#include "UserInterfaceLayer.h" 

bool UserInterfaceLayer::init()
{
    bool bRet = false;
    do 
    {   // super init first        
        CC_BREAK_IF(! CCLayer::init()); 


    //todo, init stuff here

        bRet = true;
    } while (0);

    return bRet;
}

Then I create the game layer in all my scenes that need the user interface like so:

HelloWorld.cpp:

CCScene* HelloWorld::scene()
{
    CCScene * scene = NULL;
    do 
    {
        //Create the scene
        scene = CCScene::node();
        CC_BREAK_IF(! scene);

        //Create and add the main game layer
        HelloWorld *layer = HelloWorld::node();
        CC_BREAK_IF(! layer);       
        scene->addChild(layer);

        ////////////////////////////////////
        //Create and add the user interface
        ////////////////////////////////////
        UserInterfaceLayer* userInterfaceLayer = UserInterfaceLayer::node();
        CC_BREAK_IF(! userInterfaceLayer);
        scene->addChild(userInterfaceLayer);

    } while (0);

    // return the scene
    return scene;
}

Now from my understanding, I just need to develop my UserInterfaceLayer by adding objects and/or an update method, adding ccTouchesEnded, e.t.c…

Is this way correct? Will it clean up correctly? Did I miss anything? Can I make multiple layers like this and put them all in the same same scene?

1 Like

Anyone?

I just want to be sure I won’t get memory leaks, and that all will autrealease correctly, if I do it like the example above.

I think your code is ok.

Thanks Minggo Zhang.

Iv’e been using the code for about a week now and all seems well. No leaks. And the childs of the class seem to autorelease ok.

One more quick question about this.

If I derive a new class from this one, do I need to declare the LAYER_NODE_FUNC(UserInterfaceLayer) again in the derived class definition.
Or is it fine just once in the base class?

e.i.

    LAYER_NODE_FUNC(UserInterfaceLayer);

Yes, you should declare LAYER_NODE_FUNC(UserInterfaceLayer) again.

Great! :slight_smile:

Thanks a lot Minggo Zhang! I appreciate your quick replies.

You’ve been very helpful in answering my questions.

but how do you change something that’s in userInterfaceLayer? if it shows your score for example how do you call it from helloworld classes to change the score?

arnas dundulis wrote:

but how do you change something that’s in userInterfaceLayer? if it shows your score for example how do you call it from helloworld classes to change the score?

The UserInterfaceLayer instance exists in hello world. Or Helloworld can have a reference to it. Then You can use accessors e.i. getters and setters to access the classes in UserInterfaceLayer.

e.i.

    m_userInterfaceLayer->GetScoreBoard()->SetScore(1000);

could you post an example?
since the scene method is static i can’t create a private variable UserInterfaceLayer* userInterfaceLayer; since i get errors :

error C2597: illegal reference to non-static member 'HelloWorld::userInterfaceLayer'
error C2597: illegal reference to non-static member 'HelloWorld::userInterfaceLayer'

if i make a pointer and point it to userInterfaceLayer i get :

error C2597: illegal reference to non-static member 'HelloWorld::userInterfaceLayerPtr'

i can’t figure out another way since the scene variable only exists in the scene() method.

i tried doing

    HelloWorld *layer = HelloWorld::node();

    userInterfaceLayer->setUserData(layer);

and then

    CCMenuItemImage *pCloseItem = CCMenuItemImage::itemFromNormalImage(
                                        "CloseNormal.png",
                                        "CloseSelected.png",
                                        (HelloWorld*)this->getUserData(),
                                        menu_selector(HelloWorld::menuCloseCallback));

it compiles fine is clickable, shows the clicked sprite but does nothing as in doesn’t trigger HelloWorld::menuCloseCallback

well i figured a different approach if anybody ever needs to figure this out :

create a private layer variable in your class and initialize it in the init method

bool HelloWorld::init()
{
    userInterfaceLayer = UserInterfaceLayer::node();
    this->addChild(userInterfaceLayer,2);
    userInterfaceLayer->setUserData(this);

that way you can call the layer from your main class with userInterfaceLayer~~> and call your main class from the layer with this~~>getUserData())>
<pre>
void UserInterfaceLayer::menuCloseCallback
{
this
>getUserData())->menuCloseCallback(pSender);

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

Here is an example of creating an instance of user interface later in Hello World.
Let me know if this helps.

HelloWorld.h:

protected:
     //Declare pointer to a user interface layer
     UserInterfaceLayer* m_userInterface;

HelloWorld.cpp:

bool HelloWorld::init()
{
    bool bRet = false;
    do 
    {   // super init first        
        CC_BREAK_IF(! CCLayer::init());         


        ///////////////////
        //Initialize the user interface
        ////////////////////
        m_userInterface = UserInterfaceLayer::node();

        CC_BREAK_IF(! m_userInterface);

        //Set position of the user interface layer
        m_userInterface->setPosition(ccp(0.0f, 0.0f));

        //Add user interface to hello world layer
        this->addChild(m_userInterface, 1000);

        //Can now access the user interface layer from anywhere in the HelloWorld class.        

        //e.i. Set the score of the scoreboard in the user interface layer
        m_userInterface->SetScore(1000);

        //User interface layer can also be passed into other classes that need it       

        bRet = true;
    } while (0);

    return bRet;
}

Let me know of this helps.

yep, that’s what i’m doing now, thanks Marc! the only change i made is that i add HelloWorld’s this pointer to userInterfaceLayer’s userData so i can call HelloWorld from it.