Authman Apatira
Authman Apatira

Reputation: 4054

cocos2d remove scene / scene transitions

I started my app using the base code found here in the menus tutorial. In this manner, all of my 'screens' (there are only 5 of them) are implemented as extensions of the CCLayer class, and I have a shared + Scene Manager which works by adding my layer classes as children to a new scene and then using the director to run or replace the currently playing scene:

+(void) goMenu{
    // \/---------- Issue right here, next line:
    CCLayer *layer = [MenuLayer node];
    [SceneManager go: layer];
}

+(void) go: (CCLayer *) layer{
    CCDirector *director = [CCDirector sharedDirector];
    CCScene *newScene = [SceneManager wrap:layer];
    if ([director runningScene]) {
        [director replaceScene: newScene];
    }else {
        [director runWithScene:newScene];
    }
}

+(CCScene *) wrap: (CCLayer *) layer{
    CCScene *newScene = [CCScene node];
    [newScene addChild: layer];
    return newScene;
}

The problem I am having is as follows. Let's say I have 2 layers -- 'MenuLayer' and 'GameLayer'. I start off with MenuLayer and later on use [SceneManager go:[GameLayer node]] to transition over to GameLayer. From GameLayer, if I goMenu the app terminates with an 'NSInternalInconsistencyException', reason: 'child already added. It can't be added again' where indicated. I assumed that this is happening because I am trying to add some child sprites in the layer's init code and I am re-adding them again.

My first attempt at debugging was to call [self removeAllChildrenWithCleanup:YES]; within the onExit code of all my layers. That didn't solve the issue. I added in some debugging logs and found out the last line that executes before the script blows up is the indicated one [myLayerClass node];. The init code inside the layer class does not get executed at all -- so it can't be one of the sprites or other children being added that is causing the issue. Again -- remember that everything works the first time I try to open any scene. It's moving back to an opened scene that is currently problematic.

So I tried a different approach -- the approach used in Cocos2D Hello world. I modified all my Layer Classes by adding a singleton +(id) scene method defined as follows:

+(id) scene
{
    CCScene *scene = [CCScene node];    
    myLayerClass *layer = [myLayerClass node];
    [scene addChild: layer];
    return scene;
}

Added in a [super dealloc] in the dealloc, and encapsulated all my init code within:

-(id) init
{
    if( (self=[super init] )) {
        // All init code here....
    }
}

Of course, all of the goLayerName singleton methods in the scene manager had their contents replaced to match this -- for example:

+(void) goMenu {
    //CCLayer *layer = [MenuLayer node];
    //[SceneManager go: layerMenu];
    CCDirector *director = [CCDirector sharedDirector];
    if ([director runningScene])
        [director replaceScene:[MenuLayer scene]];
    else 
        [director runWithScene:[MenuLayer scene]];
}

I figured this was the way Cocos2D's hello world worked, it must be good. Also, since each of my scenes would be created once and once alone (and thus every layer would be created once and once alone). No effect whatsoever! The first time I visit any scene it runs as expected. Whenever I try to navigate back to any existing scene, I get the error I mentioned above.

I tried poking around SO and found this, but I am unsure how to properly implement it; also I'm not entirely sure that would even solve the issue -- since the symptoms are different (he just gets a pink screen, whereas my app terminates).

Any assistance would be appreciated.

Upvotes: 1

Views: 4086

Answers (1)

Authman Apatira
Authman Apatira

Reputation: 4054

For anyone who was interested in this question, I was able to resolve the issue.

In summary, any child of a child you add, will not be released with releaseAllChildrenWithClenup. That function will only release the immediate children, so you are responsible to release any nested children yourself.

In my game, I had some characters and their eyes were nested in the head sprites (so that I could just move / rotate the heads). The eyes had their own animation loop but I wanted them to transform with the head. All that worked, but since I had a line of code in init which basically [headSprite addChild:eyeSprite];, I had to also add [headSprite removeChild:eyeSprite]; in the onExit code to dissociate it, followed by releaseAllChildrenWithClenup to remove all of the n=1 level children as well.

Once that was handled, everything worked as advertised.

Upvotes: 1

Related Questions