先把上一篇忘记分析的autorelease说一下,在CCDirector.cpp的主循环有
void DisplayLinkDirector::mainLoop() { if (_purgeDirectorInNextLoop) { _purgeDirectorInNextLoop = false; purgeDirector(); } else if (! _invalid) { drawScene(); // release the objects PoolManager::getInstance()->getCurrentPool()->clear(); } }
显然表明了在每一帧结束的时候会进行PoolManager的一个清理工作,而通过CCRef.cpp可知道当进行autorelease的时候会把对象放入AutoreleasePool的verctor里面,所以调用了autorelease的对象会在一帧结束的时候调用了release的操作,即把引用计数减为0,然后会进行delete的操作,把对象给释放掉。
cocos是一个跨平台的游戏引擎,有必要分析一下cocos的启动流程,这里主要分析一下Win32的启动流程,其他平台的大同小异。
分析Win32的启动流程,首先要找到win32的应用入口,即通常说的main函数。
在新建的工程里面有一个main.cpp的文件,
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); // create the application instance AppDelegate app; return Application::getInstance()->run(); }
显然这就是Win32的入口。显然接下来要分析一下Application的内容:
先浏览一下头文件的内容
//CCApplication.h
#ifndef __CC_APPLICATION_WIN32_H__ #define __CC_APPLICATION_WIN32_H__ #include "base/CCPlatformConfig.h" #if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 #include "CCStdC.h" #include "platform/CCCommon.h" #include "platform/CCApplicationProtocol.h" #include <string> NS_CC_BEGIN class Rect; class CC_DLL Application : public ApplicationProtocol { public: /** * @js ctor */ Application(); /** * @js NA * @lua NA */ virtual ~Application(); /** @brief Run the message loop. */ int run(); /** @brief Get current applicaiton instance. @return Current application instance pointer. */
//说明是采用单例模式实现的 static Application* getInstance(); /** @deprecated Use getInstance() instead */
//被废除的函数 CC_DEPRECATED_ATTRIBUTE static Application* sharedApplication(); /* override functions */ virtual void setAnimationInterval(double interval); virtual LanguageType getCurrentLanguage(); virtual const char * getCurrentLanguageCode(); /** @brief Get target platform */ virtual Platform getTargetPlatform(); /** * Sets the Resource root path. * @deprecated Please use FileUtils::getInstance()->setSearchPaths() instead. */ CC_DEPRECATED_ATTRIBUTE void setResourceRootPath(const std::string& rootResDir); /** * Gets the Resource root path. * @deprecated Please use FileUtils::getInstance()->getSearchPaths() instead. */ CC_DEPRECATED_ATTRIBUTE const std::string& getResourceRootPath(void); void setStartupScriptFilename(const std::string& startupScriptFile); const std::string& getStartupScriptFilename(void) { return _startupScriptFilename; } protected: HINSTANCE _instance; HACCEL _accelTable; LARGE_INTEGER _animationInterval; std::string _resourceRootPath; std::string _startupScriptFilename; static Application * sm_pSharedApplication; }; NS_CC_END #endif // CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 #endif // __CC_APPLICATION_WIN32_H__
在来看一下具体的实现:
CCApplication.cpp
#include "base/CCPlatformConfig.h"
//限定是Win32平台 #if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 #include "CCApplication.h" #include "CCGLView.h" #include "base/CCDirector.h" #include <algorithm> #include "platform/CCFileUtils.h" /** @brief This function change the PVRFrame show/hide setting in register. @param bEnable If true show the PVRFrame window,otherwise hide. */ static void PVRFrameEnableControlWindow(bool bEnable); NS_CC_BEGIN // sharedApplication pointer Application * Application::sm_pSharedApplication = 0; //构造函数 Application::Application() : _instance(nullptr) ,_accelTable(nullptr) { _instance = GetModuleHandle(nullptr); _animationInterval.QuadPart = 0; CC_ASSERT(! sm_pSharedApplication); sm_pSharedApplication = this; } //析构函数,令sm_pSharedApplication的值为Null,猜测是为了防止野指针 Application::~Application() { CC_ASSERT(this == sm_pSharedApplication); sm_pSharedApplication = NULL; } 主要的内容,主要分析一下 int Application::run() {
//这个函数是一些关于注册表的操作,大致的操作就是向注册表注册一些内容 PVRFrameEnableControlWindow(false); // Main message loop: LARGE_INTEGER nFreq; LARGE_INTEGER nLast; LARGE_INTEGER nNow; //这两个也是Windows的接口函数,是精确到毫秒级的计时器函数 QueryPerformanceFrequency(&nFreq); QueryPerformanceCounter(&nLast); //这里回调用工程里面的Applidegrate.cpp的函数然后可以在里面进入游戏的场景 // Initialize instance and cocos2d. if (!applicationDidFinishLaunching()) { return 0; } auto director = Director::getInstance(); auto glview = director->getOpenGLView(); //对glview进行retain操作,防止被释放掉 // Retain glview to avoid glview being released in the while loop glview->retain(); //判断窗口是否关掉 while(!glview->windowShouldClose()) {
//计时器判断两次执行的间隔是否大于设置的更新频率,如果大于进入游戏的主循环,如果小于则调用Sleep(0),查了相关的资料,知道如果当前的CPU有大于当前优先级的线程,则会调用优先级大的线程,否则继续当前线程的操作,所以如果两帧的间隔小于设置的函数,则会判断如果有大于当前线程的优先级的线程,则调用优先级大的函数,否则继续当前的线程 QueryPerformanceCounter(&nNow); if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart) { nLast.QuadPart = nNow.QuadPart; //CCDirecotr的主循环,稍后分析 director->mainLoop(); glview->pollEvents(); } else { Sleep(0); } } //跳出循环后,判断当前的opengl是否准备好,进行清理的工作 // Director should still do a cleanup if the window was closed manually. if (glview->isOpenGLReady()) { director->end(); director->mainLoop(); director = nullptr; }
//释放glview glview->release(); return true; } //设置更新的间隔 void Application::setAnimationInterval(double interval) { LARGE_INTEGER nFreq; QueryPerformanceFrequency(&nFreq); _animationInterval.QuadPart = (LONGLONG)(interval * nFreq.QuadPart); } ////////////////////////////////////////////////////////////////////////// // static member function //////////////////////////////////////////////////////////////////////////
//获得Application的实例,采用了单例模式 Application* Application::getInstance() { CC_ASSERT(sm_pSharedApplication); return sm_pSharedApplication; } //废弃了的函数,此处不做分析了 // @deprecated Use getInstance() instead Application* Application::sharedApplication() { return Application::getInstance(); }
//获得当前使用的语言 LanguageType Application::getCurrentLanguage() { LanguageType ret = LanguageType::ENGLISH; LCID localeID = GetUserDefaultLCID(); unsigned short primaryLanguageID = localeID & 0xFF; switch (primaryLanguageID) { case LANG_CHINESE: ret = LanguageType::CHINESE; break; case LANG_ENGLISH: ret = LanguageType::ENGLISH; break; case LANG_FRENCH: ret = LanguageType::FRENCH; break; case LANG_ITALIAN: ret = LanguageType::ITALIAN; break; case LANG_GERMAN: ret = LanguageType::GERMAN; break; case LANG_SPANISH: ret = LanguageType::SPANISH; break; case LANG_DUTCH: ret = LanguageType::DUTCH; break; case LANG_RUSSIAN: ret = LanguageType::RUSSIAN; break; case LANG_KOREAN: ret = LanguageType::KOREAN; break; case LANG_JAPANESE: ret = LanguageType::JAPANESE; break; case LANG_HUNGARIAN: ret = LanguageType::HUNGARIAN; break; case LANG_PORTUGUESE: ret = LanguageType::PORTUGUESE; break; case LANG_ARABIC: ret = LanguageType::ARABIC; break; case LANG_NORWEGIAN: ret = LanguageType::NORWEGIAN; break; case LANG_POLISH: ret = LanguageType::POLISH; break; } return ret; } //获得当前使用语言的代码 const char * Application::getCurrentLanguageCode() { LANGID lid = GetUserDefaultUILanguage(); const LCID locale_id = MAKELCID(lid,SORT_DEFAULT); static char code[3] = { 0 }; GetLocaleInfoA(locale_id,LOCALE_SISO639LANGNAME,code,sizeof(code)); code[2] = ' '; return code; } //返回平台 Application::Platform Application::getTargetPlatform() { return Platform::OS_WINDOWS; } //设置资源的路径,以后分析CCFileUtils的时候在分析 void Application::setResourceRootPath(const std::string& rootResDir) { _resourceRootPath = rootResDir; std::replace(_resourceRootPath.begin(),_resourceRootPath.end(),'','/'); if (_resourceRootPath[_resourceRootPath.length() - 1] != '/') { _resourceRootPath += '/'; } FileUtils* pFileUtils = FileUtils::getInstance(); std::vector<std::string> searchPaths = pFileUtils->getSearchPaths(); searchPaths.insert(searchPaths.begin(),_resourceRootPath); pFileUtils->setSearchPaths(searchPaths); } //获得资源的根路径 const std::string& Application::getResourceRootPath(void) { return _resourceRootPath; } //设置脚本的启动名字,以后分析脚本的时候在分析 void Application::setStartupScriptFilename(const std::string& startupScriptFile) { _startupScriptFilename = startupScriptFile; std::replace(_startupScriptFilename.begin(),_startupScriptFilename.end(),'/'); } NS_CC_END ////////////////////////////////////////////////////////////////////////// // Local function //////////////////////////////////////////////////////////////////////////
//这个函数就是设置注册表的实现函数,暂时对注册表不太熟悉,不做具体分析,猜测就是对注册表做一些写入的操作 static void PVRFrameEnableControlWindow(bool bEnable) { HKEY hKey = 0; // Open PVRFrame control key,if not exist create it. if(ERROR_SUCCESS != RegCreateKeyExW(HKEY_CURRENT_USER, L"SoftwareImagination TechnologiesPVRVFRameSTARTUP", 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, &hKey, NULL)) { return; } const WCHAR* wszValue = L"hide_gui"; const WCHAR* wszNewData = (bEnable) ? L"NO" : L"YES"; WCHAR wszOldData[256] = {0}; DWORD dwSize = sizeof(wszOldData); LSTATUS status = RegQueryValueExW(hKey,wszValue,NULL,(LPBYTE)wszOldData,&dwSize); if (ERROR_FILE_NOT_FOUND == status // the key not exist || (ERROR_SUCCESS == status // or the hide_gui value is exist && 0 != wcscmp(wszNewData,wszOldData))) // but new data and old data not equal { dwSize = sizeof(WCHAR) * (wcslen(wszNewData) + 1); RegSetValueEx(hKey,REG_SZ,(const BYTE *)wszNewData,dwSize); } RegCloseKey(hKey); } #endif // CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
applicationDidFinishLaunching这个函数是ApplicationProtocol的纯虚函数,然后Appdelegate继承Application并实现了这个函数,显然调用此函数时,进入了Appdelegate.cpp里面的applicationDidFinishLaunching的函数,这是面向对象的三大特性的多态的体现了。
从以上的分析可以知道,还有两个文件比较重要,一个是Appdelegate.cpp和CCDirector.cpp
分别贴出这两个文件
Appdelegate.h
#ifndef _APP_DELEGATE_H_ #define _APP_DELEGATE_H_ #include "cocos2d.h" /** @brief The cocos2d Application. The reason for implement as private inheritance is to hide some interface call by Director. */ class AppDelegate : private cocos2d::Application { public: AppDelegate(); virtual ~AppDelegate(); /** @brief Implement Director and Scene 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(); }; #endif // _APP_DELEGATE_H_
标出红色的函数就是实现了虚函数,这就是抽象的体现了,跨平台抽象了接口,但是具体的实现就依据不同的平台不同的实现。我们在applicationDidFinishLaunching里面做的就是第一个场景的出现了,然后就进入了游戏,很简单,参考一下工程就明白了。接下来分析CCDirector.cpp文件,因为我们这里只用到了两个函数,我们在这里主要分析他们:end,mainLoop,
//实例化的时候返回了Director的子类,DisplayLinkDirector的实例,所以调用的是DisplayLinkDirector::mainLoop()
Director* Director::getInstance() { if (!s_SharedDirector) { s_SharedDirector = new DisplayLinkDirector(); s_SharedDirector->init(); } return s_SharedDirector; }
void DisplayLinkDirector::mainLoop() {
//判断是否清除导演类,即游戏是否停止 if (_purgeDirectorInNextLoop) { _purgeDirectorInNextLoop = false; purgeDirector(); } else if (! _invalid) {
//游戏的渲染,具体下次分析游戏的渲染的时候在分析 drawScene(); //这个就是本文首先提到的对于autorelease对象,会在此时进行清理的工作 // release the objects PoolManager::getInstance()->getCurrentPool()->clear(); } }
今天的分析暂时到这里,下一次打算分析一下cocos的渲染。本文纯属个人分析学习,如果有不当之处,请大神指教一下! (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|