文章出自于  http://blog.csdn.net/zhouyunxuan

cocos2d到底是怎样把场景展示给我们的,我一直非常好奇。

凭个人猜想,引擎内部的结构类似于这样

    while(true)
{
if(update_span < min_update_span)
{
update_game();
if(done)
{
break;
}
}
else
{
cal_update_span();
}
}

在app開始执行时会调用里面的方法。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 

来看看这个函数最后return YES之前的一行代码

    cocos2d::Application::getInstance()->run();

没错,就是这个,然后我们进入到run函数里面来看个到底

    int Application::run()
{
if (applicationDidFinishLaunching())
{
//这个函数在这里调用了startMainLoop
[[CCDirectorCaller sharedDirectorCaller] startMainLoop];
}
return 0;
}

然后我们继续跟进看看startMainLoop

    -(void) startMainLoop
{
// Director::setAnimationInterval() is called, we should invalidate it first
[displayLink invalidate];
displayLink = nil; //给CADisplayLink传了一个doCaller函数,让CADisplayLink不断的调用
displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(doCaller:)];
//设置调用频率
[displayLink setFrameInterval: self.interval];
//開始循环吧!
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}

CADisplayLink,须要增加QuartzCore.framework

这个函数类似于update函数,默认每秒被调用60次,如今我们再进入doCaller函数吧

    -(void) doCaller: (id) sender
{
cocos2d::Director* director = cocos2d::Director::getInstance();
[EAGLContext setCurrentContext: [(CCEAGLView*)director->getOpenGLView()->getEAGLView() context]];
//最终进入到这场表演的主角了,我期待了好久!! 。
director->mainLoop();
}

事实上Director::getInstance();返回的不是Director。被骗了好久-= -

Director::getInstance() 返回的并非Director。而是Director的子类DisplayLinkDirector();

    Director* Director::getInstance()
{
if (!s_SharedDirector)
{
s_SharedDirector = new DisplayLinkDirector();
s_SharedDirector->init();
} return s_SharedDirector;
}

程序的主要逻辑都通过调用mainloop来完毕,这种方法负责调用计时器。画图,发送全局通知,并处理内存回收池,这种方法按帧调用,每帧调用一次。而帧之间取决于两个因素,一个是预设的帧频(默觉得每秒六十次),还有一个是每帧的计算量大小,当逻辑处理与画图计算量过大时,设备无法完毕每秒六十次的绘制,此时帧率就会减少。

    void DisplayLinkDirector::mainLoop()
{
//是否在下一循环中清除
//bool _purgeDirectorInNextLoop; // this flag will be set to true in end()
if (_purgeDirectorInNextLoop)
{
log("clear director");
_purgeDirectorInNextLoop = false;
//会做一些清理
purgeDirector();
}
//假设不清除的话(且为合法的)ps:一般都是会进入到这里。然后进行绘制等等。 else if (! _invalid)
{
//画场景
drawScene(); // release the objects
PoolManager::getInstance()->getCurrentPool()->clear();
}
}

然后我们接着看看这伟大的 drawScene里面做了什么吧!

 void Director::drawScene()
{
//计算时间增量
// calculate "global" dt
calculateDeltaTime(); // 假设两帧间隔时间太短(_deltaTime等于0)就直接忽略这次的绘制
// FLT_EPSILON 是 __FLT_EPSILON__ 的宏。__FLT_EPSILON__ 是c99的特征,它是满足 x+1.0不等于1.0的最小的正数,直接输出为0。
if(_deltaTime < FLT_EPSILON)
{
return;
} //
if (_openGLView)
{
_openGLView->pollInputEvents();
} //tick before glClear: issue #533
//仅仅要游戏没有暂停,调度器神马的就会在这里被运行。
if (! _paused)
{
_scheduler->update(_deltaTime);
_eventDispatcher->dispatchEvent(_eventAfterUpdate);
} glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* to avoid flickr, nextScene MUST be here: after tick and before draw.
XXX: Which bug is this one. It seems that it can't be reproduced with v0.9 */
if (_nextScene)
{
setNextScene();
} pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); //画场景
if (_runningScene)
{
_runningScene->visit(_renderer, Mat4::IDENTITY, false);
_eventDispatcher->dispatchEvent(_eventAfterVisit);
} // 画通知节点
if (_notificationNode)
{
_notificationNode->visit(_renderer, Mat4::IDENTITY, false);
} //假设设置了显示debug信息,就会在这里进行每帧的更新。
if (_displayStats)
{
showStats();
} _renderer->render();
_eventDispatcher->dispatchEvent(_eventAfterDraw); popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); _totalFrames++; // 交换缓冲区
if (_openGLView)
{
_openGLView->swapBuffers();
} //计算fps上的信息
if (_displayStats)
{
calculateMPF();
}
}

最初提出来的结构和发现的结构还是有点相似的。

仅仅只是引擎更友好的抽象封装出来了。且做了非常多防止异常的处理。程序猿还都是非常小心的嘛。。。

调用的CADisplayLink是ios平台的,假设换成其它平台就不一样啦。

毕竟win是木有CADisplayLink的。

不相信?

好吧,我们来看看win是怎样调用的吧,首先找到Application::run()函数。

    //假设窗体不关闭
