简述:
 
我靠上面图是不是太大了, 有点看不清了。 
总结一下过程:
之前说过的appController 之后经过了若干初始化, 最后调用了displayLinker 的定时调用, 这里调用了函数 mainLoop, 我们在这里进行详细分解这个mainloop 到底做些些啥, 看完这篇,应该能初步了解到cocos2dx是如何把Scene或界面元素显示到屏幕上的。 
 
我们主要分析的是 void DisplayLinkDirector::mainLoop() 
这个函数, 它最后调用了Director::drawScene 这里对drawScene进行展开,不明白这个mainloop如何调用的, 可以参考一下我写的第一篇分析 “1 cocos2dx 3.0 源码分析-程序启动与主循环”。 
 
目录:
 
Director::drawScene()  主要做了哪些事呢? 其中省去了一些我觉得无关紧要的小东西,最好你看看源码, 看哪里我没说到。
 
1 计算时间差, 2帧之前的时间差,calculateDeltaTime()
2 定时任务调用 _scheduler->update(_deltaTime);
3 事件处理 EventAfterUpdate
4 设置当前的下一个场景, 主要就是把当前场景释放掉, 之后把_nextScene 设置为当前的场景
5 调用当前场景的渲染方法        _runningScene->render(_renderer);
6 事件处理意思是Visit调用完了, _eventAfterVisit
7 调用渲染引擎进行渲染  _renderer->render();
8 事件处理 _eventAfterDraw
9 调用 openGLView 平台提供的屏幕显示方法, _openGLView->swapBuffers();
 
下面我一个一个的展开, 简单的介绍一下, 比较复杂的咱们留在后面进行分析说明:
 
1 计算时间差, 2帧之前的时间差 calculateDeltaTime()
 
我们在update(float dt) 中得到的float dt.  就是这里计算的,计算了, 上次调用和这次调用之前的差。 
 
2 定时任务调用 _scheduler->update(_deltaTime);
 
Scheduler 本身就是用来处理更新函数调用的。 我们在自己的场景中经常会使用schedulerUpdate(), 然后实现一个update(float dt) 方法,其实就是在内部把当前的调用请求注册到了 scheudler 中, 之后在这个主循环每帧时进行统一的调用update() 函数. 
这里可以看到, 这个update调用的时机还是蛮早的呢, 啥都没干呢, 就先调用它了。 稍等我要把这点记住。 
 
3 事件处理 EventAfterUpdate
 
 _eventDispatcher->dispatchEvent(_eventAfterUpdate);
 
触发事件“更新调用完了”, 这里大家也不用纠结, 我们可以简单的认为这是一个通知,发送了一个 “更新调用完了“的通知,之后由事件管理器EventDispatcher 来调用注册了这个事件的函数。 
 
事件处理器Dispatcher 典型的观察者模式, 细节这里不说, 以后单出一章说明。 
 
4 设置当前的下一个场景,其实就场景的处理, 场景的用处理就在这里体现了。 
setNextScene();
 
主要就是把当前场景释放掉, 之后把_nextScene 设置为当前的场景, 还记得我们在调用场景时要调用一个 director->runWithScene(scene);
这里的scene 可以被认为是下一个场景了。 下面是它的几个过程
 
> 清理正在运行的Scene
_runningScene->release();
> 设置当前Scene
_runningScene = _nextScene;
_nextScene->retain();
_nextScene = nullptr;
> 调用当前场景onEnter
_runningScene->onEnter();
 
5 调用当前场景的渲染方法        _runningScene->render(_renderer);
 
1> 加载当前的Camera
Camera::_visitingCamera = defaultCamera;
2> 装载当前Camera的投影矩阵  director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION,Camera::_visitingCamera->getViewProjectionMatrix());
3> 调用visit; 这个函数可重要了,这个函数主要是分别调用当前节点下的子节点的visit(), 之后调用了自身的draw将相应的Command命令把渲染请求加入的当前readerer的渲染队列中。   visit(renderer, Mat4::IDENTITY, 0);
3.1 对当前子节点排序 sortAllChildren
3.2 递归调用当前localZOrder 小于当前元素的子元素的visit() 

