本文仅供个人记录和复习,不用于其他用途
什么是帧循环
我们之前对于帧已经有了一个基本的概念,事实上,游戏乃至图形界面都是不断的绘图,然而这些绘图必须遵守一定的逻辑,也就是所谓的游戏逻辑。游戏逻辑控制游戏的内容,会根据用户的输入和时间的流逝而改变。因此,游戏可以抽象为不断地重复以下动作:
- 处理用户输入
- 处理定时事件
- 绘图
游戏的主循环基本上就是如此,它会反复执行以上的动作,保持游戏的进程,直到玩家退出游戏。
mainLoop方法
CCDirector::mainLoop()
方法是定义在CCDirector
中的抽象方法,它的具体实现在CCDisplayLinkDirector
类(3.0找不到的话就把CC
去掉)。这个方法负责调用定时器、绘图、发送全局通知、并处理内存回收池。该方法按帧调用,每帧调用一次,而帧间间隔取决于两个因素:预设频率(默认为60帧每秒)和每帧计算量的大小。我们在玩游戏的时候都知道,如果电脑的配置较低,哪怕你设置的帧率为60,电脑的计算力也无法达到60帧每秒。因此,就会出现游戏画面不流畅。下面是从DisplayLinkDirector
类中找到的关于mainLoop()
方法的实现:
|
|
mainLoop()
主要是先查看是否需要释放Director
,一般是游戏结束时执行。第三个有一个drawScene()
方法,从字面意义上来看就是绘制场景,遍历每一个节点进行绘图。最后将这一帧弹出内存回收池,删除这一帧的内容。具体代码如下:
|
|
可以发现drawScene
主要用于处理OpenGL和一些细节,如计算FPS、帧间时间差等,这里我们主要进行了以下操作:
- 计算时间差,2帧之前的时间差,
calculateDeltaTime()
- 定时任务调用
_scheduler->update(_deltaTime)
- 事件处理
EventAfterUpdate
- 设置当前的下一个场景,主要就是把当前场景释放掉,之后把
_nextScene
设置为当前的场景 - 调用当前场景的渲染方法
_runningScene->render(_renderer)
- 事件处理意思是
Visit
调用完了,_eventAfterVisit
- 调用渲染引擎进行渲染
_renderer->render()
- 事件处理
_eventAfterDraw
- 调用
openGLView
平台提供的屏幕显示方法,_openGLView->swapBuffers()
游戏的开始
说起来,我们介绍了那么多概念,貌似还没有讲游戏是如何开始的。事实上,游戏的开始文件是main.h
,也就是游戏的入口函数,位于win32
目录下。查看源文件,能够发现如下代码:
|
|
这里可以看出,在入口函数中,首先创建了一个AppDelegate
对象,AppDelegate
继承自CCApplication
,在创建AppDelegate
对象的时候就会隐式调用CCApplication
构造函数,在这个构造函数里边会将AppDelegate
的this
指针传递给全局共享对象sm_pSharedApplication
,如下:
|
|
接下来调用Application::getInstance()->run()
启动游戏,如下:
|
|
这里可以看到,run()
启动了applicationDidFinishLaunching()
方法。我们之前介绍过,这个方法用于设置游戏启动相关参数,同时也执行我们自定义的代码。
|
|
另外呢,在applicationDidFinishLaunching()
中可以找到这一行代码。它设置了glview
对象之后就开始运行场景,GLView
主要就是就是负责窗口管理的工作。
|
|
至于Run()
方法就是将m_running
设置为true
,用于启动。我们再来看看使用了m_running
的方法:
|
|
可以看到,Rander()
渲染方法执行了OnRendering()
。而当m_running
和m_initialized
全为true
时,便调用我们的mainLoop()
方法。至此,便是游戏的主循环。至于具体的渲染过程,之后再讲。