您的位置:首页 > 移动开发 > Cocos引擎

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

2013-08-24 20:46 316 查看
刚阅读完了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的整体框架就非常清晰的摆在我们面前了,后面就开始解剖麻雀了^_^
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: