当前位置: 首页 > news >正文

【2014-01-27】cocos2dx学习笔记:CCNode回调流程

[历史归档]本文原发布于 cstriker1407.info 个人博客,内容为历史存档,仅供参考。
发布时间:2014-01-27| 标题:cocos2dx学习笔记:CCNode回调流程分类:编程 / C && C++ / cocos2dx |标签:cocos2dx


cocos2dx学习笔记:CCNode回调流程

    • CCNode的回调流程
      • CCNode的几个回调函数:
      • cocos2dx程序框架流程:
        • 首先进入main.cpp函数,可以发现程序调用了Appliaction的run方法:
        • 然后查看run方法,是一个while(1)循环,调用了Director的mainloop方法:
        • 查看mainLoop方法,发现其调用了drawScene方法:
        • 查看drawScene方法:
      • 没有场景切换动画时的回调流程:
        • void CCDirector::setNextScene(void):
      • 有场景切换动画时的回调流程:
        • 从场景A切换到场景X:
        • CCTransitionScene和CCTransitionShrinkGrow片段:
        • 由场景X切换场景B:

最近项目中用到了cocos2dx来开发一个基于陀螺仪的demo,忙了半个星期,一边学习一边开发,总算搞了出来。这里备份下开发中学习到的一些cocos2dx知识。

CCNode的回调流程

在使用CCLayer,CCScene的时候往往想在layer或者场景切换的时候处理一些资源类的东西,于是就在CCNode里发现了一些回调函数,但是这些回调函数如何调用,作者在网上也没有搜索,自己翻了下源码,发现比较简单。在这里备份下。

CCNode的几个回调函数:

classCC_DLLCCNode:publicCCObject{public:。。。。。 。。。。。virtualboolinit();staticCCNode*create(void);/** * Event callback that is invoked every time when CCNode enters the 'stage'. * If the CCNode enters the 'stage' with a transition, this event is called when the transition starts. * During onEnter you can't access a "sister/brother" node. * If you override onEnter, you shall call its parent's one, e.g., CCNode::onEnter(). * @js NA * @lua NA */virtualvoidonEnter();/** Event callback that is invoked when the CCNode enters in the 'stage'. * If the CCNode enters the 'stage' with a transition, this event is called when the transition finishes. * If you override onEnterTransitionDidFinish, you shall call its parent's one, e.g. CCNode::onEnterTransitionDidFinish() * @js NA * @lua NA */virtualvoidonEnterTransitionDidFinish();/** * Event callback that is invoked every time the CCNode leaves the 'stage'. * If the CCNode leaves the 'stage' with a transition, this event is called when the transition finishes. * During onExit you can't access a sibling node. * If you override onExit, you shall call its parent's one, e.g., CCNode::onExit(). * @js NA * @lua NA */virtualvoidonExit();/** * Event callback that is called every time the CCNode leaves the 'stage'. * If the CCNode leaves the 'stage' with a transition, this callback is called when the transition starts. * @js NA * @lua NA */virtualvoidonExitTransitionDidStart();/// @} end of event callbacks./** * Stops all running actions and schedulers */virtualvoidcleanup(void);。。。。。 。。。。。};

cocos2dx程序框架流程:

首先进入main.cpp函数,可以发现程序调用了Appliaction的run方法:
intAPIENTRY_tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,intnCmdShow){。。。。。 。。。。。returnCCApplication::sharedApplication()->run();}
然后查看run方法,是一个while(1)循环,调用了Director的mainloop方法:
intCCApplication::run(){。。。。。 。。。。。while(1){。。。。。CCDirector::sharedDirector()->mainLoop();。。。。。}。。。。。}
查看mainLoop方法,发现其调用了drawScene方法:
voidCCDisplayLinkDirector::mainLoop(void){。。。。。 。。。。。drawScene();。。。。。}
查看drawScene方法:
voidCCDirector::drawScene(void){。。。。。 。。。。。if(m_pNextScene){setNextScene();}。。。。。if(m_pRunningScene){m_pRunningScene->visit();}。。。。。}

查看代码到这里,就可以大致的知道cocos2dx程序的运行流程,通过不停的循环,来执行当前scene的visit方法绘制界面,如果有场景切换,就切换场景后继续visiit。这里作者不关心visit和draw方法,只关注于CCNode的回调流程。

没有场景切换动画时的回调流程:

