上一篇文章中有一個在棧中創建的實例——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是個單例共享類,可以在程序中隨時獲取當前的平臺信息,設置/獲取資源的根路徑等操作。