首先看一下HelloWorld的项目结构:
找到入口函数,代码如下:
主要是两行代码:
我们在去看看Application::getInstance():
这个函数中的sm_pSharedApplication是在什么地方初始化的呢?我们先来看一下AppDelegate和Application的关系:
原来AppDelegate是Application的子类。我们再来看Application的构造函数:
构造函数中声明了这个全局唯一的静态变量。
由此Application的单例也有了。Application::Run()做了什么呢,让整个程序运行起来了呢?
int Application::run()
{
PVRFrameEnableControlWindow(false);
///
/// changing timer resolution
///
UINT TARGET_RESOLUTION = 1; // 1 millisecond target resolution
TIMECAPS tc;
UINT wTimerRes = 0;
if (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof(TIMECAPS)))
{
wTimerRes = std::min(std::max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax);
timeBeginPeriod(wTimerRes);
}
// Main message loop:
LARGE_INTEGER nLast;
LARGE_INTEGER nNow;
QueryPerformanceCounter(&nLast);
initGLContextAttrs();
// Initialize instance and cocos2d.
if (!applicationDidFinishLaunching())
{
return 1;
}
auto director = Director::getInstance();
auto glview = director->getOpenGLView();
// Retain glview to avoid glview being released in the while loop
glview->retain();
LONGLONG interval = 0LL;
LONG waitMS = 0L;
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
while(!glview->windowShouldClose())
{
QueryPerformanceCounter(&nNow);
interval = nNow.QuadPart - nLast.QuadPart;
if (interval >= _animationInterval.QuadPart)
{
nLast.QuadPart = nNow.QuadPart;
director->mainLoop();
glview->pollEvents();
}
else
{
// The precision of timer on Windows is set to highest (1ms) by 'timeBeginPeriod' from above code,
// but it's still not precise enough. For example, if the precision of timer is 1ms,
// Sleep(3) may make a sleep of 2ms or 4ms. Therefore, we subtract 1ms here to make Sleep time shorter.
// If 'waitMS' is equal or less than 1ms, don't sleep and run into next loop to
// boost CPU to next frame accurately.
waitMS = (_animationInterval.QuadPart - interval) * 1000LL / freq.QuadPart - 1L;
if (waitMS > 1L)
Sleep(waitMS);
}
}
// Director should still do a cleanup if the window was closed manually.
if (glview->isOpenGLReady())
{
director->end();
director->mainLoop();
director = nullptr;
}
glview->release();
///
/// restoring timer resolution
///
if (wTimerRes != 0)
{
timeEndPeriod(wTimerRes);
}
return 0;
}
在这个run方法里我们着重分析applicationDidFinishLaunching和while循环。
现在看一下applicationDidFinishLaunching的实现:
bool AppDelegate::applicationDidFinishLaunching()
{
// initialize director
auto director = Director::getInstance();
auto glview = director->getOpenGLView();
if(!glview) {
glview = GLViewImpl::create("Cpp Empty Test");
glview->setFrameSize(1364, 368);
director->setOpenGLView(glview);
}
director->setOpenGLView(glview);
// Set the design resolution
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::NO_BORDER);
Size frameSize = glview->getFrameSize();
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);
director->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);
director->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);
director->setContentScaleFactor(MIN(smallResource.size.height/designResolutionSize.height, smallResource.size.width/designResolutionSize.width));
}
// set searching path
FileUtils::getInstance()->setSearchPaths(searchPath);
// Uncomment follow block to use localize manager to set localize strings
// If you want to load json localize data, use follow block
/*
cocostudio::ILocalizationManager * lm = cocostudio::JsonLocalizationManager::getInstance();
lm->initLanguageData("your localize file name.lang.json");
cocostudio::LocalizationHelper::setCurrentManager(lm, false);
*/
// If you want to load binary localize data, use follow block
/*
cocostudio::ILocalizationManager * lm = cocostudio::BinLocalizationManager::getInstance();
lm->initLanguageData("your localize file name.lang.csb");
cocostudio::LocalizationHelper::setCurrentManager(lm, true);
*/
// to enable VR, uncomment the following lines
// auto vrImpl = new VRGenericRenderer;
// glview->setVR(vrImpl);
// turn on display FPS
director->setDisplayStats(true);
// set FPS. the default value is 1.0/60 if you don't call this
director->setAnimationInterval(1.0f / 60);
// create a scene. it's an autorelease object
auto scene = HelloWorld::scene();
// run
director->runWithScene(scene);
return true;
}
通过代码里的注释我们可以知道在这里面主要做了initialize director、Set the design resolution、set select resource、set searching path、create a scene....
重点是这两句:
这段代码创建了一个HelloWorld的场景(Scene),然后这个场景作为了director
的方法runWithScene
的参数。
我们在回到Application的run方法分析while循环,可以看到在while循环中反复地调用director
的mainLoop
方法,下面我们的目标自然要到mainLoop
中看个究竟:
我们现在着重看最后一个if
,主要做了两件事:drawScene
和clear
到此我们大概能够明白,coco2d-x的游戏主循环中,会不停地进行场景的渲染和资源的清理,至于渲染的细节和如何进行资源的清理,我们后面再讲。