void CCDirector::setNextScene(void):
voidCCDirector::setNextScene(void){boolrunningIsTransition=dynamic_cast<CCTransitionScene*>(m_pRunningScene)!=NULL;boolnewIsTransition=dynamic_cast<CCTransitionScene*>(m_pNextScene)!=NULL;// If it is not a transition, call onExit/cleanupif(!newIsTransition){if(m_pRunningScene){m_pRunningScene->onExitTransitionDidStart();m_pRunningScene->onExit();}// issue #709. the root node (scene) should receive the cleanup message too// otherwise it might be leaked.if(m_bSendCleanupToScene&&m_pRunningScene){m_pRunningScene->cleanup();}}if(m_pRunningScene){m_pRunningScene->release();}m_pRunningScene=m_pNextScene;m_pNextScene->retain();m_pNextScene=NULL;if((!runningIsTransition)&&m_pRunningScene){m_pRunningScene->onEnter();m_pRunningScene->onEnterTransitionDidFinish();}}

通过查看setNextScene的方法,就可以发现在没有场景切换动画时,各个回调函数的调用流程很清楚了。

首先调用要退出场景的 onExitTransitionDidStart 方法和 onExit 方法,如果当前是切换场景不是push场景,就继续调用cleanup方法,最后在执行新场景的 onEnter 和 onEnterTransitionDidFinish 方法。

我们查看下这4个onXXXX方法,CCScene和CCLayer均继承自CCNode,这4个方法也是CCNode的方法。我们以onEnter为例,

voidCCNode::onEnter(){arrayMakeObjectsPerformSelector(m_pChildren,onEnter,CCNode*);。。。。。}

可以发现里面有个宏,这个就是关键所在~~,宏的定义如下:

#definearrayMakeObjectsPerformSelector(pArray,func,elementType)\do{\if(pArray&&pArray->count()>0)\{\CCObject*child;\CCARRAY_FOREACH(pArray,child)\{\elementType pNode=(elementType)child;\if(pNode)\{\pNode->func();\}\}\}\}\while(false)

由此就很清晰了,当场景切换时,新老场景的各个回调方法会被回调,这些回调方法又会递归调用其children的相同的回调方法,由于CCScene,CCLayer,CCSprite等在cocos2dx的场景构建时为父子关系,那么场景中的各种元素都会回调一次。

有场景切换动画时的回调流程:

有场景动画时回调比较复杂一点,首先需要明确的是场景切换动画也是场景。这样当场景A通过动画X切换到场景B时,实际上是有3个场景:A,X,B。为了便于分析,我们假设场景切换动画X为 CCTransitionShrinkGrow 类的动画。

从场景A切换到场景X:

回到函数 void CCDirector::setNextScene(void) 中,当从A切到X时,m_pRunningScene 是场景A,m_pNextScene 是场景X,A不是场景切换动画类CCTransitionShrinkGrow(CCTransitionScene),X是场景切换动画类。那么根据函数逻辑,函数流程会直接走向场景X的onEnter和onEnterXXX函数,但不会走向场景A的onExitXXX和onExit函数。

CCTransitionScene和CCTransitionShrinkGrow片段:

代码较多,但是根据代码的走向就很清晰了。

classCC_DLLCCTransitionScene:publicCCScene{protected:CCScene*m_pInScene;CCScene*m_pOutScene;。。。。。 。。。。。}classCC_DLLCCTransitionShrinkGrow:publicCCTransitionScene,publicCCTransitionEaseScene{。。。。。 。。。。。}CCTransitionScene*CCTransitionScene::create(floatt,CCScene*scene){CCTransitionScene*pScene=newCCTransitionScene();if(pScene&&pScene->initWithDuration(t,scene)){pScene->autorelease();returnpScene;}CC_SAFE_DELETE(pScene);returnNULL;}boolCCTransitionScene::initWithDuration(floatt,CCScene*scene){CCAssert(scene!=NULL,"Argument scene must be non-nil");if(CCScene::init()){m_fDuration=t;// retainm_pInScene=scene;m_pInScene->retain();m_pOutScene=CCDirector::sharedDirector()->getRunningScene();if(m_pOutScene==NULL){m_pOutScene=CCScene::create();m_pOutScene->init();}m_pOutScene->retain();CCAssert(m_pInScene!=m_pOutScene,"Incoming scene must be different from the outgoing scene");sceneOrder();returntrue;}else{returnfalse;}}voidCCTransitionScene::finish(){。。。。。 。。。。。this->schedule(schedule_selector(CCTransitionScene::setNewScene),0);}voidCCTransitionScene::setNewScene(floatdt){。。。。。 CCDirector*director=CCDirector::sharedDirector();。。。。。 director->replaceScene(m_pInScene);。。。。。}// custom onEntervoidCCTransitionScene::onEnter(){CCScene::onEnter();// disable events while transitionsCCDirector::sharedDirector()->getTouchDispatcher()->setDispatchEvents(false);// outScene should not receive the onEnter callback// only the onExitTransitionDidStartm_pOutScene->onExitTransitionDidStart();m_pInScene->onEnter();}// custom onExitvoidCCTransitionScene::onExit(){CCScene::onExit();// enable events while transitionsCCDirector::sharedDirector()->getTouchDispatcher()->setDispatchEvents(true);m_pOutScene->onExit();// m_pInScene should not receive the onEnter callback// only the onEnterTransitionDidFinishm_pInScene->onEnterTransitionDidFinish();}voidCCTransitionShrinkGrow::onEnter(){CCTransitionScene::onEnter();。。。。。 。。。。。 m_pInScene->runAction(this->easeActionWithAction(scaleIn));m_pOutScene->runAction(CCSequence::create(this->easeActionWithAction(scaleOut),CCCallFunc::create(this,callfunc_selector(CCTransitionScene::finish)),NULL));}

首先,当走向场景X的onEnter时,CCTransitionShrinkGrow类的onEnter函数首先调用了父类CCTransitionScene的onEnter函数,然后调用了CCTransitionScene的finish函数。

根据CCTransitionScene的initXX函数,可以知道在CCTransitionScene中,m_pInScene是场景B,m_pOutScene是场景A,那么根据CCTransitionScene的onEnter函数的逻辑,知道此时场景A的onExitXXX被调用,场景B的onEnter被调用。

再来分析CCTransitionScene的finish函数,该函数又调用了CCTransitionScene的setNewScene函数,在该函数中,我们发现程序调用了我们熟悉的ReplaceScene函数,前面已经知道了m_pInScene是场景B,即程序现在开始执行由场景X切换场景B。

由场景X切换场景B:

和上面一样,我们分析void CCDirector::setNextScene(void) 中,当从X切到B时,m_pRunningScene 是场景X,m_pNextScene 是场景B,B不是场景切换动画类CCTransitionShrinkGrow(CCTransitionScene),X是场景切换动画类。那么根据函数逻辑,函数流程会走向场景X的onExitXXX和onExit函数,但是不会执行场景B的onEnter和onEnterXXX函数。

场景X类是CCTransitionShrinkGrow类,执行场景X的onExitXXX函数和onExit函数时,会进入CCTransitionScene函数的onExit函数,由于cocos2dx是类实例(指针)传递,因此这里的实例和上面由A切到X的类实例是一个,那么m_pInScene依然是场景B,m_pOutScene依然是场景A,在CCTransitionScene函数的onExit函数里,场景A的onExit被调用,场景B的onEnterXXX被调用。

此时,整个场景切换过程已经完成。

综上可得:

没有切换动画时,调用流程:

A: onExitTransitionDidStart

A: onExit

B: onEnter

B: onEnterTransitionDidFinish

有切换动画时,调用流程:

A: onExitTransitionDidStart

B: onEnter

A: onExit

B: onEnterTransitionDidFinish

http://www.jsqmd.com/news/1198369/

相关文章:

  • 度申相机DVP2 SDK 实战:从环境搭建到多语言应用开发
  • BATMAN-ADV协议在Mesh自组网中的拓扑发现与动态绘制
  • 从瀑布到DevOps,我们到底在解决什么问题
  • 真力时中国官方售后服务中心|服务电话及详细地址权威信息公示(2026年7月最新) - 亨得利官方服务中心
  • 卡地亚表蒙安装专业维修保养服务指南权威公示(2026年7月最新) - 卡地亚官方售后中心
  • 2026年太原民事律师选对=省心 杨梅律师专业推荐 - 本地品牌推荐
  • 排查Windows局域网共享失败:从网络发现到SMB协议的深度诊断
  • FPGA电源设计挑战与模块化解决方案
  • Java循环控制进阶:while与do..while的实战抉择与break/continue的精准调控
  • 微信小程序开店用哪个平台?从商品、支付、会员和履约能力判断
  • 2026年7月最新亨得利官方服务项目及价格查询|热线及详细地址权威信息公示 - 亨得利官方博客
  • C++树结构实现:从BST到红黑树的工程实践与内存管理
  • Swagger3与拦截器冲突排查指南:从报错到精准放行
  • 江诗丹顿中国官方专柜客户热线权威信息通知(2026年7月最新) - 江诗丹顿官方服务中心
  • 2026 年现阶段,宜春比较好的太阳能板热水器加工厂推荐几家,别再烧煤!这套系统如何帮你省下每月几百块电费? - 企业推荐管【认证】
  • Typora:告别窄屏束缚,三步打造沉浸式宽屏写作区
  • 江诗丹顿官方售后服务中心地址及联系电话实地考察报告多信源验证(2026年7月更新) - 江诗丹顿服务中心
  • AI工具免费试用全攻略:从注册到平稳过渡的30天实战指南
  • 建站平台哪家好?从AI生成、模板编辑和SEO基础能力判断
  • 2026年7月亲身探访杭州亨得利官方名表服务中心|全新电话和维修地址 - 亨得利官方
  • 【AI总结】2026年6月 主流国内外大模型总结
  • 2026刑事纠纷律所口碑推荐强势出炉 零套路不踩坑 高性价比之选看这篇就够 - myqiye
  • C++与Lua无缝交互:原理、实现与性能优化实战
  • 2026 年 7 月新发布:尖草坪比较好的旧方木模板出租定制厂家怎么联系,揭秘:旧方木模板出租如何帮你省下巨额装修费? - 企业推荐官【认证】
  • XSS漏洞
  • 从问答到任务完成:智体系统与驾驭设计的综述(上)
  • 硬件工程师转型软件设计的思维转变与实践指南
  • GD32F470ZKT6单片机开发板入门学习(一)Keil工程搭建
  • PCB设计工程师核心技能与学习路径:从入门到进阶
  • 真力时维修保养价格查询与费用说明权威公示(2026年7月最新) - 亨得利官方服务中心