// draw children zOrder < 0
for( ; i < _children.size(); i++ )
{
auto node = _children.at(i); if ( node && node->_localZOrder < )
node->visit(renderer, _modelViewTransform, flags);
else
break;
}
3.3 调用自身的draw()把指定的渲染命令添加到当前的渲染队列
   if (visibleByCamera)
this->draw(renderer, _modelViewTransform, flags); 下面是一个标准的Sprite的Draw()
void Sprite::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
// Don't do calculate the culling if the transform was not updated
_insideBounds = (flags & FLAGS_TRANSFORM_DIRTY) ? renderer->checkVisibility(transform,_contentSize) : _insideBounds;
if(_insideBounds)
{
_quadCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(),_blendFunc, &_quad, , transform);
renderer->addCommand(&_quadCommand);
}
}
 
3.4 递归调用其它子节点的visit() 

 for(auto it=_children.cbegin()+i; it != _children.cend(); ++it)
(*it)->visit(renderer, _modelViewTransform, flags);
4> 调用渲染引擎进行渲染 renderer->render();
这块渲染相关的, 我不展开了,回头会详细说, 大家知道引擎就是使用它来把元素显示的屏幕上的,它封装了大部分的OpenGL的指令。 
 
6 事件处理意思是Visit调用完了, _eventAfterVisit
 
通知Visit调用完了, 这个visit就是把渲染请求封装成命令,压入Render的渲染队列。 
 
7 调用渲染引擎进行渲染  _renderer->render();
 
其它渲染操作。 就是画东西
 
8 事件处理 _eventAfterDraw
 
通知我画完了。 
 
9 调用 openGLView 平台提供的屏幕显示方法, _openGLView->swapBuffers();
 
所有操作做完了, 这里我们的操作都还只在 OpenGL 里帧缓存中, 我们要把它显示在屏幕上 就要调用 不同平台提供的对OpenGLES 的支持函数, iOS上调用的是 [context_presentRenderbuffer:GL_RENDERBUFFER], 主要就是把帧缓存中的内容真正的交换或者说是显示在屏幕上。 
 
 
总结:
 
可以看到, 主循环里做了很多工作, 更新,事件处理, 场景切换,渲染, 是不是全了。 我看差不多。 后面继续。。 

