上一篇文章中有一个在栈中创建的实例——AppDelegate,这个类的初始化使cocos2d-x的程序可以运行起来。因为它是继承于CCApplication类,而运行的run方法就是在此类中实现的。
class CC_DLL CCApplication : public CCApplicationProtocol
{
public:
CCApplication();
virtual ~CCApplication();
/**
@brief Run the message loop.
*/
virtual int run();
/**
@brief Get current applicaiton instance.
@return Current application instance pointer.
*/
static CCApplication* sharedApplication();
/* override functions */
virtual void setAnimationInterval(double interval);
virtual ccLanguageType getCurrentLanguage();
/**
@brief Get target platform
*/
virtual TargetPlatform getTargetPlatform();
/**
* Sets the Resource root path.
* @deprecated Please use CCFileUtils::sharedFileUtils()->setSearchPaths() instead.
*/
CC_DEPRECATED_ATTRIBUTE void setResourceRootPath(const std::string& rootResDir);
/**
* Gets the Resource root path.
* @deprecated Please use CCFileUtils::sharedFileUtils()->getSearchPaths() instead.
*/
CC_DEPRECATED_ATTRIBUTE const std::string& getResourceRootPath(void);
void setStartupScriptFilename(const std::string& startupScriptFile);
const std::string& getStartupScriptFilename(void)
{
return m_startupScriptFilename;
}
protected:
HINSTANCE m_hInstance;
HACCEL m_hAccelTable;
LARGE_INTEGER m_nAnimationInterval;
std::string m_resourceRootPath;
std::string m_startupScriptFilename;
static CCApplication * sm_pSharedApplication;
};
NS_CC_END
#endif // __CC_APPLICATION_WIN32_H__
可以看到,CCApplication是继承自于CCApplicationProtocol,CCApplicationProtocol是个纯虚类,生命了程序启动,切到后台,后台唤醒等函数。
class CC_DLL CCApplicationProtocol
{
public:
virtual ~CCApplicationProtocol() {}
/**
@brief Implement CCDirector and CCScene init code here.
@return true Initialize success, app continue.
@return false Initialize failed, app terminate.
*/
//游戏第一次运行时被调用,用于初始场景和加载场景
virtual bool applicationDidFinishLaunching() = 0;
/**
@brief The function be called when the application enter background
@param the pointer of the application
*/
//当游戏进入后台时被调用。
virtual void applicationDidEnterBackground() = 0;
/**
@brief The function be called when the application enter foreground
@param the pointer of the application
*/
//从后台被唤醒时调用。
virtual void applicationWillEnterForeground() = 0;
/**
@brief Callback by CCDirector for limit FPS.
@interval The time, expressed in seconds, between current frame and next.
*/
//设置帧数
virtual void setAnimationInterval(double interval) = 0;
/**
@brief Get current language config
@return Current language config
*/
//获取语言
virtual ccLanguageType getCurrentLanguage() = 0;
/**
@brief Get target platform
*/
//获取运行的平台
virtual TargetPlatform getTargetPlatform() = 0;
};
而CCApplication只实现了setAnimationInterval,getCurrentLanguage和getTargetPlatform三个函数,另外三个交给CCApplication的子类,也就是AppDelegate来实现。如下代码所示:
class AppDelegate : private cocos2d::CCApplication
{
public:
AppDelegate();
virtual ~AppDelegate();
/**
@brief Implement CCDirector and CCScene init code here.
@return true Initialize success, app continue.
@return false Initialize failed, app terminate.
*/
virtual bool applicationDidFinishLaunching();
/**
@brief The function be called when the application enter background
@param the pointer of the application
*/
virtual void applicationDidEnterBackground();
/**
@brief The function be called when the application enter foreground
@param the pointer of the application
*/
virtual void applicationWillEnterForeground();
};
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;
}
// This function will be called when the app is inactive. When comes a phone call,it's be invoked too
void AppDelegate::applicationDidEnterBackground() {
CCDirector::sharedDirector()->stopAnimation();
// if you use SimpleAudioEngine, it must be pause
// SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic();
}
// this function will be called when the app is active again
void AppDelegate::applicationWillEnterForeground() {
CCDirector::sharedDirector()->startAnimation();
// if you use SimpleAudioEngine, it must resume here
// SimpleAudioEngine::sharedEngine()->resumeBackgroundMusic();
}
其实现很简单。在applicationDidFinishLaunching函数中先初始化导演,设置是否显示FPS,设置帧率,创建场景,加载和运行场景。applicationDidEnterBackground则让导演停止渲染,applicationWillEnterForeground则让导演继续渲染。
上面说到applicationDidFinishLaunching在程序一启动就会被调用,而在main函数中只是创建了一个AppDelegate的实例,而AppDelegate的实例并没有主动调用该方法,那么它的调用肯定是在它的父类在调用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 (!applicationDidFinishLaunching())
{
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;
}
这个函数的主要逻辑是先调用子类的applicationDidFinishLaunching函数,执行创建场景等操作,然后设置窗口,最后将整个拥有权交给导演类的主循环,也就是死循环中的mainLoop函数的调用,当然在调用前还要判断当前的帧率与上一帧的帧率之差是否大于设置的帧率,否则不调用。
总结:从上面的过程可以看出CCApplication类是整个程序的起始控制类,里面执行了让游戏真正跑起来的主循环,其次还定义了整个程序的执行环境。像设置帧率,获取当前的运行平台等。另外,由于CCApplication是个单例共享类,可以在程序中随时获取当前的平台信息,设置/获取资源的根路径等操作。