addChild on the fly, something wrong?


#1

I’m trying to add a pause layer to my game by adding it’s layer on the fly, after the player touches the pause button. The problem is: it’s crashing! I know I must be doing something really wrong here, but I just can’t find it…
I preload the pause layer in the Scene’s onEnter pauseLayer = new PauseLayer();, pauseLayer is defined in my scene’s .h, but somehow it crashes when I try to add it to the scene…
01-29 04:54:37.123: A/libc(1371): Fatal signal 11 (SIGSEGV) at 0x000000d8 (code=1), thread 1384 (Thread-99)

Here’s the code:
PauseLayer.h

 class PauseLayer : public CCLayer {
    public:
        PauseLayer();
        virtual ~PauseLayer();
        void setResumeCallback(CCObject * target, SEL_CallFunc callfunc);
        void setQuitCallback(CCObject * target, SEL_CallFunc callfunc);
        CCMenu* pauseMenu;
    private:
        CCSprite* background;
        char* pauseTitle;
        CCLabelTTF* pauseTitleLabel;
        CCLabelTTF* resumeLabel;
        CCLabelTTF* quitLabel;
        CCObject* targetResume;
        CCObject* targetQuit;
        SEL_CallFunc resumeCallback;
        SEL_CallFunc quitCallback;

        void onResumeSelected(CCObject *pSender);
        void onQuitSelected(CCObject *pSender);
    };

PauseLayer.cpp

PauseLayer::PauseLayer() {
    CCLayer::init();
    background = NULL;
    pauseMenu = NULL;
    resumeCallback = NULL;
    quitCallback = NULL;

    pauseTitle = new char[50];
    if(DEBUG) CCLog("Loading Pause Layer");
    sprintf(pauseTitle, LanguageClass::sharedLanguageClass()->getStringFromKey("pauseTitle"));
    if(DEBUG) CCLog("Pause title loaded");
    background = CCSprite::createWithSpriteFrameName(s_HighScoreBG);
    background->setPosition(ccp(Constants::winSize.width / 2, Constants::winSize.height / 2));
    background->setScale(Constants::scale);
    background->retain();
    if(DEBUG) CCLog("Pause background loaded");
    pauseTitleLabel = CCLabelTTF::create(pauseTitle, s_FontPath, 52 * Constants::scale);
    pauseTitleLabel->setHorizontalAlignment(kCCTextAlignmentCenter);
    pauseTitleLabel->setPosition(ccp(background->getPositionX(), background->getPositionY() * 1.3));
    pauseTitleLabel->retain();
    if(DEBUG) CCLog("Pause title Label loaded");

    CCSprite* buttonSprite = CCSprite::createWithSpriteFrameName(s_Button);
    buttonSprite->setScale(Constants::scale);
    buttonSprite->retain();
    CCSprite* buttonPressedSprite = CCSprite::createWithSpriteFrameName(s_ButtonPressed);
    buttonPressedSprite->setScale(Constants::scale);
    buttonPressedSprite->retain();
    if(DEBUG) CCLog("Pause buttons loaded");

    CCMenuItemSprite* menuButtonResume = CCMenuItemSprite::create(buttonSprite, buttonPressedSprite, this, menu_selector(PauseLayer::onResumeSelected));
    menuButtonResume->setPosition(background->getPosition());
    menuButtonResume->retain();

    resumeLabel = CCLabelTTF::create(LanguageClass::sharedLanguageClass()->getStringFromKey("resume"), s_FontPath, 30 * Constants::scale);
    resumeLabel->setPosition(menuButtonResume->getPosition());
    resumeLabel->retain();
    if(DEBUG) CCLog("Pause resume label loaded");

    CCMenuItemSprite* menuButtonQuit = CCMenuItemSprite::create(buttonSprite, buttonPressedSprite, this, menu_selector(PauseLayer::onQuitSelected));
    menuButtonQuit->setPosition(ccp(menuButtonResume->getPositionX(), menuButtonResume->getPositionY() * 0.6));
    menuButtonQuit->retain();

    quitLabel = CCLabelTTF::create(LanguageClass::sharedLanguageClass()->getStringFromKey("quitMenu"), s_FontPath, 30 * Constants::scale);
    quitLabel->setPosition(menuButtonQuit->getPosition());
    quitLabel->retain();
    if(DEBUG) CCLog("Pause quit Label loaded");

    pauseMenu = CCMenu::create(menuButtonResume, menuButtonQuit, NULL);
    pauseMenu->setPosition(CCPointZero);
    pauseMenu->retain();
    if(DEBUG) CCLog("Pause Menu loaded");

    addChild(background);
    addChild(pauseTitleLabel);
    addChild(pauseMenu);
    addChild(resumeLabel);
    addChild(quitLabel);
    if(DEBUG) CCLog("Pause Layer loaded");
}

PauseLayer::~PauseLayer() {
    CCLayer::release();
    CC_SAFE_RELEASE(background);
    CC_SAFE_RELEASE(pauseMenu);
    CC_SAFE_RELEASE(pauseTitleLabel);
    CC_SAFE_RELEASE(resumeLabel);
    CC_SAFE_RELEASE(quitLabel);
}

void PauseLayer::setResumeCallback(CCObject * target, SEL_CallFunc callfunc) {
    targetResume = target;
    resumeCallback = callfunc;
}

void PauseLayer::setQuitCallback(CCObject * target, SEL_CallFunc callfunc) {
    targetQuit = target;
    quitCallback = callfunc;
}

void PauseLayer::onResumeSelected(CCObject* pSender) {
    if (targetResume && resumeCallback) {
            (targetResume->*resumeCallback)();
        };
}

void PauseLayer::onQuitSelected(CCObject* pSender) {
    if (targetQuit && quitCallback) {
            (targetQuit->*quitCallback)();
        };
}

ArcadeModeScene.cpp

void ArcadeModeScene::onEnter() {
    CCScene::onEnter();

    grid = new GridClass();
    pLayer = new PaintingLayer(grid);
    pLayer->setOnTouchEndCallback(this, callfunc_selector(ArcadeModeScene::checkAccuracy));

    RuneList::sharedRuneList()->copyRuneList("Alphabetical", runes);

    //CCSize winSize = CCDirector::sharedDirector()->getWinSize();
    // Background Layer - BG and Particles
    bgLayer = new BackgroundLayer();//CCLayer::create();
    addChild(bgLayer);
    if(DEBUG) CCLog("BG Layer loaded");
    // UI Layer - Rune Stone and UI info
    uiLayer = new UILayer();//CCLayer::create();
    addChild(uiLayer);
    if(DEBUG) CCLog("UI Layer loaded");
    // Rune Layer
    //runeLayer = new RuneLayer();
    runeLayer = CCLayer::create();
    addChild(runeLayer);
    if(DEBUG) CCLog("Rune Layer loaded");
    addChild(pLayer);

    /*
    if(DEBUG) {
        debugLayer = new DebugLayer(this);
        addChild(debugLayer);

        CCLog("Debug Layer loaded");
    }
    */

    pauseLayer = new PauseLayer();
    //addChild(pauseLayer);
    pauseLayer->setResumeCallback(this, callfunc_selector(ArcadeModeScene::onResume));
    pauseLayer->setQuitCallback(this, callfunc_selector(ArcadeModeScene::onQuitToMenu));
    //pauseLayer->pauseMenu->setEnabled(false);
    //pauseLayer->setVisible(false);
    if(DEBUG) CCLog("Pause Layer loaded");

    sprintf(countdownString, "3");
    countdownLabel = CCLabelTTF::create(countdownString, s_FontPath, 60 * Constants::scale);
    countdownLabel->setPosition(ccp(Constants::winSize.width / 2, Constants::winSize.height / 2));
    startSprite = CCSprite::createWithSpriteFrameName(s_StartSprite);
    startSprite->setScale(Constants::scale);
    startSprite->setPosition(ccp(Constants::winSize.width / 2, Constants::winSize.height / 2));
    startSprite->setTag(10);
    startSprite->setVisible(false);
    currentTimer = 0;
    countdown = 3;
    addChild(countdownLabel);
    addChild(startSprite);
    scheduleUpdate();
}

void ArcadeModeScene::onEndGame() {
    if(DEBUG) CCLog("Game Over!");
    unscheduleUpdate();
    //runeLayer->removeAllChildren();
    pLayer->clear();
    grid->clearGrid();
}

void ArcadeModeScene::onPausePressed(cocos2d::CCObject* pSender) {
    if(DEBUG) CCLog("Paused");
    unscheduleUpdate();
    addChild(pauseLayer);
    //CCDirector::sharedDirector()->pause();
}

void ArcadeModeScene::onResume() {
    removeChild(pauseLayer);
    //CCDirector::sharedDirector()->resume();
    scheduleUpdate();
}

void ArcadeModeScene::onQuitToMenu() {
//Test
    CCDirector::sharedDirector()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
}

I really can’t find what’s wrong…
I also want to note that somehow my *unscheduleUpdate()* is not working…

Thanks in advance to anyone willing to help me :slight_smile:


#2

Try using PauseLayer::create* instead ofnew PauseLayer(). You must addLAYER_CREATE_FUNC( PauseLayer )* or CREATE_FUNC* on your public methods in the header file forcreate()* to work.

Also, instead of adding it when you pause the game, create it instead

void ArcadeModeScene::onPausePressed(cocos2d::CCObject* pSender) {
   if ( DEBUG ) CCLog( "Paused" );

   PauseLayer * pauseLayer = PauseLayer::create();
   pauseLayer -> setPosition( CCPointZero );
   this -> addChild( pauseLayer, 100, 10 );

   this -> unscheduleUpdate();
}

#3

I found the problem. It was in my Destructor implementation. I’ll read more about memory management in Cocos2d-X… as I’m coming from GC enabled languages as Java and C#, I need to learn how to properly use the memory with cocos and C++ :X
(I just removed the PauseLayer::~PauseLayer() destructor and now it’s working…)


#4

Cocos2d-x has its own Garbage Collection system, called the Auto-release Pool. Usually, when you use create* the objects are set to automatically get released when no references exist anymore. But when you usenew MyClass(), you have to manuallydelete* it somewhere since C++ does not automatically destroy pointers when they aren’t used anymore.

So basically, the rule of thumb is:

  • If you use retain, you mustrelease* somewhere else. Or you could useautorelease()*
  • If you use new, you must delete somewhere else.

#5

Thanks Lance, I was really confused about when to use new or retain/*autorelease* that I was allocating withnew but trying to deallocate with release heh
Now, there’s some code that needs to be cleaned hehehehe


#6

You dont need to change all relese() to delete. You can use release() to deallocate a CCObject allocated with new.