2
votes

How do I restart cocos2d scene and clean memory after the previous one?

[director replaceScene:s] is displaying pink screen. Can't get it to work.

The work-around I made is below, however after closing scene this way app runs very slow and slowly reacts to touch. MainViewController.m:

- (IBAction)startScene { 

[CCTexture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGBA8888];

if ([director runningScene]) {
    [director end];
    works = NO;
}
if (!works) {
    EAGLView *glview = [EAGLView viewWithFrame:CGRectMake(0,0, 768, 1024)]; 
    [self.view addSubview:glview];
    [director setOpenGLView:glview];
    CCLayer *layer = [PlayLayer node];
    CCScene *s = [CCScene node];
    [s addChild: layer];
    [director runWithScene:s];
}

}

Inside PlayLayer.m I go back from scene to view using:

CCDirector *d = [CCDirector sharedDirector];
EAGLView *v = [d openGLView];
[v removeFromSuperview];

Application is displaying images (1280x960x32, imageview inside scrollview) and when user presses the button he can start cocos2d scene. User can then leave from scene back to view (.xib) and continue browsing through images till he finds a new one to start scene with.

I believe this is not a good way to leave scene but everything else I tried is causing app to crash or I keep getting this pink screen 2nd time I start scene. How do I restart it ?

3

3 Answers

2
votes

I finally could get rid of pink screen while replacing scene. This is how I am doing it. While adding scene, I check if it's running first time or subsequent times.

MyTestAppDelegate * appDelegate = (MyTestAppDelegate *)[[UIApplication sharedApplication] delegate];
EAGLView *glView;
//check if scene is running first time then create OpenGLView, add to director and run the scene
if ([[CCDirector sharedDirector] runningScene] == NULL) {
    if( ! [CCDirector setDirectorType:kCCDirectorTypeDisplayLink] )
        [CCDirector setDirectorType:kCCDirectorTypeDefault];

    CCDirector *director = [CCDirector sharedDirector];
    glView = [EAGLView viewWithFrame:[appDelegate.window bounds]
                                   pixelFormat:kEAGLColorFormatRGB565   // kEAGLColorFormatRGBA8
                                   depthFormat:0                        // GL_DEPTH_COMPONENT16_OES
                        ];  
    [director setOpenGLView:glView];        
    [director setDeviceOrientation:kCCDeviceOrientationPortrait];   
    [director setAnimationInterval:1.0/60];
    [director setDisplayFPS:YES];
    [appDelegate.window addSubview:glView];     

    [[CCDirector sharedDirector] runWithScene: [MyScene node]];
}
//if scene is to be reloaded, add back the openGLView which was removed when removing the scene
else {      
    [appDelegate.window addSubview:[[CCDirector sharedDirector] openGLView]];
    [[CCDirector sharedDirector] replaceScene:[MyScene node]];
}

For removing currently running scene:

[[CCDirector sharedDirector] replaceScene:[MySceneTwoLayer scene]];
[[CCDirector sharedDirector].openGLView removeFromSuperview];

Adding MySceneTwoLayer is optional. It is an empty scene. I am using it to make sure previous scene was properly removed. And I checked, previous scene's dealloc is properly called.

I hope it helps.

1
votes

I came across a simliar problem when using Storyboards and when returning to m original UI view which contained my CCGLView from another view.

//when leaving the scene containing the CCGLView.
[CCDirector director] popScene];

then I noticed in viewDIdLoad for that viewcontroller, it would go through this when reinstantiated bt the segue, where you can re add the scene again.

// in viewDidLoad
[CCDirector director] pushScene: theSceneIRemovedEtc];

Admititedly this mightnot work for all cases but certainly did for me..

0
votes

Ok, found a solution that closes the scene from inside and works well.

While starting scene I add the notification observer in my viewcontroller:

(...)
[director runWithScene:s];
[[NSNotificationCenter defaultCenter] addObserver:self 
      selector:@selector(mySceneEnd:) name:@"scene_ended" object:nil];

That is connected to:

- (void) mySceneEnd:(NSNotification *)notif {   
    if ([director runningScene])
        [director end];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

Then in the scene ending method I'm sending the notification to my viewcontroller:

EAGLView *v = [[CCDirector sharedDirector] openGLView];
[v removeFromSuperview];
[[NSNotificationCenter defaultCenter] postNotificationName:@"scene_ended" 
     object:nil userInfo:nil];

Works really nice, app runs fast after closing scene, but it's an old question/answer and there is surely a better way to do it now.