从本篇文章开始,将分析cocos2d-X 3.2源代码,本篇首先介绍cocos2d-X 3.2的渲染结构,使用的是3.2正式版。
首先是程序入口:
<pre name="code" class="cpp">int Application::run()
{
PVRFrameEnableControlWindow(false);
// Main message loop:
LARGE_INTEGER nFreq;
LARGE_INTEGER nLast;
LARGE_INTEGER nNow;
QueryPerformanceFrequency(&nFreq);
QueryPerformanceCounter(&nLast);
// Initialize instance and cocos2d.进入主循环之前做初始化工作
if (!applicationDidFinishLaunching())
{
return 0;
}
//获取单例的director和绘图窗口
auto director = Director::getInstance();
auto glview = director->getOpenGLView();
// Retain glview to avoid glview being released in the while loop
glview->retain();
while(!glview->windowShouldClose())
{
QueryPerformanceCounter(&nNow);
if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart)
{
nLast.QuadPart = nNow.QuadPart;
//进入主循环
director->mainLoop();
glview->pollEvents();
}
else
{
Sleep(0);
}
}
// Director should still do a cleanup if the window was closed manually.这里是说游戏窗口关闭之后需要再运行一次主循环释放内存,否则会报错
if (glview->isOpenGLReady())
{
director->end();
director->mainLoop();
director = nullptr;
}
glview->release();
return true;
}
</pre><pre name="code" class="cpp">
游戏主循环mainloop()方法:游戏主循环每一帧所做的事无非就是加载数据,绘制屏幕,释放内存
<pre name="code" class="cpp">void DisplayLinkDirector::mainLoop()
{
//导演类调用end函数 ,会调用到这里来
if (_purgeDirectorInNextLoop)
{
_purgeDirectorInNextLoop = false;
purgeDirector();//清除导演类
}
else if (! _invalid)
{
drawScene();//绘制屏幕
// release the objects
PoolManager::getInstance()->getCurrentPool()->clear();//释放内存
}
}
绘制屏幕drawScene():
void Director::drawScene()
{
// calculate "global" dt 计算上一帧开始到即将开始这一帧的时间间隔<span style="font-family: Arial, Helvetica, sans-serif;">_deltaTime </span>
calculateDeltaTime();
// skip one flame when _deltaTime equal to zero.间隔时间太短则忽略
if(_deltaTime < FLT_EPSILON)
{
return;
}
//空实现
if (_openGLView)
{
_openGLView->pollInputEvents();
}
//自己加的游戏循环
if(! _pausePreDrawListener && _preDrawListener)
{
_preDrawListener->onPreDraw(_deltaTime);
}
//tick before glClear: issue #533 非暂停状态
if (! _paused)
{
_scheduler->update(_deltaTime);
_eventDispatcher->dispatchEvent(_eventAfterUpdate);
}
//自己的游戏逻辑
if(_speedStep > 0.0f && _speedTime > 0.0f)
{
for(float time = 0.0f; time < _speedTime; time += _speedStep)
{
if(_preDrawListener)
{
_preDrawListener->onPreDraw(_speedStep);
}
_scheduler->update(_speedStep);
}
_speedStep = 0.0f;
_speedTime = 0.0f;
}
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); //edit by chenyingpeng
/* 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 */切换下一场景,必须放在逻辑后绘制前,否则会出bug
if (_nextScene)
{
setNextScene();
}
pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
// draw the scene绘制场景
if (_runningScene)
{
_runningScene->visit(_renderer, Mat4::IDENTITY, false);
_eventDispatcher->dispatchEvent(_eventAfterVisit);
}
// draw the notifications node //绘制观察节点,如果你需要在场景中设立观察节点,请调用摄像机的setNotificationNode函数
if (_notificationNode)
{
_notificationNode->visit(_renderer, Mat4::IDENTITY, false);
}
//绘制屏幕左下角的状态
if (_displayStats)
{
showStats();
}
//开始渲染
_renderer->render();
_eventDispatcher->dispatchEvent(_eventAfterDraw);
popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
_totalFrames++;
// swap buffers
if (_openGLView)
{
_openGLView->swapBuffers();
}
//计算绘制时间
if (_displayStats)
{
calculateMPF();
}
}