[cocos2d]场景切换以及切换进度显示

时间:2022-07-10 17:21:00

本文主要分两个部分叙述,第一是场景切换,第二是场景切换的进度显示。

一、场景切换

参考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

 #import <Foundation/Foundation.h>
#import "cocos2d.h" typedef enum
{
TargetSceneINVALID = ,
TargetSceneScene1,
TargetSceneScene2,
TargetSceneMAX,
} TargetScenes; @interface LoadingScene : CCLayer
{
TargetScenes targetScene_;
} +(id) sceneWithTargetScene:(TargetScenes)targetScene;
-(id) initWithTargetScene:(TargetScenes)targetScene; @end

LoadingScene.h

 #import "LoadingScene.h"
#import "Scene1.h"
#import "Scene2.h" @interface LoadingScene (PrivateMethods)
-(void) update:(ccTime)delta;
@end @implementation LoadingScene{ } +(id) sceneWithTargetScene:(TargetScenes)targetScene;
{
CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self); return [[[self alloc] initWithTargetScene:targetScene] autorelease];
//或者这样
//return [[[LoadingScene alloc] initWithTargetScene:targetScene] autorelease];
} -(id) initWithTargetScene:(TargetScenes)targetScene
{
if ((self = [super init]))
{
targetScene_ = targetScene; CCLabelTTF* label = [CCLabelTTF labelWithString:@"Loading ..." fontName:@"Marker Felt" fontSize:];
CGSize screenSize = [[CCDirector sharedDirector] winSize];
label.position = CGPointMake(screenSize.width / , screenSize.height / );
[self addChild:label];
//在加载目标场景前至少等1帧
//因为:1、直接加载会崩溃 2、精灵(也就是label)不是显示
[self scheduleUpdate];
}
return self;
} -(void) update:(ccTime)delta
{ // 因为要切换场景,所以这里不是必要的。这样做是以防万一。
[self unschedule:_cmd]; // 根据需求加载目标场景,这样就代码可以用在多种情况下了
switch (targetScene_)
{
case TargetSceneMainScene:
[[CCDirector sharedDirector] replaceScene:[Scene1 scene]];
break;
case TargetSceneExamScene:
[[CCDirector sharedDirector] replaceScene:[Scene2 scene]];
break; default:
// 如果使用了不恰当的数值,这会警告你
NSAssert2(nil, @"%@: unsupported TargetScene %i", NSStringFromSelector(_cmd), targetScene_);
break;
} // Tip: example usage of the INVALID and MAX enum values to iterate over all enum values
for (TargetScenes i = TargetSceneINVALID + ; i < TargetSceneMAX; i++)
{
} } -(void) dealloc
{
CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self);
// don't forget to call "super dealloc"
[super dealloc];
} @end

LoadingScene.m

 #import "Scene1.h"
#import "LoadingScene.h" @implementation Scene1 +(id)scene{
CCScene *scene = [CCScene node];
Scene1*layer = [Scene1 node];
[scene addChild:layer];
return scene;
} -(id)init{
if ((self = [super init])) {
CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self); CGSize size = [[CCDirector sharedDirector] winSize]; CCLabelTTF *titlelabel = [CCLabelTTF labelWithString:@"游戏" fontName:@"Heiti SC" fontSize:];
titlelabel.color = ccBLUE; titlelabel.position = CGPointMake(size.width * 0.5f, size.height * 0.7f);
[self addChild:titlelabel];
CCLabelTTF *label = [CCLabelTTF labelWithString:@"点击开始游戏" fontName:@"Heiti SC" fontSize:];
label.color = ccYELLOW;
label.position = CGPointMake(size.width * 0.5f, size.height * 0.4f);
[self addChild:label];
[self setTouchEnabled:YES];
}
return self;
}

Scene1.m

二、进度显示(针对中间场景)

有了中间场景的方法了,那么直接把进度条加到中间场景里面就ok了么。

但是如果仔细观察切换场景的过程,会发现loadingScene的帧率是不动的,这意味着在切换场景的过程中loadingScene是不刷新的。无论你如何修改进度条的百分比,loadingScene还是保持在切换scene2前的状态,直到进入scene2而loadingScene释放。

待续