本文主要分两个部分叙述,第一是场景切换,第二是场景切换的进度显示。
一、场景切换
参考learn-iphone-and-ipad-cocos2d-game-development 第五章内容
cocos2d可以使用CCDirector replaceScene替换场景。切换场景时节点会调用CCNode的三个方法
onEnter //节点调用init方法后调用此方法(使用了CCTransitionScene的话,将在过渡效果后调用此方法)
onEnterTransitionDidFinish //调用onEnter后调用此方法(使用了CCTransitionScene,将在过渡效果后调用此方法
onExit//节点调用dealloc方法前调用此方法(使用CCTransitionScene,将在过渡效果结束后调用此方法)
对于两个Scene,scene1和scene2
调用次序为
1.scene:scene2
2.init scene2
3.onEnter scene2
4.过渡效果
5.onExit scene1
6.onEnterTransitionDidFinish scene2
7.dealloc scene1
由此可见scene1在scene加载完后调用dealloc,这意味着scene1的内存会一直保存到scene2生成完。
当场景使用的内存较多的时候,切换就需要谨慎起来了。
解决方法:
1、scene2的onEnterTransitionDidFinish里面schedule一个方法,在update里面分配内存,这样的话就会在下一帧或者更后的时候分配内存,此时scene1的内存已经释放了。
2、scene1的onExit里面释放尽量多的内存
3、使用中间场景
4、等等
中间场景使用方法:
scene1切换到loadingScene,loadingScene 在init的时候schedule一个方法,在update方法里面切换到scene2
1 #import <Foundation/Foundation.h> 2 #import "cocos2d.h" 3 4 typedef enum 5 { 6 TargetSceneINVALID = 0, 7 TargetSceneScene1, 8 TargetSceneScene2, 9 TargetSceneMAX, 10 } TargetScenes; 11 12 @interface LoadingScene : CCLayer 13 { 14 TargetScenes targetScene_; 15 } 16 17 +(id) sceneWithTargetScene:(TargetScenes)targetScene; 18 -(id) initWithTargetScene:(TargetScenes)targetScene; 19 20 @end
1 #import "LoadingScene.h" 2 #import "Scene1.h" 3 #import "Scene2.h" 4 5 6 @interface LoadingScene (PrivateMethods) 7 -(void) update:(ccTime)delta; 8 @end 9 10 @implementation LoadingScene{ 11 12 } 13 14 +(id) sceneWithTargetScene:(TargetScenes)targetScene; 15 { 16 CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self); 17 18 return [[[self alloc] initWithTargetScene:targetScene] autorelease]; 19 //或者这样 20 //return [[[LoadingScene alloc] initWithTargetScene:targetScene] autorelease]; 21 } 22 23 -(id) initWithTargetScene:(TargetScenes)targetScene 24 { 25 if ((self = [super init])) 26 { 27 targetScene_ = targetScene; 28 29 CCLabelTTF* label = [CCLabelTTF labelWithString:@"Loading ..." fontName:@"Marker Felt" fontSize:64]; 30 CGSize screenSize = [[CCDirector sharedDirector] winSize]; 31 label.position = CGPointMake(screenSize.width / 2, screenSize.height / 2); 32 [self addChild:label]; 33 //在加载目标场景前至少等1帧 34 //因为:1、直接加载会崩溃 2、精灵(也就是label)不是显示 35 [self scheduleUpdate]; 36 } 37 return self; 38 } 39 40 -(void) update:(ccTime)delta 41 { 42 43 // 因为要切换场景,所以这里不是必要的。这样做是以防万一。 44 [self unschedule:_cmd]; 45 46 // 根据需求加载目标场景,这样就代码可以用在多种情况下了 47 switch (targetScene_) 48 { 49 case TargetSceneMainScene: 50 [[CCDirector sharedDirector] replaceScene:[Scene1 scene]]; 51 break; 52 case TargetSceneExamScene: 53 [[CCDirector sharedDirector] replaceScene:[Scene2 scene]]; 54 break; 55 56 default: 57 // 如果使用了不恰当的数值,这会警告你 58 NSAssert2(nil, @"%@: unsupported TargetScene %i", NSStringFromSelector(_cmd), targetScene_); 59 break; 60 } 61 62 // Tip: example usage of the INVALID and MAX enum values to iterate over all enum values 63 for (TargetScenes i = TargetSceneINVALID + 1; i < TargetSceneMAX; i++) 64 { 65 } 66 67 } 68 69 -(void) dealloc 70 { 71 CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self); 72 // don't forget to call "super dealloc" 73 [super dealloc]; 74 } 75 76 @end
1 #import "Scene1.h" 2 #import "LoadingScene.h" 3 4 5 @implementation Scene1 6 7 +(id)scene{ 8 CCScene *scene = [CCScene node]; 9 Scene1*layer = [Scene1 node]; 10 [scene addChild:layer]; 11 return scene; 12 } 13 14 -(id)init{ 15 if ((self = [super init])) { 16 CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self); 17 18 CGSize size = [[CCDirector sharedDirector] winSize]; 19 20 CCLabelTTF *titlelabel = [CCLabelTTF labelWithString:@"游戏" fontName:@"Heiti SC" fontSize:30]; 21 titlelabel.color = ccBLUE; 22 23 titlelabel.position = CGPointMake(size.width * 0.5f, size.height * 0.7f); 24 [self addChild:titlelabel]; 25 CCLabelTTF *label = [CCLabelTTF labelWithString:@"点击开始游戏" fontName:@"Heiti SC" fontSize:20]; 26 label.color = ccYELLOW; 27 label.position = CGPointMake(size.width * 0.5f, size.height * 0.4f); 28 [self addChild:label]; 29 [self setTouchEnabled:YES]; 30 } 31 return self; 32 }
二、进度显示(针对中间场景)
有了中间场景的方法了,那么直接把进度条加到中间场景里面就ok了么。
但是如果仔细观察切换场景的过程,会发现loadingScene的帧率是不动的,这意味着在切换场景的过程中loadingScene是不刷新的。无论你如何修改进度条的百分比,loadingScene还是保持在切换scene2前的状态,直到进入scene2而loadingScene释放。
待续