上次讲到cocos2d-x的main loop是下面这句:
cocos2d::CCApplication::sharedApplication()->run();
我们来看看这个函数的内部实现:
int CCApplication::run()
{
if(applicationDidFinishLaunching())
{
[[CCDirectorCaller sharedDirectorCaller] startMainLoop];
}
return0;
}
看看,我没有欺骗大家吧。这个函数在设计的时候想要参照main函数返回一个int值来表示运行结果,但是你知道的外部调用中完全没有进行处理,略坑爹。来深入这个函数的内部:
-(void) startMainLoop
{
// CCDirector::setAnimationInterval() is called,
// we should invalidate it first
[displayLink invalidate];
displayLink = nil;
displayLink = [NSClassFromString(@"CADisplayLink")
displayLinkWithTarget:self selector:@selector(doCaller:)];
[displayLink setFrameInterval: self.interval];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
}
这个函数在不同平台实现不同,在这里它使用被动刷新模式。就是系统的display link调动游戏的主循环。这比一个单纯的while循环更能节省系统资源,与Android上的OpenGL绘制类似。与之不同的是desktop平台上的实现。你会发现,就算什么都不绘制,cocos2d-x也要耗尽你一个cpu核的计算。测试hello world在我的touch 5 上闲置cpu占用只有10%。
到这里可以知道run函数只是进入main loop的入口,一直在不停调用的是:
cocos2d::CCDirector::sharedDirector()->mainLoop();
进入CCDirector这个类就会发现,这也是一个抽象类,mainLoop被标示为纯虚函数。那就看看sharedDirector:
CCDirector* CCDirector::sharedDirector(void)
{
if (!s_SharedDirector)
{
s_SharedDirector = new CCDisplayLinkDirector();
s_SharedDirector->init();
}
return s_SharedDirector;
}
这个与之前的CCApplication有类似的地方,却使用了另外一种实现。在第一次访问的时候创建实例,也就是典型的单件模式。真正做事情的是CCDisplayLinkDirector。诚如你所预料的CCDisplayLinkDirector继承之CCDirector。实现了main loop。与之前如出一辙:
void CCDisplayLinkDirector::mainLoop(void)
{
if(m_bPurgeDirecotorInNextLoop)
{
m_bPurgeDirecotorInNextLoop=false;
purgeDirector();
}
elseif(!m_bInvalid)
{
drawScene();
// release the objects
CCPoolManager::sharedPoolManager()->pop();
}
}
前面检查是否在下一帧中结束循环。如果为真就开始调用purgeDirector()来进行清理。注意这里的变量命名,是没有错的。当前帧中设置这个值,也只能等到下一帧才能生效。如果不结束循环,那就开始绘制场景,然后进行一次垃圾回收。这里的三个函数都是大头,只能一节节分析。我们接下来先看看windows版本CCApplication的实作。