while(!glview->windowShouldClose())
{
//计算时间
QueryPerformanceCounter(&nNow);
//两帧间距时间要大一点才给你画哦
if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart)
{
//上一帧的时间就等于如今这一帧,用于下次计算两帧的间隔时间。 nLast.QuadPart = nNow.QuadPart; //进入到我们伟大的mainloop了。是不是有点小激动 - -
director->mainLoop();
glview->pollEvents();
}
else
{
//神马!睡0秒。 好吧。光是看表面还是非常骗人的。
Sleep(0);
}
}

Sleep(0)是指CPU交出当前线程的运行权,让CPU去运行其它线程。也就是放弃当前线程的时间片。转而运行其它线程。

一般来说,假设当前线程比較耗时比較占CPU资源。能够在结尾处加上Sleep(0), 这样效率会得到大大的提高。

看了win上面的调用,发现和我一開始的猜想更像有木有!!!

有时候。做笔记记录下学习过程也挺不错的。

肯定没人会转载的- -

可是为了防止蜘蛛爬走了我的文章,我还是凝视下- -

文章出自于  http://blog.csdn.net/zhouyunxuan

cocos2d-x 3.1.1学习笔记[23]寻找主循环 mainloop的更多相关文章

  1. [XMPP]iOS聊天软件学习笔记[一]

    @import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...

  2. cocos2d-x 3.1.1 学习笔记[3]Action 动作

    这些动画貌似都非常多的样子,就所有都创建一次. 代码例如以下: /* 动画*/ auto sp = Sprite::create("card_bg_big_26.jpg"); Si ...

  3. cocos2d-x 3.1.1 学习笔记[2]Sprite 精灵

    Sprite应该是用到最多的一个类吧.无法想像一个游戏没有精灵将怎样进行愉快的玩耍. Sprite继承于Node 和 TextureProtocol. Sprite是一个2d的图像. Sprite能够 ...

  4. cocos2d-x 3.1.1 学习笔记[21]cocos2d-x 创建过程

    文章出自于  http://blog.csdn.net/zhouyunxuan RootViewController.h #import <UIKit/UIKit.h> @interfac ...

  5. cocos2d-x 3.1.1 学习笔记[4]GridActions 网格动画

    文章写的  http://blog.csdn.net/zhouyunxuan 老样子.见代码. //GridActions can only used on NodeGrid auto nodeGri ...

  6. cocos2d-x 3.1.1 学习笔记[11] http请求 + json解析

    //http须要引入的头文件和命名空间 #include <network/HttpClient.h> using namespace network; //json须要引入的头文件 #i ...

  7. [XMPP]iOS聊天软件学习笔记[四]

    昨天完成了聊天界面,基本功能算告一段落 开发时间:五天(工作时间) 开发工具:xcode6 开发平台:iOS8 XMPP框架:XMPPFramework git clone https://githu ...

  8. [XMPP]iOS聊天软件学习笔记[三]

    今天做了好友界面,其实xmpp内部已经写好很多扩展模块,所以使用起来还是很方便的 开发时间:五天(工作时间) 开发工具:xcode6 开发平台:iOS8 XMPP框架:XMPPFramework gi ...

  9. [XMPP]iOS聊天软件学习笔记[二]

    @import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...

随机推荐

  1. 运维派 企业面试题4&5 创建10个 用户 ; ping探测主机是否在线

    Linux运维必会的实战编程笔试题(19题) 企业面试题4: 批量创建10个系统帐号oldboy01-oldboy10并设置密码(密码为随机8位字符串). #!/bin/bash # ;i<=; ...

  2. pace.js 原理(转)

    pace.js监控了什么: pace.js对于加载进度监控了什么呢?通过阅读源码,我们看到整体的进度有四个部分组成:document,elements,eventLag和ajax这四种监视器(Moni ...

  3. bzoj4551 [HEOI2016]树

    题目描述 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均 ...

  4. Linux bash常用快捷键

    移动光标 ctrl-a 光标移动到行首 ctrl-e 光标移动到行尾 ctrl+xx 在行首和光标位置直接切换 ctrl-b 光标左移一位 ctrl-f 光标右移一位 alt-b 光标左移一词 alt ...

  5. 普通码农和CTO之间的差距

    虚心 学习的第一步是--"我不懂".一个空是水杯才能装水,如果是满的就没有办法装水了."自我肯定"是一种非常难克服的习惯,经常会有朋友看到某个技术或者实现之后不 ...

  6. javascript位操作符右移>>>的妙用

    var len=arr.length>>>0; 在arr.length为null或undefined的时间,强制转换为0;

  7. SpringMVC+Jquery -页面异步载入数据

    背景: 做项目时涉及到页面.当我打算在controller中传一个list到页面,然后通过<c:foreach>循环遍历出来时,同事说:你这样每次都要刷新.这都是几百年前使用的技术了.你用 ...

  8. 使用client对象模型读取SharePoint列表数据

    使用client对象模型读取SharePoint列表数据 client对象模型提供了强有力的方式.从远程client应用程序管理列表. 1. 管理员身份打开VS,新建项目Windows窗口应用程序,命 ...

  9. 英语音乐---三、Cry on my shoulder

    英语音乐---三.Cry on my shoulder 一.总结 一句话总结:Cry on my shoulder 在我的肩膀上哭泣 1.If the hero never comes to you. ...

  10. php中的页面跳转和重定向

    php中的页面跳转和重定向 ThinkPHP中跳转和重定向的区别 跳转: 浏览器认为: 当前URL请求成功, 重新请求新的URL. 浏览器会 记录当前的URL 和 新的URL 在请求历史记录中. 回退 ...