@H_403_1@先把上一篇忘记分析的autorelease说一下,在CCDirector.cpp的主循环有
@H_403_1@voID displaylinkDirector::mainLoop()@H_404_6@ {@H_404_6@ if (_purgeDirectorInNextLoop)@H_404_6@ {@H_404_6@ _purgeDirectorInNextLoop = false;@H_404_6@ purgeDirector();@H_404_6@ }@H_404_6@ else if (! _invalID)@H_404_6@ {@H_404_6@ drawScene();@H_404_6@ @H_404_6@ // release the objects@H_404_6@ PoolManager::getInstance()->getCurrentPool()->clear();@H_404_6@ }@H_404_6@ }@H_404_6@
@H_403_1@显然表明了在每一帧结束的时候会进行PoolManager的一个清理工作,而通过CCRef.cpp可知道当进行autorelease的时候会把对象放入autoreleasePool的verctor里面,所以调用了autorelease的对象会在一帧结束的时候调用了release的 *** 作,即把引用计数减为0,然后会进行delete的 *** 作,把对象给释放掉。
@H_403_1@cocos是一个跨平台的游戏引擎,有必要分析一下cocos的启动流程,这里主要分析一下Win32的启动流程,其他平台的大同小异。
@H_403_1@分析Win32的启动流程,首先要找到win32的应用入口,即通常说的main函数。
@H_403_1@在新建的工程里面有一个main.cpp的文件,
@H_403_1@int APIENTRY _tWinMain(HINSTANCE hInstance,@H_404_6@ HINSTANCE hPrevInstance,@H_404_6@ LPTSTR lpCmdline,@H_404_6@ int nCmdshow)@H_404_6@ {@H_404_6@ UNREFERENCED_ParaMETER(hPrevInstance);@H_404_6@ UNREFERENCED_ParaMETER(lpCmdline);@H_404_6@ @H_404_6@ @H_404_6@ // create the application instance@H_404_6@ AppDelegate app;@H_404_6@ return Application::getInstance()->run();@H_404_6@ }@H_404_6@
@H_403_1@显然这就是Win32的入口。显然接下来要分析一下Application的内容:
@H_403_1@先浏览一下头文件的内容
@H_403_1@//CCApplication.h
@H_403_1@#ifndef __CC_APPliCATION_WIN32_H__@H_404_6@ #define __CC_APPliCATION_WIN32_H__@H_404_6@ #include "base/CCPlatformConfig.h"@H_404_6@ #if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32@H_404_6@ #include "CCStdC.h"@H_404_6@ #include "platform/CCCommon.h"@H_404_6@ #include "platform/CCApplicationProtocol.h"@H_404_6@ #include <string>@H_404_6@ NS_CC_BEGIN@H_404_6@ class Rect;@H_404_6@ class CC_DLL Application : public ApplicationProtocol@H_404_6@ {@H_404_6@ public:@H_404_6@ /**@H_404_6@ * @Js ctor@H_404_6@ */@H_404_6@ Application();@H_404_6@ /**@H_404_6@ * @Js NA@H_404_6@ * @lua NA@H_404_6@ */@H_404_6@ virtual ~Application();@H_404_6@ @H_404_6@ /**@H_404_6@ @brIEf Run the message loop.@H_404_6@ */@H_404_6@ int run();@H_404_6@ @H_404_6@ /**@H_404_6@ @brIEf Get current applicaiton instance.@H_404_6@ @return Current application instance pointer.@H_404_6@ */
@H_403_1@//说明是采用单例模式实现的@H_404_6@ static Application* getInstance();@H_404_6@ @H_404_6@ /** @deprecated Use getInstance() instead */
@H_403_1@//被废除的函数@H_404_6@ CC_DEPRECATED_ATTRIBUTE static Application* sharedApplication();@H_404_6@ @H_404_6@ /* overrIDe functions */@H_404_6@ virtual voID setAnimationInterval(double interval);@H_404_6@ virtual LanguageType getCurrentLanguage();@H_404_6@ virtual const char * getCurrentLanguageCode();@H_404_6@ /**@H_404_6@ @brIEf Get target platform@H_404_6@ */@H_404_6@ virtual Platform getTargetPlatform();@H_404_6@ @H_404_6@ @H_404_6@ /**@H_404_6@ * Sets the Resource root path.@H_404_6@ * @deprecated Please use fileUtils::getInstance()->setSearchPaths() instead.@H_404_6@ */@H_404_6@ CC_DEPRECATED_ATTRIBUTE voID setResourceRootPath(const std::string& rootResDir);@H_404_6@ @H_404_6@ @H_404_6@ /**@H_404_6@ * Gets the Resource root path.@H_404_6@ * @deprecated Please use fileUtils::getInstance()->getSearchPaths() instead.@H_404_6@ */@H_404_6@ CC_DEPRECATED_ATTRIBUTE const std::string& getResourceRootPath(voID);@H_404_6@ @H_404_6@ @H_404_6@ voID setStartupScriptfilename(const std::string& startupScriptfile);@H_404_6@ @H_404_6@ @H_404_6@ const std::string& getStartupScriptfilename(voID)@H_404_6@ {@H_404_6@ return _startupScriptfilename;@H_404_6@ }@H_404_6@ protected:@H_404_6@ HINSTANCE _instance;@H_404_6@ HACCEL _acceltable;@H_404_6@ LARGE_INTEGER _animationInterval;@H_404_6@ std::string _resourceRootPath;@H_404_6@ std::string _startupScriptfilename;@H_404_6@ @H_404_6@ static Application * sm_pSharedApplication;@H_404_6@ };@H_404_6@ NS_CC_END@H_404_6@ #endif // CC_TARGET_PLATFORM == CC_PLATFORM_WIN32@H_404_6@ #endif // __CC_APPliCATION_WIN32_H__
@H_403_1@在来看一下具体的实现:
@H_403_1@\\CCApplication.cpp
@H_403_1@#include "base/CCPlatformConfig.h"
@H_403_1@//限定是Win32平台@H_404_6@ #if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32@H_404_6@ #include "CCApplication.h"@H_404_6@ #include "CCGLVIEw.h"@H_404_6@ #include "base/CCDirector.h"@H_404_6@ #include <algorithm>@H_404_6@ #include "platform/CCfileUtils.h"@H_404_6@ /**@H_404_6@ @brIEf This function change the PVRFrame show/hIDe setting in register.@H_404_6@ @param bEnable If true show the PVRFrame window,otherwise hIDe.@H_404_6@ */@H_404_6@ static voID PVRFrameEnableControlWindow(bool bEnable);@H_404_6@ @H_404_6@ @H_404_6@ NS_CC_BEGIN@H_404_6@ @H_404_6@ @H_404_6@ // sharedApplication pointer@H_404_6@ Application * Application::sm_pSharedApplication = 0;@H_404_6@ @H_404_6@ //构造函数@H_404_6@ Application::Application()@H_404_6@ : _instance(nullptr)@H_404_6@,_acceltable(nullptr)@H_404_6@ {@H_404_6@ _instance = GetModuleHandle(nullptr);@H_404_6@ _animationInterval.QuadPart = 0;@H_404_6@ CC_ASSERT(! sm_pSharedApplication);@H_404_6@ sm_pSharedApplication = this;@H_404_6@ }@H_404_6@ @H_404_6@ //析构函数,令sm_pSharedApplication的值为Null,猜测是为了防止野指针@H_404_6@ Application::~Application()@H_404_6@ {@H_404_6@ CC_ASSERT(this == sm_pSharedApplication);@H_404_6@ sm_pSharedApplication = NulL;@H_404_6@ }@H_404_6@ @H_404_6@ \\主要的内容,主要分析一下@H_404_6@ int Application::run()@H_404_6@ {
@H_403_1@//这个函数是一些关于注册表的 *** 作,大致的 *** 作就是向注册表注册一些内容@H_404_6@ PVRFrameEnableControlWindow(false);@H_404_6@ // Main message loop:@H_404_6@ LARGE_INTEGER nFreq;@H_404_6@ LARGE_INTEGER nLast;@H_404_6@ LARGE_INTEGER nNow;@H_404_6@ @H_404_6@ //这两个也是windows的接口函数,是精确到毫秒级的计时器函数@H_404_6@ queryPerformanceFrequency(&nFreq);@H_404_6@ queryPerformanceCounter(&nLast);@H_404_6@ @H_404_6@ //这里回调用工程里面的ApplIDegrate.cpp的函数然后可以在里面进入游戏的场景@H_404_6@ // Initialize instance and cocos2d.@H_404_6@ if (!applicationDIDFinishLaunching())@H_404_6@ {@H_404_6@ return 0;@H_404_6@ }@H_404_6@ @H_404_6@ auto director = Director::getInstance();@H_404_6@ auto glvIEw = director->getopenGLVIEw();@H_404_6@ //对glvIEw进行retain *** 作,防止被释放掉@H_404_6@ // Retain glvIEw to avoID glvIEw being released in the while loop@H_404_6@ glvIEw->retain();@H_404_6@ //判断窗口是否关掉@H_404_6@ while(!glvIEw->windowshouldClose())@H_404_6@ {
@H_403_1@//计时器判断两次执行的间隔是否大于设置的更新频率,如果大于进入游戏的主循环,如果小于则调用Sleep(0),查了相关的资料,知道如果当前的cpu有大于当前优先级的线程,则会调用优先级大的线程,否则继续当前线程的 *** 作,所以如果两帧的间隔小于设置的函数,则会判断如果有大于当前线程的优先级的线程,则调用优先级大的函数,否则继续当前的线程@H_404_6@ queryPerformanceCounter(&nNow);@H_404_6@ if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart)@H_404_6@ {@H_404_6@ nLast.QuadPart = nNow.QuadPart;@H_404_6@ //CCDirecotr的主循环,稍后分析@H_404_6@ director->mainLoop();@H_404_6@ glvIEw->pollEvents();@H_404_6@ }@H_404_6@ else@H_404_6@ {@H_404_6@ Sleep(0);@H_404_6@ }@H_404_6@ }@H_404_6@ //跳出循环后,判断当前的opengl是否准备好,进行清理的工作@H_404_6@ // Director should still do a cleanup if the window was closed manually.@H_404_6@ if (glvIEw->isOpenglready())@H_404_6@ {@H_404_6@ director->end();@H_404_6@ director->mainLoop();@H_404_6@ director = nullptr;@H_404_6@ }
@H_403_1@//释放glvIEw@H_404_6@ glvIEw->release();@H_404_6@ return true;@H_404_6@ }@H_404_6@ //设置更新的间隔@H_404_6@ voID Application::setAnimationInterval(double interval)@H_404_6@ {@H_404_6@ LARGE_INTEGER nFreq;@H_404_6@ queryPerformanceFrequency(&nFreq);@H_404_6@ _animationInterval.QuadPart = (LONGLONG)(interval * nFreq.QuadPart);@H_404_6@ }@H_404_6@ @H_404_6@ //////////////////////////////////////////////////////////////////////////@H_404_6@ // static member function@H_404_6@ //////////////////////////////////////////////////////////////////////////
@H_403_1@//获得Application的实例,采用了单例模式@H_404_6@ Application* Application::getInstance()@H_404_6@ {@H_404_6@ CC_ASSERT(sm_pSharedApplication);@H_404_6@ return sm_pSharedApplication;@H_404_6@ }@H_404_6@ //废弃了的函数,此处不做分析了@H_404_6@ // @deprecated Use getInstance() instead@H_404_6@ Application* Application::sharedApplication()@H_404_6@ {@H_404_6@ return Application::getInstance();@H_404_6@ }
@H_403_1@//获得当前使用的语言@H_404_6@ LanguageType Application::getCurrentLanguage()@H_404_6@ {@H_404_6@ LanguageType ret = LanguageType::ENGliSH;@H_404_6@ @H_404_6@ @H_404_6@ LCID localeID = GetUserDefaultLCID();@H_404_6@ unsigned short primaryLanguageID = localeID & 0xFF;@H_404_6@ @H_404_6@ switch (primaryLanguageID)@H_404_6@ {@H_404_6@ case LANG_CHInesE:@H_404_6@ ret = LanguageType::CHInesE;@H_404_6@ break;@H_404_6@ case LANG_ENGliSH:@H_404_6@ ret = LanguageType::ENGliSH;@H_404_6@ break;@H_404_6@ case LANG_french:@H_404_6@ ret = LanguageType::french;@H_404_6@ break;@H_404_6@ case LANG_ITAliAN:@H_404_6@ ret = LanguageType::ITAliAN;@H_404_6@ break;@H_404_6@ case LANG_GERMAN:@H_404_6@ ret = LanguageType::GERMAN;@H_404_6@ break;@H_404_6@ case LANG_SPANISH:@H_404_6@ ret = LanguageType::SPANISH;@H_404_6@ break;@H_404_6@ case LANG_DUTCH:@H_404_6@ ret = LanguageType::DUTCH;@H_404_6@ break;@H_404_6@ case LANG_RUSSIAN:@H_404_6@ ret = LanguageType::RUSSIAN;@H_404_6@ break;@H_404_6@ case LANG_KOREAN:@H_404_6@ ret = LanguageType::KOREAN;@H_404_6@ break;@H_404_6@ case LANG_JAPAnesE:@H_404_6@ ret = LanguageType::JAPAnesE;@H_404_6@ break;@H_404_6@ case LANG_HUNGARIAN:@H_404_6@ ret = LanguageType::HUNGARIAN;@H_404_6@ break;@H_404_6@ case LANG_PORTUGUESE:@H_404_6@ ret = LanguageType::PORTUGUESE;@H_404_6@ break;@H_404_6@ case LANG_araBIC:@H_404_6@ ret = LanguageType::araBIC;@H_404_6@ break;@H_404_6@ case LANG_norWEGIAN:@H_404_6@ ret = LanguageType::norWEGIAN;@H_404_6@ break;@H_404_6@ case LANG_POliSH:@H_404_6@ ret = LanguageType::POliSH;@H_404_6@ break;@H_404_6@ }@H_404_6@ return ret;@H_404_6@ }@H_404_6@ //获得当前使用语言的代码@H_404_6@ const char * Application::getCurrentLanguageCode()@H_404_6@ {@H_404_6@ LANGID lID = GetUserDefaultUILanguage();@H_404_6@ const LCID locale_ID = MAKELCID(lID,SORT_DEFAulT);@H_404_6@ static char code[3] = { 0 };@H_404_6@ GetLocaleInfoA(locale_ID,LOCALE_SISO639LANGname,code,sizeof(code));@H_404_6@ code[2] = '\0';@H_404_6@ return code;@H_404_6@ }@H_404_6@ //返回平台@H_404_6@ Application::Platform Application::getTargetPlatform()@H_404_6@ {@H_404_6@ return Platform::OS_windows;@H_404_6@ }@H_404_6@ //设置资源的路径,以后分析CCfileUtils的时候在分析@H_404_6@ voID Application::setResourceRootPath(const std::string& rootResDir)@H_404_6@ {@H_404_6@ _resourceRootPath = rootResDir;@H_404_6@ std::replace(_resourceRootPath.begin(),_resourceRootPath.end(),'\\','/');@H_404_6@ if (_resourceRootPath[_resourceRootPath.length() - 1] != '/')@H_404_6@ {@H_404_6@ _resourceRootPath += '/';@H_404_6@ }@H_404_6@ fileUtils* pfileUtils = fileUtils::getInstance();@H_404_6@ std::vector<std::string> searchPaths = pfileUtils->getSearchPaths();@H_404_6@ searchPaths.insert(searchPaths.begin(),_resourceRootPath);@H_404_6@ pfileUtils->setSearchPaths(searchPaths);@H_404_6@ }@H_404_6@ //获得资源的根路径@H_404_6@ const std::string& Application::getResourceRootPath(voID)@H_404_6@ {@H_404_6@ return _resourceRootPath;@H_404_6@ }@H_404_6@ //设置脚本的启动名字,以后分析脚本的时候在分析@H_404_6@ voID Application::setStartupScriptfilename(const std::string& startupScriptfile)@H_404_6@ {@H_404_6@ _startupScriptfilename = startupScriptfile;@H_404_6@ std::replace(_startupScriptfilename.begin(),_startupScriptfilename.end(),'/');@H_404_6@ }@H_404_6@ NS_CC_END@H_404_6@ //////////////////////////////////////////////////////////////////////////@H_404_6@ // Local function@H_404_6@ //////////////////////////////////////////////////////////////////////////
@H_403_1@//这个函数就是设置注册表的实现函数,暂时对注册表不太熟悉,不做具体分析,猜测就是对注册表做一些写入的 *** 作@H_404_6@ static voID PVRFrameEnableControlWindow(bool bEnable)@H_404_6@ {@H_404_6@ HKEY hKey = 0;@H_404_6@ // Open PVRFrame control key,if not exist create it.@H_404_6@ if(ERROR_SUCCESS != RegCreateKeyExW(HKEY_CURRENT_USER,@H_404_6@ L"Software\\Imagination TechnologIEs\\PVRVFRame\\STARTUP\\",@H_404_6@ 0,@H_404_6@ REG_OPTION_NON_VolATILE,@H_404_6@ KEY_ALL_ACCESS,@H_404_6@ &hKey,@H_404_6@ NulL))@H_404_6@ {@H_404_6@ return;@H_404_6@ }@H_404_6@ const WCHAR* wszValue = L"hIDe_gui";@H_404_6@ const WCHAR* wszNewData = (bEnable) ? L"NO" : L"YES";@H_404_6@ WCHAR wszoldData[256] = {0};@H_404_6@ DWORD DWSize = sizeof(wszoldData);@H_404_6@ LSTATUS status = RegqueryValueExW(hKey,wszValue,NulL,(LPBYTE)wszoldData,&DWSize);@H_404_6@ if (ERROR_file_NOT_FOUND == status // the key not exist@H_404_6@ || (ERROR_SUCCESS == status // or the hIDe_gui value is exist@H_404_6@ && 0 != wcscmp(wszNewData,wszoldData))) // but new data and old data not equal@H_404_6@ {@H_404_6@ DWSize = sizeof(WCHAR) * (wcslen(wszNewData) + 1);@H_404_6@ RegSetValueEx(hKey,REG_SZ,(const BYTE *)wszNewData,DWSize);@H_404_6@ }@H_404_6@ RegCloseKey(hKey);@H_404_6@ }@H_404_6@ #endif // CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
@H_403_1@applicationDIDFinishLaunching这个函数是@H_403_1@ApplicationProtocol的纯虚函数,然后Appdelegate继承Application并实现了这个函数,显然调用此函数时,进入了Appdelegate.cpp里面的applicationDIDFinishLaunching的函数,这是面向对象的三大特性的多态的体现了。@H_404_6@
@H_403_1@从以上的分析可以知道,还有两个文件比较重要,一个是Appdelegate.cpp和CCDirector.cpp
@H_403_1@分别贴出这两个文件
@H_403_1@\\Appdelegate.h
@H_403_1@#ifndef _APP_DELEGATE_H_@H_404_6@ #define _APP_DELEGATE_H_@H_404_6@ @H_404_6@ @H_404_6@ #include "cocos2d.h"@H_404_6@ @H_404_6@ @H_404_6@ /**@H_404_6@ @brIEf The cocos2d Application.@H_404_6@ @H_404_6@ @H_404_6@ The reason for implement as private inheritance is to hIDe some interface call by Director.@H_404_6@ */@H_404_6@ class AppDelegate : private cocos2d::Application@H_404_6@ {@H_404_6@ public:@H_404_6@ AppDelegate();@H_404_6@ virtual ~AppDelegate();@H_404_6@ /**@H_404_6@ @brIEf Implement Director and Scene init code here.@H_404_6@ @return true Initialize success,app continue.@H_404_6@ @return false Initialize Failed,app terminate.@H_404_6@ */@H_404_6@ virtual bool applicationDIDFinishLaunching();@H_404_6@ /**@H_404_6@ @brIEf The function be called when the application enter background@H_404_6@ @param the pointer of the application@H_404_6@ */@H_404_6@ virtual voID applicationDIDEnterBackground();@H_404_6@ /**@H_404_6@ @brIEf The function be called when the application enter foreground@H_404_6@ @param the pointer of the application@H_404_6@ */@H_404_6@ virtual voID applicationWillEnterForeground();@H_404_6@ };@H_404_6@ #endif // _APP_DELEGATE_H_@H_404_6@
@H_403_1@\\标出红色的函数就是实现了虚函数,这就是抽象的体现了,跨平台抽象了接口,但是具体的实现就依据不同的平台不同的实现。我们在applicationDIDFinishLaunching@H_403_1@里面做的就是第一个场景的出现了,然后就进入了游戏,很简单,参考一下工程就明白了。接下来分析CCDirector.cpp文件,因为我们这里只用到了两个函数,我们在这里主要分析他们:end,mainLoop,
@H_403_1@//实例化的时候返回了Director的子类,displaylinkDirector的实例,所以调用的是displaylinkDirector::mainLoop()
@H_403_1@@H_403_1@Director* Director::getInstance()@H_404_6@ {@H_404_6@ if (!s_SharedDirector)@H_404_6@ {@H_404_6@ s_SharedDirector = new displaylinkDirector();@H_404_6@ s_SharedDirector->init();@H_404_6@ }@H_404_6@ return s_SharedDirector;@H_404_6@ }@H_404_6@
@H_403_1@@H_403_1@voID displaylinkDirector::mainLoop()@H_404_6@ {
@H_403_1@@H_403_1@//判断是否清除导演类,即游戏是否停止@H_404_6@ if (_purgeDirectorInNextLoop)@H_404_6@ {@H_404_6@ _purgeDirectorInNextLoop = false;@H_404_6@ purgeDirector();@H_404_6@ }@H_404_6@ else if (! _invalID)@H_404_6@ {
@H_403_1@@H_403_1@//游戏的渲染,具体下次分析游戏的渲染的时候在分析@H_404_6@ drawScene();@H_404_6@ //这个就是本文首先提到的对于autorelease对象,会在此时进行清理的工作@H_404_6@ // release the objects@H_404_6@ PoolManager::getInstance()->getCurrentPool()->clear();@H_404_6@ }@H_404_6@ }
@H_403_1@@H_403_1@今天的分析暂时到这里,下一次打算分析一下cocos的渲染。本文纯属个人分析学习,如果有不当之处,请大神指教一下!
总结以上是内存溢出为你收集整理的cocos3.1源码分析(1)-------cocos的启动分析(Win32平台)全部内容,希望文章能够帮你解决cocos3.1源码分析(1)-------cocos的启动分析(Win32平台)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)