cocos2d-x原始碼剖析之整體框架
阿新 • • 發佈:2019-02-13
剛閱讀完了cocos2d-x的大部分原始碼,感覺受益匪淺,cocos2d-x的程式碼並不複雜,可讀性很強,並且其中一部分精華的部分也可以運用到工作中去,相得益彰。現在看來,閱讀原始碼的最好方式是top-down的方式,先弄懂整個框架,再重點突破重要和感興趣的模組。廢話少說,先看看coscos2d-x的框架是怎樣的,如何執行起來。
先讓我們看看測試用例TestCpp中的主函式,也是整個Win32程式的入口。
這個入口有2個非常重要的類CCEGLView和CCApplication,在整個程式中都是單例。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(); }
先看看CCEGLView
CCEGLView是用來管理視窗和繪製。在 CCEGLView::Create中做了如下大家非常熟悉的事情
1. RegisterClass註冊視窗,其中非常重要的訊息處理函式CCEGLView::_WindowProc就是在整個地方定義的。整個遊戲中的視窗的鍵盤、滑鼠訊息響應就可以在這個函式中進行處理。
2. initGL初始化OpenGL引擎.
CCEGLView::initGL中設定了畫素的格式,建立了OpenGL的RenderContext,OpenGL最終渲染的結果會顯示到該視窗的DC上。m_hDC = GetDC(m_hWnd); SetupPixelFormat(m_hDC); //SetupPalette(); m_hRC = wglCreateContext(m_hDC); wglMakeCurrent(m_hDC, m_hRC);
再看看CCApplication
CCApplication是用來管理程式的邏輯,最後一句CCApplication::sharedApplication()->run()整個程式就開始高速運轉起來了。剛開始看程式碼的時候有一個疑問:
這個函式中的sm_pSharedApplication是在什麼地方初始化的呢?聰明的你很快就會發現其實前面有一個AppDelegate app,AppDelegate是Application的子類,在這個子類的建構函式中聲明瞭這個全域性唯一的靜態變數。CCApplication* CCApplication::sharedApplication() { CC_ASSERT(sm_pSharedApplication); return sm_pSharedApplication; }
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的整體框架就非常清晰的擺在我們面前了,後面就開始解剖麻雀了^_^