初學cocos2d-x,照着别人的示例,稍微改了一些很基礎的東西玩玩,例如加些字,加些圖檔啊什麼的。大緻了解了,CCScene是個場景類,是被顯示的:CCDirector是到導演類,控制程式流程;CCLayer是遊戲畫面層類,層上可以放置menu、精靈(遊戲機關)、其他層等遊戲元素。但是我好奇這個程式啟動後的流程到底是怎麼樣的?于是稍微跟蹤了一下。
毫無疑問,先main入手。
AppDelegate app;
CCEGLView* eglView = CCEGLView::sharedOpenGLView();
eglView->setViewName("HelloCpp");
eglView->setFrameSize(480, 320);
return CCApplication::sharedApplication()->run();
和QT差不多,基本main都很簡單,先是建一個app對象,然後啟動app的run()方法。從命名上看,AppDelegate應該是一個繼承于CCApplication的類,而
sharedApplication()
這個靜态函數也定是傳回了app類的指針。轉到AppDelegate.h,一看果然是繼承于CCApplication。然後檢視sharedApplication() 這個函數的定義
CCApplication* CCApplication::sharedApplication()
{
CC_ASSERT(sm_pSharedApplication);
return sm_pSharedApplication;
}
看了下,基本就是assert()一下,然後傳回CCApplication類指針。
到此,思路很簡單,就是建立一個App對象,擷取指針(至于為什麼不直接用,估計是用斷言判斷下指針非空什麼的,提高安全性吧),然後調用app的run()。那麼這個run()裡面到底發生了什麼?
檢視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 (!<span style="color: rgb(255, 0, 0);">applicationDidFinishLaunching()</span>)
{
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;
}
發現了一個AppDelegate類中有定義的函數 applicationDidFinishLaunching()。然後下面的結構,一看就是消息循環了,接收msg,處理msg,windows程式設計也是這個結構,隻不過這個例子比較簡單,隻對一個WM_QUIT做了處理。回過頭來檢視 applicationDidFinishLaunching()這個函數,這函數父類CCApplication并沒有,查了下宗譜,發現原來是爺爺的
class CC_DLL CCApplication : public CCApplicationProtocol
再看這函數的内容
bool AppDelegate::applicationDidFinishLaunching() {
// initialize director
CCDirector* pDirector = CCDirector::sharedDirector();
CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();
pDirector->setOpenGLView(pEGLView);
// turn on display FPS
pDirector->setDisplayStats(true);
// set FPS. the default value is 1.0/60 if you don't call this
pDirector->setAnimationInterval(1.0 / 60);
// create a scene. it's an autorelease object
CCScene *pScene = HelloWorld::scene();
// run
pDirector->runWithScene(pScene);
return true;
}
終于出現了CCDirector、CCScene這些”名“類,也出現了Helloword這個關鍵字,項目裡的另一個類終于出現了。重點在于
CCScene *pScene = HelloWorld::scene();
// run
pDirector->runWithScene(pScene);
這兩句,調用了HelloWorld的一個靜态方法獲得了一個scene,然後director把運作起來了,然後我們就看到了,事情就是這麼簡單。繼續“轉到定義”看scene()這個函數,
CCScene* HelloWorld::scene()
{
// 'scene' is an autorelease object
CCScene *scene = CCScene::create();
// 'layer' is an autorelease object
HelloWorld *layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
建立一個CCScene對象,然後用HelloWorld類的create()函數建立一個“層”,把“層”布置到場景上,傳回給導演用。看了下HelloWorld的定義,發現它的基類也是CCLayer
,粗略一看,沒有create()函數。仔細看,發現一個
CREATE_FUNC(HelloWorld);
點到這個宏上發現正是用這個宏定義這個create()函數,而且還發現這個函數用到了init()函數,正是這個Init()對HelloWorld這個Layer作了修飾,添加了各種圖檔按鈕。
<pre name="code" class="cpp">CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
pMenu->setPosition(CCPointZero);
this->addChild(pMenu, 1);
添加了按鈕
CCLabelTTF* pLabel = CCLabelTTF::create("Hello World", "Arial", 24);
// position the label on the center of the screen
pLabel->setPosition(ccp(origin.x + visibleSize.width/2,
origin.y + visibleSize.height - pLabel->getContentSize().height));
// add the label as a child to this layer
this->addChild(pLabel, 1);
添加圖示
CCSprite* pSprite = CCSprite::create("HelloWorld.png");
// position the sprite on the center of the screen
pSprite->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
// add the sprite as a child to this layer
this->addChild(pSprite, 0);
添加精靈
到此為止,思路基本理清了,故事原來是這樣的:main函數建立了一個app對象并啟動了它的run接口;這個run接口呢,調用了一個AppDelegate從CCApplicationProtocol那裡繼承過來的applicationDidFinishLaunching()接口,在裡面建立一個了導演(CCDirector),并且用HelloWorld的scene()接口建立了一個HelloWorld的場景,用導演把場景運作起來,然後就進入按部就班模式(消息循環)。HelloWorld在建立場景的時候呢,就調用了自己的create函數,create裡生成了那個場景,至于它場景的布置,則是在init()函數裡完成的。
這樣整個流程就大緻清楚了。我可以在run()接口裡對多種消息做處理而不隻是退出;讓導演多做一些控制,而不隻是顯示,顯示也隻是顯示一個scene;在init裡多加一些遊戲元素;等等。