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

从HelloApp看一个cocos2d-x程序是怎么启动的

2013-09-13 22:17 344 查看
初学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里多加一些游戏元素;等等。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: