addChild on the fly, something wrong?

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:

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();
}

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

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.

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

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