cocos2d-x源码剖析之整体框架


     刚阅读完了cocos2d-x的大部分源码,感觉受益匪浅,cocos2d-x的代码并不复杂,可读性很强,并且其中一部分精华的部分也可以运用到工作中去,相得益彰。现在看来,阅读源代码的最好方式是top-down的方式,先弄懂整个框架,再重点突破重要和感兴趣的模块。废话少说,先看看coscos2d-x的框架是怎样的,如何运行起来。
     先让我们看看测试用例TestCpp中的主函数,也是整个Win32程序的入口。

int APIENTRY _tWinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPTSTR    lpCmdLine,
                       int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);


// create the application instance
AppDelegate app;
CCEGLView* eglView = CCEGLView::sharedOpenGLView();
eglView->setViewName("TestCpp");
eglView->setFrameSize(480, 320);
return CCApplication::sharedApplication()->run();
}
     这个入口有2个非常重要的类CCEGLView和CCApplication,在整个程序中都是单例。
      先看看CCEGLView
     CCEGLView是用来管理窗口和绘制。在 CCEGLView::Create中做了如下大家非常熟悉的事情
    1. RegisterClass注册窗口,其中非常重要的消息处理函数CCEGLView::_WindowProc就是在整个地方定义的。整个游戏中的窗口的键盘、鼠标消息响应就可以在这个函数中进行处理。
    2. initGL初始化OpenGL引擎.
    m_hDC = GetDC(m_hWnd);
    SetupPixelFormat(m_hDC);
    //SetupPalette();
   m_hRC = wglCreateContext(m_hDC);
   wglMakeCurrent(m_hDC, m_hRC);
   CCEGLView::initGL中设置了像素的格式,创建了OpenGL的RenderContext,OpenGL最终渲染的结果会显示到该窗口的DC上。
    再看看CCApplication
    CCApplication是用来管理程序的逻辑,最后一句CCApplication::sharedApplication()->run()整个程序就开始高速运转起来了。刚开始看代码的时候有一个疑问:
CCApplication* CCApplication::sharedApplication()
{
    CC_ASSERT(sm_pSharedApplication);
    return sm_pSharedApplication;
}
  这个函数中的sm_pSharedApplication是在什么地方初始化的呢?聪明的你很快就会发现其实前面有一个AppDelegate app,AppDelegate是Application的子类,在这个子类的构造函数中声明了这个全局唯一的静态变量。
CCApplication::CCApplication()
: m_hInstance(NULL)
, m_hAccelTable(NULL)
{
m_hInstance    = GetModuleHandle(NULL);
m_nAnimationInterval.QuadPart = 0;
CC_ASSERT(! sm_pSharedApplication);
sm_pSharedApplication = this;
}
 由此Application的单例也有了。Application::Run()做了什么呢,让整个程序运行起来了呢?
int CCApplication::run()
{
    PVRFrameEnableControlWindow(false);


    // Main message loop:
    MSG msg;
    LARGE_INTEGER nFreq;
    LARGE_INTEGER nLast;
    LARGE_INTEGER nNow;

    QueryPerformanceFrequency(&nFreq);
    QueryPerformanceCounter(&nLast);

    // Initialize instance and cocos2d.
    if (!applicationDidFinishLaunching())
    {
        return 0;
    }

    CCEGLView* pMainWnd = CCEGLView::sharedOpenGLView();
    pMainWnd->centerWindow();
    ShowWindow(pMainWnd->getHWnd(), SW_SHOW);

    while (1)
    {
        if (! PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            // Get current time tick.
            QueryPerformanceCounter(&nNow);

            // If it's the time to draw next frame, draw it, else sleep a while.
            if (nNow.QuadPart - nLast.QuadPart > m_nAnimationInterval.QuadPart)
            {
                nLast.QuadPart = nNow.QuadPart;
                CCDirector::sharedDirector()->mainLoop();
            }
            else
            {
                Sleep(0);
            }
            continue;
        }

        if (WM_QUIT == msg.message)
        {
            // Quit message loop.
            break;
        }

        // Deal with windows message.
        if (! m_hAccelTable || ! TranslateAccelerator(msg.hwnd, m_hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}
先跳过applicationDidFinishLaunching()部分(这部分和测试用例有关系),可以看到在while主循环中做了两件事:
  1. 转发窗口消息,交给之前定义的CCEGLView::_WindowProc进行处理
  2. 每隔m_nAnimationInterval.QuadPart时间,也就是游戏的一帧,进行一次处理.
这里就引出了最重要的一个类CCDirector即导演类,这个类也是一个单例,负责整个游戏场景管理,逻辑更新以及绘制。那让我们看看
CCDirector::sharedDirector()->mainLoop()的每帧的mainLoop都做了啥事情:
    CCDirector的帧常工作:
void CCDisplayLinkDirector::mainLoop(void)
{
    if (m_bPurgeDirecotorInNextLoop)
    {
        m_bPurgeDirecotorInNextLoop = false;
        purgeDirector();
    }
    else if (! m_bInvalid)
     {
         drawScene();
     
         // release the objects
         CCPoolManager::sharedPoolManager()->pop();        
     }
}
 导演类的的每帧做的最重要的事情就是drawScene,
void CCDirector::drawScene(void)
{
    ......
    if (! m_bPaused)
    {
        m_pScheduler->update(m_fDeltaTime);
    }
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    // draw the scene
    if (m_pRunningScene)
    {
        m_pRunningScene->visit();
    }
    // swap buffers
    if (m_pobOpenGLView)
    {
        m_pobOpenGLView->swapBuffers();
    }
}

读者仔细看看就会发现这个函数做了两个方面的工作,:

       1.  更新调度器m_pScheduler,比如场景中的动作等,后面的博文会详细的分析

        2.  绘制场景中的对象结点,树形的方式

        至此,cocos2d-x的整体框架就非常清晰的摆在我们面前了,后面就开始解剖麻雀了^_^

你可能感兴趣的:(游戏,cocos2d-x)