3 cocos2dx 3.0 源码分析-mainLoop详细的更多相关文章

  1. 5 cocos2dx 3.0源码分析 渲染 render

    渲染,感觉这个挺重要了,这里代入一个简单的例子 Sprite 建立及到最后的画在屏幕上, 我们描述一下这个渲染的流程:   1 sprite 初始化(纹理, 坐标,及当前元素的坐标大小信息) 2 主循 ...

  2. 4 cocos2dx 3.0 源码分析- scheduler

    scheduler 这个类, 负责了引擎的自定义更新, 及定时更新相关的操作, 看看下面的代码,很熟悉吧.   schedule(schedule_selector(HelloWorld::updat ...

  3. 2 cocos2dx 3.0 源码分析-Director

    Director 导演类, 这个类在整个引擎中担当着最重要的角色, 先看看它是如何初始化的,它共管理了哪些内容呢?    1初始化- 更新处理Scheduler   Scheduler 这个类负责用户 ...

  4. AFNetWorking3.0源码分析

    分析: AFNetWorking(3.0)源码分析(一)——基本框架 AFNetworking源码解析 AFNetworking2.0源码解析<一> end

  5. Solr5.0源码分析-SolrDispatchFilter

    年初,公司开发法律行业的搜索引擎.当时,我作为整个系统的核心成员,选择solr,并在solr根据我们的要求做了相应的二次开发.但是,对solr的还没有进行认真仔细的研究.最近,事情比较清闲,翻翻sol ...

  6. Solr4.8.0源码分析(25)之SolrCloud的Split流程

    Solr4.8.0源码分析(25)之SolrCloud的Split流程(一) 题记:昨天有位网友问我SolrCloud的split的机制是如何的,这个还真不知道,所以今天抽空去看了Split的原理,大 ...

  7. Solr4.8.0源码分析(24)之SolrCloud的Recovery策略(五)

    Solr4.8.0源码分析(24)之SolrCloud的Recovery策略(五) 题记:关于SolrCloud的Recovery策略已经写了四篇了,这篇应该是系统介绍Recovery策略的最后一篇了 ...

  8. Solr4.8.0源码分析(23)之SolrCloud的Recovery策略(四)

    Solr4.8.0源码分析(23)之SolrCloud的Recovery策略(四) 题记:本来计划的SolrCloud的Recovery策略的文章是3篇的,但是没想到Recovery的内容蛮多的,前面 ...

  9. Solr4.8.0源码分析(22)之SolrCloud的Recovery策略(三)

    Solr4.8.0源码分析(22)之SolrCloud的Recovery策略(三) 本文是SolrCloud的Recovery策略系列的第三篇文章,前面两篇主要介绍了Recovery的总体流程,以及P ...

随机推荐

  1. pdb-不需要IDE也能调试

    python中有个pdb模块,使python代码也可以像gdb那样进行调试,一般情况下pdb模块可以在代码内直接使用,也可以通过命令行参数的形式添加该模块进行调试(python -m pdb file ...

  2. Error: Exception was raised when calling event-notify Vuser function in extension parameng.dll: System Exceptions: EXCEPTION_ACCESS_VIOLATION

    解决方法:在C 盘新建一个TEMP目录,把环境变量TMP,TEMP的值设置成环境变量,重启计算机

  3. Oracle表空间不足ORA-01654

    v在往数据表里插入数据时,出现了ORA-01654: 索引 SSERVICE.IX_MSI_WDR_INPUT_1 无法通过 1024 (在表空间 USERD 中) 扩展的错误信息,原来是数据量太大, ...

  4. C++后台研发面试总结

    前言: 从中秋到国庆这几天面试了几家公司,有大公司也有小公司,连续几天面试没有系统的整理整理,正好有时间系统的整理一下,好多考点牛客的大佬们都分享过了,虽然每个人的方向不相同,不过多看一些总能找到一些 ...

  5. C# 字符串提取数字

    转自:http://www.cnblogs.com/dolphin-gjh/p/6121792.html 一.使用正则表达式 1 string str = "sztq数字提取123sztq数 ...

  6. ScrureCRT访问CentOS时出现乱码的解决办法

    1.  ScrureCRT访问CentOS时,出现乱码. 登陆后,输入日历命令:cal 输出日历带有乱码的结果: 2.  查看当前系统的语言. 输入命令:echo $LANG 输出:zh_CN.UTF ...

  7. ie8浏览器 图片本身问题导致 无法显示图片--- 诡异现象的排查分享

    引子:   前段时间 做新版2.0 首页 的时候, 总感觉 新版首页 线上 精彩回顾下的 2张图片颜色怪怪的,当时以为是图片压缩太厉害导致的,由于实在太忙就没太在意!以下 是来自线上 截图:  红色方 ...

  8. Number 和 parseInt 区别

    把字符串 转换成 数字的时候, Number 有点不靠谱, 因为会对 '' 和 null 转换成0, parseInt 相对靠谱些; 判断是否是数值时, isNaN 对于字符串'2'的判断是数字, 对 ...

  9. django使用mongodb建表

    1.安装mongodb的py模块包 pip install mongoengine 同时安装了mongoengine.pymongo 2.在项目配置文件settings.py中配置 from mong ...

  10. BZOJ1018 堵塞的交通(线段树)

    题目很好明白,然后实现很神奇.首先如果考虑并查集的话,对于删边和加边操作我们无法同时进行.然后暴力分块的话,复杂度是O(n sqrt n) ,不是很优.于是看了题解,发现了线段树的神奇用途. 我们维护 ...