【Cocos2d-X】场景切换的小小研究

来源:互联网 发布:制衣打菲软件 编辑:程序博客网 时间:2024/05/16 15:57

 七十一雾央原创 转载请注明 http://blog.csdn.net/hust_xy      

 新浪微博:http://weibo.com/1689160943



        学Cocos2d-X快三个月了,在看了点API的用法后,就一直试着写自己的游戏玩。一直只知道怎么用,但是很多地方都不是太明白,出了问题也不太清楚。写游戏的时候遇到一个BUG,一直没搞清楚原因,但是可以解决,今天自己试验了下,算是清楚了一点。

       看场景切换的代码可以知道过程大概是这样:场景A切换场景B,则场景B在init之后,执行切换效果(如果有),再释放A。也就是说在切换的一段时间内,场景A和场景B是同时存在的。

       写游戏的时候自己考虑场景A和B同时存在可能占用内存过多,就在有些地方加入了过渡场景,比如游戏关卡的重新开始。但是在“游戏关卡—过渡场景—游戏关卡”的切换时候出现了问题。我设定的是过渡场景init中定时器一定时间后自动切换场景,但是发现最后一直停在过渡场景,无法跳到游戏关卡去。

        在不太理解的情况下,偶然发现把过渡场景中延时切换的时间调长一点就正常了,由于急着做出游戏,一是当课设交了,二是投了一个比赛,就先放下了。

        在九月份忙着写自己的游戏,十月份做了一个月的文档狂魔后,终于空闲了,就自己写几个场景,试验了一下场景切换,也纠正了一下以前的一些误解。

        先建两个场景,游戏场景HelloWorld,过渡场景C_TollgateLoading。

        游戏场景HelloWorld就是一个按钮,点击切换到过渡场景。

bool HelloWorld::init(){    if (!CCLayer::init() )    {        return false;    }       CCSprite *pSprite = CCSprite::create("HelloWorld.png");    pSprite->setPosition(ccp(240,160));    this->addChild(pSprite,0);     CCMenuItemImage*pBtn=CCMenuItemImage::create("CloseNormal.png","CloseSelected.png",this,menu_selector(HelloWorld::menuCloseCallback));    CCMenu *pMenu=CCMenu::create(pBtn,NULL);    pMenu->setPosition(ccp(100,40));    this->addChild(pMenu,1);     return true;} void HelloWorld::menuCloseCallback(CCObject* pSender){    CCScene *pScene =C_TollgateLoading::scene();    CCDirector::sharedDirector()->replaceScene(CCTransitionFade::create(0.5f,pScene));}

        过渡场景C_TollgateLoading就是间隔一段时间后回到游戏场景

bool C_TollgateLoading::init(){       CCSprite *pLoadBg=CCSprite::create("CloseNormal.png");    pLoadBg->setPosition(ccp(0,100));    this->addChild(pLoadBg,0);     pLoadBg->runAction(CCRepeatForever::create(CCMoveBy::create(0.3f,ccp(20,0))));     this->scheduleOnce(schedule_selector(C_TollgateLoading::tollgateStart),0.8f);     return true;} void C_TollgateLoading::tollgateStart(float dt){    CCScene *pScene = HelloWorld::scene();    CCDirector::sharedDirector()->replaceScene(CCTransitionFade::create(0.5f,pScene));}

       上面这两段代码运行是没什么问题的。但是当在下面这个函数中    

     bool C_TollgateLoading::init()

        定时器时间从0.8f改为0.4f之后发现就出问题了,在游戏场景HelloWorld按下按钮切换场景的时候会跳到过渡场景,然后会切换会游戏场景,但是最终又会回过渡场景,游戏显示的就始终是过渡场景了。

 

        当时这个问题没想清楚和我对场景切换的误解有很大的关系。刚学cocos2d-x的时候,我自己的想的是场景切换的过程是这样的:假如有两个场景即游戏场景A和过渡场景B,A要切换到B,那么B在初始化init之后,两个场景A和B都处于暂停状态或者A已经被释放(场景A仅仅是一张截图),然后显示切换动画,在切换动画完毕之后,B开始执行。我这样想的原因是切换过程加入特效主要是看效果,那么就没必要运行场景。

        在上面的误解下,上面的问题我就有点想不通了。游戏场景A1切换到过渡场景B,B又切换到游戏场景A2,A1切换到B的时候B是暂停的,在切换动画完后B继续执行,才会切换A2,和定时器时间怎么会有关系?

 

       下午测试了才发现自己惯有的认识是错误的。在场景切换动画进行的时候,两个场景都在运行!

       在HelloWorld切换场景前加一个定时器,打印日志,在C_TollgateLoading场景中也加一个定时器打印,同时把切换效果时间变长一点到5秒,如下:

        HelloWorld:

void HelloWorld::menuCloseCallback(CCObject* pSender){    this->schedule(schedule_selector(HelloWorld::print_log),0.5f);    CCScene *pScene =C_TollgateLoading::scene();    CCDirector::sharedDirector()->replaceScene(CCTransitionFade::create(5.0f,pScene));}void HelloWorld::print_log(floatdt){    CCLOG("HelloWorld");}

        TollgateLoading:

bool C_TollgateLoading::init(){       CCSprite *pLoadBg=CCSprite::create("CloseNormal.png");    pLoadBg->setPosition(ccp(0,100));    this->addChild(pLoadBg,0);     pLoadBg->runAction(CCRepeatForever::create(CCMoveBy::create(0.3f,ccp(20,0))));     //this->scheduleOnce(schedule_selector(C_TollgateLoading::tollgateStart),0.8f);     this->schedule(schedule_selector(C_TollgateLoading::print_log),0.5f);     return true;} void C_TollgateLoading::print_log(float dt){    CCLog("TollgateLoading");}void C_TollgateLoading::tollgateStart(float dt){    CCScene *pScene = HelloWorld::scene();    CCDirector::sharedDirector()->replaceScene(CCTransitionFade::create(0.5f,pScene));}

      输出的结果如下面这样:

       

       程序中看到场景在慢慢变暗的切换效果中时,控制台不断交替打印HelloWorld和TollgateLoading,也就是说两个场景都在运行,切换效果结束时,就只打印TollgateLoading了,只有一个场景运行了。

       这样在切换效果进行的时候,同时有两个场景在运行,在切换场景的时候最好停止掉上一个场景的定时器,否则可能会带来一些问题。比如游戏里面需要每秒加10块钱,如果不停止定时器,那么在切换的时候就是每秒加20块了,当然对这个例子的影响不是太重要。另外切换的时间要较短,不然切换的时候,目标场景已经执行一会了。


       现在就可以试着解释一下停留在过渡场景的原因了。

       有场景A1切换到场景B,切换效果时间t1

       场景B定时器延时t2切换到场景A2,切换效果时间t3。

       若t1>t2,则在切换的时间t1内,A1和B都在运行,B运行完t2,执行切换A2的切换效果。

       即由于t1>t2,导致同时存在两个场景切换效果。A1到B的,B到A2的。

       试验发现,无论t3是多少,都不会对结果有任何影响。也就是无论两个切换效果谁先结束,最后执行的一次切换都是A1到B,即先开始的那个切换效果。

       另外发现如果B切换A2不带切换效果,直接切换的话,那么执行的将是B到A2。

       即在同时存在两个切换场景时,导演遵守的规则似乎是:若两个切换都带效果,切第一个;若第二个为直接切换,切第二个。

 

       当然我觉得应该避免出现同时存在两个切换效果的情况,即保证t1<t2即可,我甚至觉得这个应该算未定义的情况,价值也不是太大的样子。另外,同时存在两个切换效果的时候控制台会打印出

        cocos2d: removeChildByTag(tag = -86050082): childnot found!   

       移除了不存在的结点,这个我也还不知道什么情况。


       现在没有看源码,因为目前水平不是太够,看一大堆代码感觉很头疼,上面的仅为一些试验和猜测,不知道导演真实是怎么切换场景的,希望以后有能力的时候可以看懂到底真正发生了什么,如果有研究过的朋友请留言告知,感谢。

原创粉丝点击