做个游戏的应该都知道,我们的游戏一般是在一个死循环中渲染的,比如下面:

  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.            {                                                                                                                                   <span style="white-space:pre">                                                                        </span>//主要是看锁定多少的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矩阵的变化<span style="white-space:pre">                                                                </span>//,移动,旋转等。

  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的工作方式和里面所用到的数据结构。