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

cocos2d-x: 死磕"HelloWorld"(3)——游戏运行主函数run()

2014-07-05 07:37 507 查看
在该篇中,我们将分析游戏运行主函数run(),看看它都干了些啥。并且会重点分析其中调用的两个函数:即应用初始化函数applicationDidFinishLaunching()和渲染主循环函数mainLoop()。但是这两个函数所调用的更为细节的函数将放在后续篇章中分析。一次分析两层函数应该是可以接受的,多了就晕了。现在我们就来一顿run()函数的庐山真面:
CCApplication.cpp
int CCApplication::run()
{
PVRFrameEnableControlWindow(false);//设置和获取注册表信息.

// Main message loop:
MSG msg;//创建消息对象
LARGE_INTEGER nFreq;
LARGE_INTEGER nLast;
LARGE_INTEGER nNow;
//创建三个大整数对象(大整数定义详解请移步博主另一博文[1])。这三大整数用于记录程序运行过程中两个事件的时间间隔。下面两个函数便是它们的赋值函数。

QueryPerformanceFrequency(&nFreq);//把windows高精度定时器的时钟频率传递给nFreq对象。
QueryPerformanceCounter(&nLast);//把定时器当前计数传递给 nLast。后面还会再次调用该函数,把定时器计数传递给nNow。这样一来,我们便分别获得了两个事件发生时定时器的计数,这两个计数之差nNow.QuadPart-nLast.QuadPart便是这两个事件的间隔计数(即事件间隔内时钟的振荡次数),把间隔计数除以时钟频率nFreq.QuadPart便是间隔时间。这种计时方法可以达到很高的精度。

// Initialize instance and cocos2d.
if (!applicationDidFinishLaunching())//applicationDidFinishLaunching()用于对实例进行初始化。我们马上会详解该函数。
{
return 0;
}

CCEGLView* pMainWnd = CCEGLView::sharedOpenGLView();//创建一个视窗类对象。由于sharedOpenGLView()采用单例模式,所以该对象即为之前在applicationDidFinishLaunching()里创建的那个视窗对象(见下面对applicationDidFinishLaunching()的分析)。
pMainWnd->centerWindow();//将该窗口居中
ShowWindow(pMainWnd->getHWnd(), SW_SHOW);//显示窗口

while (1)//渲染死循环
{
if (! PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))//先调用一个API函数PeekMessage。如果无法获得当前窗口(第二个参数为被检查的窗口句柄,如果为NULL,则为当前窗口)的消息,则PeekMessage返回值为零,条件判断为真,允许执行语块内代码。
{
// Get current time tick.
QueryPerformanceCounter(&nNow);//读取定时器当前计数传递给nNow。

// If it's the time to draw next frame, draw it, else sleep a while.
if (nNow.QuadPart - nLast.QuadPart > m_nAnimationInterval.QuadPart)//如果当前计数和上一个计数之差大于某一设定值 m_nAnimationInterval则进入mainLoop()开始渲染,并且更新定时器计数, 否则将当前线程挂起,挂起时间在该例中为0秒,相当于没挂。然后continue进入下一个渲染循环,跳过后面的两个条件语句。
{
nLast.QuadPart = nNow.QuadPart;
CCDirector::sharedDirector()->mainLoop();
}
else
{
Sleep(0);
}
continue;
}

if (WM_QUIT == msg.message)//如果消息结构体中的message成员等于退出编码,则退出循环。在这里我们可以大胆猜测按下HelloWorld窗口中的关闭按钮,会导致消息结构体中的message成员等于退出编码,从而退出循环。这一猜测可以通过在break处设置断点进行验证。至于细节我们会在本节末再次讨论。
{
// 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()

CCDelegate.cpp
bool AppDelegate::applicationDidFinishLaunching() {
// initialize director
CCDirector* pDirector = CCDirector::sharedDirector();//创建一个导演对象,并初始化。所谓初始化即对其成员数据赋值。
CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();//创建一个视窗类对象,并初始化。

pDirector->setOpenGLView(pEGLView);//把视窗对象指针传递给导演。注意setOpenGLView(CCEGLView *pobOpenGLView)里的m_pobOpenGLView = pobOpenGLView。
CCSize frameSize = pEGLView->getFrameSize();//获取窗口大小。

// Set the design resolution //设置分辨率。
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
pEGLView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, kResolutionShowAll);
#else
pEGLView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, kResolutionNoBorder);
#endif

vector<string> searchPath; //声明路径字符串

// In this demo, we select resource according to the frame's height.
// If the resource size is different from design resolution size, you need to set contentScaleFactor.
// We use the ratio of resource's height to the height of design resolution,
// this can make sure that the resource's height could fit for the height of design resolution.

//根据窗口大小选择图片路径和缩放比例。
// if the frame's height is larger than the height of medium resource size, select large resource.
if (frameSize.height > mediumResource.size.height)
{
searchPath.push_back(largeResource.directory);

pDirector->setContentScaleFactor(MIN(largeResource.size.height/designResolutionSize.height, largeResource.size.width/designResolutionSize.width));
}
// if the frame's height is larger than the height of small resource size, select medium resource.
else if (frameSize.height > smallResource.size.height)
{
searchPath.push_back(mediumResource.directory);

pDirector->setContentScaleFactor(MIN(mediumResource.size.height/designResolutionSize.height, mediumResource.size.width/designResolutionSize.width));
}
// if the frame's height is smaller than the height of medium resource size, select small resource.
else
{
searchPath.push_back(smallResource.directory);

pDirector->setContentScaleFactor(MIN(smallResource.size.height/designResolutionSize.height, smallResource.size.width/designResolutionSize.width));
}

// set searching path
CCFileUtils::sharedFileUtils()->setSearchPaths(searchPath); //设置搜索路径。

// 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); //设置渲染间隔。该间隔先传给m_dAnimationInterval,后传给m_nAnimationInterval.

// create a scene. it's an autorelease object
CCScene *pScene = HelloWorld::scene(); //创建一个HelloWorld场景。对于单纯的游戏制作者而言,这是重头戏。我们将在第四篇中详解该函数。
// run
pDirector->runWithScene(pScene); //渲染准备函数,我们将在第五篇中详解该函数。

return true;
}除了窗口和路径设置之外,导演指挥一切。初始化若成功则返回值为真,否则为假。当返回值为真时,则继续run(),否则退出整个程序。

下面就来看重点之二,渲染主循环函数mainLoop()。该函数是导演类的成员函数。

CCDirector.cpp
void CCDisplayLinkDirector::mainLoop(void)
{
if (m_bPurgeDirecotorInNextLoop)
{
m_bPurgeDirecotorInNextLoop = false;
purgeDirector();
}
else if (! m_bInvalid)
{
drawScene();

// release the objects
CCPoolManager::sharedPoolManager()->pop();
}
}

假如导演类数据成员m_bPurgeDirecotorInNextLoop为真,则将其设为假,并且调用purgeDirector(),停止并关闭渲染窗口。如果m_bPurgeDirecotorInNextLoop为假,并且m_bInvalid也为假(从CCDisplayLinkDirector构造中看出其初始值为假)时,调用渲染场景函数drawScene()进行渲染,渲染完调用sharedPoolManager()->pop()释放内存。

至此,我们对run()的内容也有了个了解。它主要就是利用applicationDidFinishLaunching()创建了一个导演,一个窗口和一个HelloWorld场景,然后利用一个死循环和mainLoop对该场景进行渲染。

还有个遗留问题是关闭键如何关闭程序。它调用了一个HelloWold类里的回调函数menuCloseCallback(CCObject* pSender)。该回调函数又调用了导演类的end()函数。该end()函数的功能很简单就是把导演类的成员数据m_bPurgeDirecotorInNextLoop设为真,因此当渲染循环再次进入到mainLoop()里时,便会调用purgeDirector(),停止并关闭渲染窗口。当程序进入下一渲染循环时,PeekMessage的返回值为真,条件判断为假,因此直接进入第二个条件判断语句。此时消息符合退出编码,因此执行break,退出渲染循环。

引文:

[1] http://blog.csdn.net/u014078216/article/details/24401421
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: