任何程序都有入口,mian.cpp; Cocos2d也不免俗,在win32平台下,有一个mian.cpp 入口,从这里进入cocos的世界。
#ifndef __MAIN_H__ #define __MAIN_H__ //WIN32_LEAN_AND_MEAN 是WINDOWS API用于屏蔽一些不常用的API(优化应用程序)才用的。 #define WIN32_LEAN_AND_MEAN // 从Windows头文件中排除不常用的内容 // Windows 头文件: #include <windows.h> #include <tchar.h> // C 运行时的头文件: #include "platform/CCStdC.h" #endif // __MAIN_H__main.h
#include "main.h" #include "../Classes/AppDelegate.h" USING_NS_CC; int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { //以上参数为windows的Api 日后再说 //我们从 UNREFERENCED_PARAMETER 开始吧。这个宏在 winnt.h 中定义如下: //#define UNREFERENCED_PARAMETER(P) (P) //换句话说 UNREFERENCED_PARAMETER 展开传递的参数或表达式,其目的是避免编译器关于未引用参数的警告 UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); //创建新的App实例 AppDelegate app; //getInstance 单实例模式 获取其实例 运行 由此进入 AppDelegate类 return Application::getInstance()->run(); }
在main.cpp中我们可以看到仅仅声明了AppDelegate.h,却使用了run()方法,于是进入AppDelegate.h类中:
class AppDelegate : private cocos2d::Application
发现其继承于Application,全局搜索Application,在libcocos2d/win32/CCApplication-win32.h 找到了它,查看它的头文件:
class CC_DLL Application : public ApplicationProtocol
发现继承于ApplicationProtocol,再次进入ApplicationProtocol类中查看,
#ifndef __CC_APPLICATION_PROTOCOL_H__ #define __CC_APPLICATION_PROTOCOL_H__ #include "platform/CCPlatformMacros.h" #include "base/CCAutoreleasePool.h" #include "base/ccTypes.h" NS_CC_BEGIN /** * @addtogroup platform * @{ */ class CC_DLL ApplicationProtocol { public: /** Since WINDOWS and ANDROID are defined as macros, we could not just use these keywords in enumeration(Platform). * Therefore, 'OS_' prefix is added to avoid conflicts with the definitions of system macros. */ enum class Platform { OS_WINDOWS, /**< Windows */ OS_LINUX, /**< Linux */ OS_MAC, /**< Mac OS X*/ OS_ANDROID, /**< Android */ OS_IPHONE, /**< iPhone */ OS_IPAD, /**< iPad */ OS_BLACKBERRY, /**< BlackBerry */ OS_NACL, /**< Native Client in Chrome */ OS_EMSCRIPTEN, /**< Emscripten */ OS_TIZEN, /**< Tizen */ OS_WINRT, /**< Windows Runtime Applications */ OS_WP8 /**< Windows Phone 8 Applications */ }; /** * @js NA * @lua NA */ virtual ~ApplicationProtocol(){ /** clean auto release pool. */ PoolManager::destroyInstance(); } /** * @brief Implement Director and Scene init code here. * @return true Initialize success, app continue. * @return false Initialize failed, app terminate. * @js NA * @lua NA */ virtual bool applicationDidFinishLaunching() = 0; /** * @brief This function will be called when the application enters background. * @js NA * @lua NA */ virtual void applicationDidEnterBackground() = 0; /** * @brief This function will be called when the application enters foreground. * @js NA * @lua NA */ virtual void applicationWillEnterForeground() = 0; /** * @brief Callback by Director for limit FPS. * @param interval The time, expressed in seconds, between current frame and next. * @js NA * @lua NA */ virtual void setAnimationInterval(float interval) = 0; virtual void setAnimationInterval(float interval, SetIntervalReason reason) = 0; /** Subclass override the function to set OpenGL context attribution instead of use default value. * And now can only set six attributions:redBits,greenBits,blueBits,alphaBits,depthBits,stencilBits. * Default value are(5,6,5,0,16,0), usually use as follows: * void AppDelegate::initGLContextAttrs(){ * GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8}; * GLView::setGLContextAttrs(glContextAttrs); * } */ virtual void initGLContextAttrs() {} /** @brief Get current language config. @return Current language config. * @js NA * @lua NA */ virtual LanguageType getCurrentLanguage() = 0; /** @brief Get current language iso 639-1 code. @return Current language iso 639-1 code. * @js NA * @lua NA */ virtual const char * getCurrentLanguageCode() = 0; /** @brief Get target platform. * @js NA * @lua NA */ virtual Platform getTargetPlatform() = 0; /** @brief Get application version. * @js NA * @lua NA */ virtual std::string getVersion() = 0; /** @brief Open url in default browser. @param String with url to open. @return True if the resource located by the URL was successfully opened; otherwise false. * @js NA * @lua NA */ virtual bool openURL(const std::string &url) = 0; }; // end of platform group /** @} */ NS_CC_END #endif // __CC_APPLICATION_PROTOCOL_H__
在这个类中,首先是定义了各个平台的枚举变量,其他的都是虚函数,在不同平台下,不同的类继承这些接口实现跨平台,来到了父类,接下来去实现这些虚方法的win32子类去看一下,在头文件中看它的一些方法声明:
#ifndef __CC_APPLICATION_WIN32_H__ #define __CC_APPLICATION_WIN32_H__ #include "platform/CCPlatformConfig.h" #if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 #include "platform/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获取当前的应用程序实例。 @return当前应用程序实例指针。 */ static Application* getInstance(); /** @deprecated Use getInstance() instead */ CC_DEPRECATED_ATTRIBUTE static Application* sharedApplication(); /* override functions */ virtual void setAnimationInterval(float interval) override; virtual void setAnimationInterval(float interval, SetIntervalReason reason) override; virtual LanguageType getCurrentLanguage(); virtual const char * getCurrentLanguageCode(); /** @brief Get target platform */ virtual Platform getTargetPlatform(); /** @brief Get application version */ virtual std::string getVersion() override; /** @brief在默认浏览器中打开网址 @param打开url的字符串。 如果成功打开了URL所在的资源,则@return为true;否则是假的。 */ virtual bool openURL(const std::string &url); /** *设置资源根路径。 * @deprecated请改用FileUtils :: getInstance() - > setSearchPaths()。 */ 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__
从上往下看,第一个函数是:
int run();
它的注释仅仅是:运行消息循环。 进入这个函数发现它做的事情不简单,代码如下:
UINT TARGET_RESOLUTION = 1; // 1毫秒的目标分辨率 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); }
经过查阅资料,弄明白这段首先是更改了window下的计时器的精度,调整为1毫秒;
initGLContextAttrs();
初始化OpenGL属性;
if (!applicationDidFinishLaunching()) { return 1; }
初始化cocos实例,成功继续,不成功返回1;
while(!glview->windowShouldClose()) { QueryPerformanceCounter(&nNow); interval = nNow.QuadPart - nLast.QuadPart; if (interval >= _animationInterval.QuadPart) { nLast.QuadPart = nNow.QuadPart; director->mainLoop(); glview->pollEvents(); } else { waitMS = (_animationInterval.QuadPart - interval) * 1000LL / freq.QuadPart - 1L; if (waitMS > 1L) Sleep(waitMS); } }
这一段所做的事情,就是一个死循环,不停的调用 director->mainLoop(); glview->pollEvents(); 看了注释,和之后的代码,就是不停的刷新,并且在win平台上加了个保护,因为win平台的调度器精度缺失,放在下一帧给cpu处理;
if (glview->isOpenGLReady()) { director->end(); director->mainLoop(); director = nullptr; } glview->release();
if (wTimerRes != 0) { timeEndPeriod(wTimerRes); }
这两个就是关闭显示和主循环,win调度器。
看完run()函数,接下来一看就是个单实例模式:
static Application* getInstance();
在实现中也是获取Application的唯一实例;
virtual void setAnimationInterval(float interval) override; virtual void setAnimationInterval(float interval, SetIntervalReason reason) override;
这两个是FPS的函数;紧接着几个获取当前语言类型,平台类型,当前版本,打开网址链接的函数
CC_DEPRECATED_ATTRIBUTE void setResourceRootPath(const std::string& rootResDir);
设置根资源路径,我们在代码中使用FileUtils :: getInstance()->setSearchPaths()代替,就是搜索你的代码和资源的路径;
CC_DEPRECATED_ATTRIBUTE const std::string& getResourceRootPath(void);
获取路径;
void setStartupScriptFilename(const std::string& startupScriptFile);
设置开始脚本名字,这个由于没有使用脚本文件,没有仔细去看;
整个循环到这里也差不多了,进入后台,和进入前台代码并没有分析,在上一节的目录结构就能发现,每一个平台都有一个自己对应的工程,现在发现了一个ApplicationProtocol的父类,每个平台有自己不同的Application来实现对应的方法驱动整个程序,在其中调用run()方法实现启动,在这个引擎中最重要的 Director Layer Scene Sprite 这几个类,他们之间存在这层级关系,之后可以一级一级的去看。