cocos2d-x 框架深入分析 - MainLoop

本文详细介绍了作者在学习游戏开发过程中使用Cocos2d-x引擎的经历,包括如何在底层框架中实现游戏的渲染循环,通过分析主循环代码,了解了时间差计算、场景绘制及帧率控制的关键步骤。文章还探讨了Cocos2d-x引擎中重要组件的作用,为游戏开发者提供了一次深入理解游戏开发底层机制的机会。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

学习游戏开发也有3个月了,其中也做一个安卓的原创游戏(2D游戏,目前没有接触到3D游戏),之前没有接触过游戏引擎,游戏的一些简单的物理效果都是自己写,cocos2d-x是我第一次接触游戏引擎,下载源码后就开始深入源码去学习,学习别人更好的思想,也在寻找在设计上和自己做的有什么异同点。记录下我现在所看到的,了解到的。废话不多说,我现在看的版本是cocos2d-2.1rc0-x-2.1.2。 
做个游戏的应该都知道,我们的游戏一般是在一个死循环中渲染的,比如下面: 
复制代码
  1. float dt;
  2. while (1)
  3. {
  4. ...
  5. update(dt); //通过时间差更新数据
  6. present(dt);//通过时间差呈现、绘制游戏画面
  7. ...
  8. }
所以我首先在底层源代码中寻找这个样子的东东。(注:我是用VS在WIN32平台下查看) 

首先打开 ...\cocos2d-2.1rc0-x-2.1.2\samples\Cpp\TestCpp\proj.win32\main.cpp 
复制代码
  1. int APIENTRY _tWinMain(HINSTANCE hInstance,
  2. HINSTANCE hPrevInstance,
  3. LPTSTR lpCmdLine,
  4. int nCmdShow)
  5. {
  6. UNREFERENCED_PARAMETER(hPrevInstance);
  7. UNREFERENCED_PARAMETER(lpCmdLine);
  8. // create the application instance
  9. AppDelegate app; //实例化应用代理对象,这个对象是CCApplication的子类,
  10. //实现了applicationDidFinishLaunching()等方法,目的
  11. //目的是为了在底层框架中回调,做一些初始化或者结尾的工作
  12. CCEGLView* eglView = CCEGLView::sharedOpenGLView();//继承和封装了一些对Opengl接口的操作。不同平台实现不一样
  13. eglView->setViewName("TestCpp");
  14. eglView->setFrameSize(480, 320);
  15. return CCApplication::sharedApplication()->run();//一个单实例类,通过run方法进入引擎主循环
  16. }
这里就是程序的主入口,没有什么好说的,唯一注意的就是AppDelegate类在这里被实例化了。接着进入 CCApplication::run(); 
...\cocos2d-2.1rc0-x-2.1.2\cocos2dx\platform\win32\CCApplication.cpp 
复制代码
  1. int CCApplication::run()
  2. {
  3. ......
  4. // Initialize instance and cocos2d.
  5. if (!applicationDidFinishLaunching())//AppDelegate的回调方法,主要就是初始化CCDirector等数据,方便显示第一个场景
  6. {
  7. return 0;
  8. }
  9. ......
  10. while (1)
  11. {
  12. if (! PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  13. {
  14. // Get current time tick.
  15. QueryPerformanceCounter(&nNow);
  16. // If it's the time to draw next frame, draw it, else sleep a while.
  17. if (nNow.QuadPart - nLast.QuadPart > m_nAnimationInterval.QuadPart)//判断时间差是不是达到了到下一帧的条件
  18. { //主要是看锁定多少的FPS
  19. nLast.QuadPart = nNow.QuadPart;
  20. CCDirector::sharedDirector()->mainLoop();//进入引擎的主循环
  21. }
  22. else
  23. {
  24. Sleep(0);
  25. }
  26. continue;
  27. }
  28. ......
  29. }
  30. return (int) msg.wParam;
  31. }
在这里省去了一些平台有关的代码,主要是WIN32平台的窗口消息的获取等,还有一些计算时间的代码。在这个循环中,只要达到渲染要求,就进入CCDirector::sharedDirector()->mainLoop();代码中,把处理交给引擎自己去完成。接着进入。。。 
...\cocos2d-2.1rc0-x-2.1.2\cocos2dx\CCDirector.cpp 
复制代码
  1. void CCDisplayLinkDirector::mainLoop(void)
  2. {
  3. if (m_bPurgeDirecotorInNextLoop)//进入下一个主循环,也就是结束这次的主循环,就净化,也就是一些后期处理
  4. {
  5. m_bPurgeDirecotorInNextLoop = false;
  6. purgeDirector();
  7. }
  8. else if (! m_bInvalid)
  9. {
  10. drawScene();//绘制屏幕
  11. // release the objects
  12. CCPoolManager::sharedPoolManager()->pop();//释放一些没有用的对象,主要保件内存的合理管理
  13. }
  14. }
CCDisplayLinkDirector是CCDisplay的子类,从命名就应该可以很清晰的知道它的用处。通过CCDirector::sharedDirector()代码,得到的都是CCDisplayLinkDirector对象。通过drawScene()代码就可以实现场景的绘制了。而开篇我要寻找的那个东东,也就在里面了。。。 
...\cocos2d-2.1rc0-x-2.1.2\cocos2dx\CCDirector.cpp 
复制代码
  1. void CCDirector::drawScene(void)
  2. {
  3. // calculate "global" dt
  4. calculateDeltaTime();//计算时间差
  5. //tick before glClear: issue #533
  6. if (! m_bPaused) //如果不暂停,就更新数据
  7. {
  8. m_pScheduler->update(m_fDeltaTime);//调度者对象,是整个框架中,非常重要的东东,他负责者引擎中精灵、动作等的调度
  9. //而里面所用的数据结构的组织,一定程度决定者引擎的效率。
  10. }
  11. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  12. /* to avoid flickr, nextScene MUST be here: after tick and before draw.
  13. XXX: Which bug is this one. It seems that it can't be reproduced with v0.9 */
  14. if (m_pNextScene)
  15. {
  16. setNextScene();//如果有m_pNextScene对象不为空,就说明需要调用到新的场景中,
  17. //在其中onEnter()、onEnterTransitionDidFinish()等函数被回调。
  18. }
  19. kmGLPushMatrix();//opengl:把当前矩阵放到栈中
  20. // draw the scene
  21. if (m_pRunningScene)
  22. {
  23. m_pRunningScene->visit();//通过访问方法,去绘制场景中包含的每个层和每个层中的每个节点的draw,
  24. //这里面是一个递归的过程,其中transform()方法实现,opengl矩阵的变化 //,移动,旋转等。
  25. }
  26. // draw the notifications node
  27. if (m_pNotificationNode)
  28. {
  29. m_pNotificationNode->visit();//绘制通知节点,目前我也不知道这个是什么!
  30. }
  31. if (m_bDisplayStats)
  32. {
  33. showStats();
  34. }
  35. kmGLPopMatrix();//opengl:把当前矩阵从栈中移除,回复之前的矩阵
  36. m_uTotalFrames++;//记录总帧数
  37. // swap buffers
  38. if (m_pobOpenGLView)
  39. {
  40. m_pobOpenGLView->swapBuffers();//opengl:交换帧缓冲区,把绘制的东东显示在屏幕。
  41. }
  42. if (m_bDisplayStats)
  43. {
  44. calculateMPF();
  45. }
  46. }
好了,到目前为止,我们看到了,我们想看到的东东,开心了,第一次写博文,记录下自己的成长路,今天放假,玩去。。。 未来记下引擎核心之一的CCScheduler的工作方式和里面所用到的数据结构。 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值