cocos2d-x: 死磕"HelloWorld"(3)——游戏运行主函数run()
2014-07-05 07:37
507 查看
在该篇中,我们将分析游戏运行主函数run(),看看它都干了些啥。并且会重点分析其中调用的两个函数:即应用初始化函数applicationDidFinishLaunching()和渲染主循环函数mainLoop()。但是这两个函数所调用的更为细节的函数将放在后续篇章中分析。一次分析两层函数应该是可以接受的,多了就晕了。现在我们就来一顿run()函数的庐山真面:
CCApplication.cpp
下面就来分析一下其中的实例初始化函数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
假如导演类数据成员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
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
相关文章推荐
- cocos2d-x: 死磕"HelloWorld"(6)——场景渲染的实施
- cocos2d-x: 死磕"HelloWorld"(2)——应用实例的创建
- cocos2d-x: 死磕"HelloWorld"(1)——入口函数及其带来的疑问
- cocos2d 游戏开发:Cocos2d v3 "hello world"+显示飞船
- cocos2d-x: 死磕"HelloWorld"(4)——HelloWorld场景的创建
- cocos2d-x: 死磕"HelloWorld"(5)——场景渲染准备工作
- cocos2d 游戏开发:Cocos2d v3 "hello world"+显示飞船
- Perl学习日志(1) — Windows下怎么运行Perl程序显示输出"hello,world"语句
- 1-用线程运行"Hello World"窗体
- Chapter1-怎么在visual studio 2012上运行第一个cocos2d-x项目:Hello World!
- Java自学笔记(第一天)安装Java8---配置运行环境---编写"hello world"程序---注释
- Windows下qt的环境配置及运行一个c++"hello world"实例详细步骤
- "Hello World " —— 深入理解程序从编译到运行
- 编写和运行简单的"Hello World"操作系统内核
- Windows下qt的环境配置及运行一个c++"hello world"实例详细步骤
- Windows下qt的环境配置及运行一个c++"hello world"实例详细步骤
- Windows下qt的环境配置及运行一个c++"hello world"实例详细步骤
- Cocos2d-x简单游戏<打飞机>代码实现|第四部分:主场景<Helloworld.h>
- Windows下qt的环境配置及运行一个c++"hello world"实例详细步骤
- Cocos2d-x--"Hello World"深入分析