cocos2d-x引擎结构
在不同平台下,cocos2d-x的入口是不一样的,在win32平台,程序是从_tWinMain()开始的,可以在每一个cocos2d-x的程序中的main.cpp中找到。
1.程序入口(1)在_tWinMain()中,创建的AppDelegate类的对象(PS:AppDelegate继承于CCApplication,在构造方法中,初始化CCApplication单例类的唯一实例)
(2)随后,程序就完全交给了cocos2d-x引擎去处理代码如下:
[cpp]viewplaincopyprint?<spanstyle="font-size:14px;">intAPIENTRY_tWinMain(HINSTANCEhInstance,
HINSTANCEhPrevInstance,
LPTSTRlpCmdLine,
intnCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
//createtheapplicationinstance
AppDelegateapp;
returncocos2d::CCApplication::sharedApplication().run();//注意这里
}</span>
[cpp]viewplaincopyprint?intCCApplication::run()
{
PVRFrameEnableControlWindow(false);
//Mainmessageloop:
MSGmsg;
LARGE_INTEGERnFreq;
LARGE_INTEGERnLast;
LARGE_INTEGERnNow;
QueryPerformanceFrequency(&nFreq);
QueryPerformanceCounter(&nLast);
//Initializeinstanceandcocos2d.
if(!applicationDidFinishLaunching())
{
return0;
}
CCEGLView*pMainWnd=CCEGLView::sharedOpenGLView();
pMainWnd->centerWindow();
ShowWindow(pMainWnd->getHWnd(),SW_SHOW);
while(1)//注意这里,主循环来了
{
if(!PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
//Getcurrenttimetick.
QueryPerformanceCounter(&nNow);
//Ifit'sthetimetodrawnextframe,drawit,elsesleepawhile.
if(nNow.QuadPart-nLast.QuadPart>m_nAnimationInterval.QuadPart)
{
nLast.QuadPart=nNow.QuadPart;
CCDirector::sharedDirector()->mainLoop();//看看这是神马
}
else
{
Sleep(0);
}
continue;
}
if(WM_QUIT==msg.message)
{
//Quitmessageloop.
break;
}
//Dealwithwindowsmessage.
if(!m_hAccelTable||!TranslateAccelerator(msg.hwnd,m_hAccelTable,&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return(int)msg.wParam;
}
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;}
不熟悉windows的童鞋估计都知道windows是消息驱动的。这个死循环就是用来处理windows的消息循环的,在其中处理了FPS逻辑,消息分发等。注意看其中红色标标注的[cpp]viewplaincopyprint?
CCDirector::sharedDirector()->mainLoop();
CCDirector::sharedDirector()->mainLoop();
这是神马东西啊!这个就是cocos2d-x的主循环了,由导演负责维护。从此就进入了cocos2d-x的世界,跟windows没有一毛钱关系了。
intAPIENTRY_tWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPTSTRlpCmdLine,intnCmdShow){UNREFERENCED_PARAMETER(hPrevInstance);UNREFERENCED_PARAMETER(lpCmdLine);//createtheapplicationinstanceAppDelegateapp;returncocos2d::CCApplication::sharedApplication().run();}
(PS:cocos2d-x中有很多这样的用法,即同一个头文件,在不同平台上实现不同)
win32平台下的CCEGLView是一个windows窗口,具体情况CCEGLView::sharedOpenGLView();
(PS:CCEGLView还用来处理鼠标点击模拟器触摸,按键等事件的处理,如果要自定义,请参看CCEGLView::WindowProc(),这个函数是Windows程序接收消息回调)
(2)游戏引擎的主循环在完成CCEGLView初始化之后,将开启游戏渲染的主循环,即调用CCDirector::sharedDirector()->mainLoop()。这样,程序就又交给CCDirector类来处理,CCDirector主要处理两件事情:
a.通过引用计数实现对内存的管理b.游戏内元素的渲染[cpp]viewplaincopyprint?<spanstyle="font-size:14px;">voidCCDisplayLinkDirector::mainLoop(void)
{
if(m_bPurgeDirecotorInNextLoop)
{
purgeDirector();
m_bPurgeDirecotorInNextLoop=false;
}
elseif(!m_bInvalid)
{
drawScene();
//releasetheobjects
CCPoolManager::getInstance()->pop();
}
}</span>
voidCCDisplayLinkDirector::mainLoop(void){if(m_bPurgeDirecotorInNextLoop){purgeDirector();m_bPurgeDirecotorInNextLoop=false;}elseif(!m_bInvalid){drawScene();//releasetheobjectsCCPoolManager::getInstance()->pop();}}3.渲染
在cocos2d中渲染的根节点是CCScene(PS:CCScene也是CCNode的子类),但是在drawScene()中似乎没有类似draw()的方法,那是因为在渲染之前,要对游戏中的节点做一些处理,包括旋转,缩放等等,所以这个方法的名字叫visit(),而visit()是定义在CCNode中的虚方法,CCScene中并没有单独实现。
(PS:在每一次渲染的时候,都需要先将之前的矩阵入栈,在渲染完当前节点之后,矩阵出栈,恢复之前的矩阵)
(1)矩阵变化通过CCNode::transform()对当前节点做矩阵处理(包括旋转,缩放等等)
(2)绘制绘制就很简单了,遍历所有的子节点,采用递归的方式,对每一个CCNode调用visit()方法
(PS:设置Z-Order的时候可以设置为负值,有时候是很必要的,比如我们以一个人物精灵的身体为位置参照物,绘制在Z-Order为0的位置上,如果要给这个人物精灵添加一个披风耍帅,就可以将披风的Z-Order设置为负值,并且可以继续以精灵身体作为参照物,因为cocos2d-x提供的访问顺序也是Z-Order为负值的子节点->自身节点->Z-Order为正值的子节点)
[cpp]viewplaincopyprint?<spanstyle="font-size:14px;">if(m_pChildren&&m_pChildren->count()>0)
{
//drawchildrenzOrder<0
ccArray*arrayData=m_pChildren->data;
for(;i<arrayData->num;i++)
{
pNode=(CCNode*)arrayData->arr[i];
if(pNode&&pNode->m_nZOrder<0)
{
pNode->visit();
}
else
{
break;
}
}
}
//selfdraw
this->draw();
//drawchildrenzOrder>=0
if(m_pChildren&&m_pChildren->count()>0)
{
ccArray*arrayData=m_pChildren->data;
for(;i<arrayData->num;i++)
{
pNode=(CCNode*)arrayData->arr[i];
if(pNode)
{
pNode->visit();
}
}
}</span>
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。