Cocos2d-x
发布时间:2022-05-02 发布网站:大佬教程 code.js-code.com
大佬教程收集整理的这篇文章主要介绍了cocos2d-x整体框架源码分析以及启动过程原理(win32),大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
引言:如果你想深入了解cocos2d-x的整个框架和运行流程,如果你想知道整个启动过程的细节,如果你想知道自己写的代码是在什么时候和在哪里被调用的,下面可以为你解答其中奥秘。
对象:适合刚刚入门了cocos2d-x的初学者,编写并运行过简单的demo,并且想仔细探究其中的原理机制。
1、程序入口main.cpp
- intAPIENTRY_tWinMain(HINSTANCEhInstance,
- hPrevInstance,
- LPTSTRlpCmdLine,51)">nCmdShow)
- {
- ...
- AppDelegateapp;
- ...
- @H_616_77@returnCCApplication::sharedApplication()->run();
以上两行是关键代码
(1)代码AppDelegate app;调用了AppDelegate的构造函数,而它的父类是CCApplication,所以CCApplication的构造函数也被调用了
CCApplication::CCApplication()
:m_hInstance(NULL)
,m_hAccelTable(NULL)
{
@H_348_53
@m_hInstance=GetModuleHandle(
null);
@H_763_56
@m_nAnimationInterva
l.QuadPart
=0;
CC_ASSERT(!sm_pSharedApplication);
sm_pSharedApplication=@H_616_77@this;
这里完成了AppDelegate和CCApplication之间的联系,由于AppDelegate是CCApplication的子类,故CCApplication里面的静态单例指针指的便是AppDelegate的实例。之后调用CCApplication::sharedApplication()的相关操作是基于AppDelegate的实现。
(2)代码CCApplication::sharedApplication()->run(
);调用了下面的代码
CCApplication:
:run()
//Initializeinstanceandcocos2d.if(!applicationDidFinishLaunching())
0;
}
..
while(1)
(!Peekmessage(&msg,NULL,PM_REMOVE))
//Getcurrenttimetick.QueryPerfoRMANceCounter(&nNow);
//Ifit'sthetimetodrawnextframe,drawit,elsesleepawhile.(nNow.QuadPart-nLast.QuadPart>m_nAnimationInterval.QuadPart)
nLast.QuadPart=nNow.QuadPart;
CCDirector::sharedDirector()->mainLoop();Sleep(0);
conTinue;
(WM_QUIT==msg.messagE)
//Quitmessageloop.break//Dealwithwindowsmessage.(!m_hAccelTable||!TranslateAccelerator(msg.hwnd,m_hAccelTable,&msg))
Translatemessage(&msg);
Dispatchmessage(&msg);
}
()msg.wParam;
}
在这里,run()函数里面是一个while死循环,不过里面有判断条件if (WM_QUIT == msg.
messag
E)可以跳出循环,终止程序。循环里面每隔一段时间m_nAnimationInterval就调用CCDirector::sharedDirector()->mainLoop(),完成游戏的刷新。
(3)下面来看看mainLoop()都干了啥事:
void
CCDisplayLinkDirector::mainLoop()
(m_bPurgeDirecotorInNextLoop)
@H_763_56
@m_bPurgeDirecotorInNextLoop=@H_
616_77@
false
purgeDirector();
(!m_bInvalid)
drawScene();CCPoolManager::sharedPoolManager()->pop();@H_88_262@
首先解释一下为什么显示的是CCDisplayLinkDirector::mainLoop,而不是 CCDirector::mainLoop,答案就在CCDirector.h头文件里面
class
CC_DLLCCDirector:@H_
616_77@public
CCObject,TypeInfo
{
.......
virtual@H_481_34@mainLoop()=0;CCDirector
..........
在CCDirector类里面,mainLoop是纯虚函数,而CCDisplayLinkDirector是CCDirector的子类。
重新回到mainLoop函数的实现,我们发现drawScene()和CCPoolManager::sharedPoolManager()->pop()是其主要内容,也就是重绘和释放自动内存池管理器里面暂时存储的对象,这个和cocos2d-x的自动内存管理机制有关,所有静态创建对象函数::create()都采用了自动托管机制,比如:
CCSprite*CCSprite::create(@H_
616_77@const
char*pszFileName)
CCSprite*pobSprite=@H_616_77@newCCSprite();
(pobSprite&&pobSprite->initWithFile(pszFileName))
pobSprite->autorelease();
CC_SAFE_deletE(pobSpritE);
NULL;
其中autorelease()函数实现如下
CCOb
ject*CCOb
ject::autorelease(
CCPoolManager::sharedPoolManager()->addObject();
由此可以看到自动内存管理对象在每帧绘制结束后都会被CCPoolManager::sharedPoolManager()->pop()释放,除非我们在create()对象后使用了retain(),retain()也很简单,实现如下
CCOb
ject:
:retain(
CCassert(m_uReference>0,"referencecountshouldgreaterthan0"++m_uReference;@H_88_262@
就是把对象的引用计数-1,这又对应于对象的release()函数
CCOb
ject:
:release(
--m_uReference;
可以看到,对象只有当其引用计数m_uReference=0时,才会真正被删除。
(4)下面看看drawScene()重绘函数负责什么,看完你就全明白了整个框架了
//DrawtheScene
CCDirector::drawScene()
..............
//tickbeforeglClear:issue#533(!m_bPaused)
@H_348_53
@m_p
scheduler->
update(m_fDeltaTim
E);
//drawthescene(m_pRunningScenE)
@H_348_53
@m_pRunningScene->visit(
);
//swapbuffers(m_pobOpenGLView)
@H_348_53
@m_pobOpenGLView->swapBuffers(
);
................
大家看到m_pscheduler->update(m_fDeltaTimE)会不会想到我们经常在HelloWorldScene.h写的void update(float dt),两者有什么关系呢?
首先回忆一下,我们在
HelloWorldScene.h里面是怎样调用到
update函数的
- CCNode::schedule(SEL_scheDULESELEctor)
- {
- ->schedule(SELEctor,0.0f,kCCRepeatForever,0.0f);
@H_515_450@}
- CCNode::schedule(SEL_scheDULESELEctor,floatinterval,unsignedrepeat,51)">delay)
@H_515_450@{
- CCassert(SELEctor,51)">"Argumentmustbenon-nil");
@H_515_450@CCassert(interval>=0,51)">"Argumentmustbepositive");
@H_32_481@m_pscheduler->scheduleSELEctor(SELEctor,,interval,repeat,delay,!m_bRunning);
- }
- CC_DLLCCNode:CCObject
- {.........
@H_515_450@CCscheduler*m_pscheduler;
@H_515_450@}
再对比一下刚才drawScene()重绘函数
TypeInfo
{...............
CC_PROPERTY(CCscheduler*,m_pscheduler,scheduler);
#defineCC_PROPERTY(varType,varName,funName)\//看这里protected:varTypevarName;\
:varTypeget##funName();\
set##funName(varTypevar);
我们发现CCNode和CCDirector类都申明了CC
scheduler *m_p
scheduler,都不是同一个滴。
且慢,不一定哦,看看CCNode的构造函数先
CCNode::CCNode(
:...........
CCDirector*director=CCDirector::sharedDirector();
...............
@H_763_56
@m_p
scheduler=director->get
scheduler(
);
原来CCNode里面的m_pscheduler引用了CCDirector的m_pscheduler,感受到穷追不舍的魅力了吧。
再回到之前的问题:
CCDirector::drawScene里面的m_p
scheduler->
update(m_fDeltaTim
E)和我们经常在
HelloWorldScene.h写的void
update(float dt),两者有什么关系呢?
//mainloop
CCscheduler::update(dt)
{
@H_515_
450@................
for(tHashTimerEntry*elt=m_pHashForTimers;elt!=NULL;)
@H_576_466
@m_pCurrentTarget=elt;
@H_576_466
@m_bCurrentTargetSalvaged=
;
@H_515_
450@
(!m_pCurrentTarget->paused)
//The'timers'arraymaychangewhileinsidethisloop(elt->timerIndex=0;elt->timerIndex<elt->timers->num;++(elt->timerIndeX))
elt->currentTimer=(Cctimer*)(elt->timers->arr[elt->timerIndex]);
elt->currentTimerSalvaged=elt->currentTimer->update(dt);
@H_515_
450@}
..................
...............
重点看elt->currentTimer->update(dt);
elt->currentTimer是C
ctimer类,看看里面的
update函数是神马情况先
C
ctimer::
update(
dt)
(m_fElapsed==-1)
....................
(m_bRunForever&&!m_bUseDelay)
{...................
(m_fElapsed>=m_fInterval)
(m_pTarget&&m_pfnSELEctor)
(m_pTarget->*m_pfnSELEctor)(m_fElapsed);
//advancedusage(m_bUseDelay)
(m_fElapsed>=m_fDelay)
...............
(m_fElapsed>=m_fInterval)
(m_pTarget&&m_pfnSELEctor)
.......................
你可能还不知道(m_pTarget->*m_pfnSELEctor)(m_fElapsed);这个什么意思,没事,重新看看HelloWorldScene.h调用update函数时的代码:
CC
scheduler::
schedule
SELEctor(SEL_
scheDULEpfn
SELEctor,CCOb
ject*pTarget,51)">fInterval,51)">delay,51
); font-weight:bold">bool
bPaused)
tHashTimerEntry*pElement=NULL;
HASH_FIND_INT(m_pHashForTimers,&pTarget,pElement);
(!pElement)
...........................
CCassert(pElement->paused==bPaused,51)">""(pElement->timers==NULL)
pElement->timers=ccArrayNew(10);
Cctimer*pTimer=Cctimer();
pTimer->initWithTarget(pTarget,pfnSELEctor,fInterval,delay);
pTimer->release();
重点看pTimer->initWithTarget(pTarget,delay),其中pTarget就是CCNode(对应
HelloWorld类)对象本身,而pfnSELEctor就是刚才说的函数指针,指向
HelloWorld::update,下面是initWithTarget的函数实现
C
ctimer::initWithTarget(CCOb
ject*pTarget,SEL_
scheDULEpfn
SELEctor,51)">fSeconds,51)">nRepeat,51)">fDelay)
@H_763_56
@m_pTarget=pTarget;
@H_763_56
@m_pfn
SELEctor=pfn
SELEctor;
.....................
true
由此,我们解决刚才提出的问题:
答案就在上面,再次啰嗦说明一下,pTarget就是CCNode(对应
HelloWorld::update,也就是说,
HelloWorld类定义的void update(float dt)被调用了,而且是在整个主循环里面
CCDirector::sharedDirector()->mainLoop()。
(5)结束语:
整个cocos2d-x的框架源码就是这样,具体一些细节还未涉及,但我们已经理解程序一开始从main函数,然后怎么样一步步调用到我们自己是
HelloWorld.h里面自己定义实现的函数,特别是
update函数,
同时也了解了cocos2d-x的一些内存管理机制和回调机制,也在这个框架代码里面,还有整个框架是怎么实现帧数控制的。
用《一代宗师》里面的一句话来概括这次框架源码研读之旅吧——”念念不忘,必有回响“。
大佬总结
以上是大佬教程为你收集整理的cocos2d-x整体框架源码分析以及启动过程原理(win32)全部内容,希望文章能够帮你解决cocos2d-x整体框架源码分析以及启动过程原理(win32)所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。