Cocos2d-X3.0 刨根问底(二)----- 从HelloWorld开始
小鱼习惯直接从代码实例来学习一套成型的引擎库。
运行cpp-empty-test

一个典型的HelloWorld程序翻看代码结构

看到了 main.h与main.cpp文件就从这里开始
#ifndef __MAIN_H__
#define __MAIN_H__ #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers // Windows Header Files:
#include <windows.h>
#include <tchar.h> // C RunTime Header Files
#include "CCStdC.h" #endif // __MAIN_H__
从这个头文件中没有得到什么有价值的信息,包含了一些库文件,还有一个就是引入了 CCStdC.h 这个文件,从命名上来看应该是Cocos2d-x的标准库头文件,打开来看了几眼,都是一些常用的宏定义,还有就是平台定义,先忽略掉这些信息,继续向下看。
main.cpp
#include "main.h"
#include "../Classes/AppDelegate.h" USING_NS_CC; 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();
}
打开了main.cpp文件我立刻石化了,竟然就有这么几行代码,看来cocos2d-x封装的很牛X啊
这个helloWorld的核心代码就一句 Application::getInstance()->run();
刨根问底我们去了解一下 Application类, 从在这里的调用上来看,整个cocox2d-x都封装在了Application这个类里面每一个应用程序都有唯一的一个Application对象,这种调用明显采用了单例的设计模式,我们跟一下代码,追踪线索。
打开Application.h文件发现
class CC_DLL Application : public ApplicationProtocol
Applilcation类继承了 ApplicationProtocol类, 继续看 ApplicationProtocol.h
CCApplicationProtocol.h
#ifndef __CC_APPLICATION_PROTOCOL_H__
#define __CC_APPLICATION_PROTOCOL_H__ #include "CCPlatformMacros.h" NS_CC_BEGIN 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<span style="white-space:pre"> </span>// 平台种类的一个枚举
{
OS_WINDOWS,
OS_LINUX,
OS_MAC,
OS_ANDROID,
OS_IPHONE,
OS_IPAD,
OS_BLACKBERRY,
OS_NACL,
OS_EMSCRIPTEN,
OS_TIZEN,
OS_WINRT,
OS_WP8
};
virtual ~ApplicationProtocol() {} virtual bool applicationDidFinishLaunching() = ;// 程序启动后的一个回调,应该在这里可以放置一些初始化的操作 virtual void applicationDidEnterBackground() = ;// 程序进入后台时的回调函数,pc中的最小化,手机中的程序转入后台的这个时机调用。 virtual void applicationWillEnterForeground() = ;// 程序又重回前台时的回调 virtual void setAnimationInterval(double interval) = ;// 设置动画两帧之间的时间间隔,也就是常说的帧速度之类的参数 virtual LanguageType getCurrentLanguage() = ;// 应该是和语种相关的,用来做多语言版本时得到当前语言类型参数 可以打开LanguageType看看 virtual const char * getCurrentLanguageCode() = ;// 得到当前语言的编码,返回的是一个字符串,可能是 utf8 gb2312(这里是推测) virtual Platform getTargetPlatform() = ;// 得到当前平台类型 也就是上面定义的枚举,
}; // end of platform group
/// @} NS_CC_END #endif // __CC_APPLICATION_PROTOCOL_H__
这里我把这个文件精简了一下去掉了注释
可以看到ApplicationProtocol是一个抽象类,提供了很多抽象方法,有一个平台类型的定义
enum class Platform
通过这个枚举里面的定义可以了解cocos2d-x所支持的平台各类,还是很全面的,很多小鱼都没用到过。
从纯虚函数的名称上我可以大致猜到这些函数的作用,以注释的形式写到上面代码的后面。
这个类并不复杂,都是定义了一些接口,可以推断,不同平台下的App都要分别继承这个接口来实现不同的处理。
下面我回到 Application 类 一点一点的看,确定Application这个类继承了ApplicationProtocol类
并且在这个头文件上面我看到了这样的一个宏定义
#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
明显这个Application类是为了 Windows平台准备的
下面列出部分代码来分析
NS_CC_BEGIN class Rect; class CC_DLL Application : public ApplicationProtocol
{
public:
Application(); virtual ~Application(); int run(); static Application* getInstance(); CC_DEPRECATED_ATTRIBUTE static Application* sharedApplication(); virtual void setAnimationInterval(double interval);
virtual LanguageType getCurrentLanguage(); virtual const char * getCurrentLanguageCode(); virtual Platform getTargetPlatform(); /**
* Sets the Resource root path.
* @deprecated Please use FileUtils::getInstance()->setSearchPaths() instead.
*/
CC_DEPRECATED_ATTRIBUTE void setResourceRootPath(const std::string& rootResDir); 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
实现父类的几个虚函数我们就不讨论了。
static Application* getInstance();
App是个单例,这是得到app对象的静态方法,不用多说。
int run();
游戏启动及游戏循环肯定在这里了。
我们稍后再进入到run里面看个究竟,先把Application看完整
CC_DEPRECATED_ATTRIBUTE void setResourceRootPath(const std::string& rootResDir);
这个函数肯定是设置资源文件的路径地址的。
void setStartupScriptFilename(const std::string& startupScriptFile);
设置启动脚本,这个肯定是设置启动Lua或者js脚本的地方
Application类小鱼总结一下,这个类也是一个抽象类,因为有些父类的虚函数并没有实现,是针对win32平台下的,如果 想在自己的平台使用应该仿照定义自己的Application类,主要负责启动Cocos2d-x 开发人员应该继承 Application类来定制自己的应用程序。值得学习的是这块Application的封装应用了抽象工厂的设计模式,来满足不同平台的整合
这个HelloWorld示例程序中私人订制的App类为AppDelegate类,我们打开看一下,实现了三个抽象方法.
virtual bool applicationDidFinishLaunching();
virtual void applicationDidEnterBackground();
virtual void applicationWillEnterForeground();
后两个函数主要是在程序前后台运行的时候进行了暂停和恢复暂停的操作,
第一个函数 applicationdidFinishLaunching 进行了一系列初始化。稍后我们再分析它。
至此我们大致分析了Application这个类,看了源码,了解了这个类的作用,那么具体是怎么驱动的呢,我们回过头来看 Application:run()这个函数,这也是helloworld里调用 的唯一一个方法。程序从这个run开始运行。我将分析写入到代码间,这样能方便大家阅读。
int Application::run()
{
PVRFrameEnableControlWindow(false); //跟进函数看到了一些注册表的操作,操作了窗口信息的变量。先过,可以了解到如果自己有些平台性质的全局数据交互可以扩展这里面的代码。 // Main message loop:
LARGE_INTEGER nFreq;
LARGE_INTEGER nLast;
LARGE_INTEGER nNow; QueryPerformanceFrequency(&nFreq);// windows平台得到硬件时钟的频率
QueryPerformanceCounter(&nLast);//记录上一次计时的时间 // Initialize instance and cocos2d.
if (!applicationDidFinishLaunching())//调用上面提到过的私人定制的初始化过程。这也是虚函数的一个应用
{
return ;
} auto director = Director::getInstance();//得到Director类的单例对象,Director类是干什么的先不管,从字面上理解是导演的意思,肯定是一个很重要的类
auto glview = director->getOpenGLView();//可以看出 Director类里封装了关于OPENGL的操作,这里是得到opengl对象 // Retain glview to avoid glview being released in the while loop
glview->retain();//从上面的注释可以了解到在这里为了防止glview这个opengl对象在下面的循环中被释放,增加了一次引用。 while(!glview->windowShouldClose())// 游戏主循环
{
QueryPerformanceCounter(&nNow);
if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart)// 计算是否达到设置的游戏帧频的时间
{
nLast.QuadPart = nNow.QuadPart; director->mainLoop();
glview->pollEvents();
}
else
{
Sleep();
}
} // Director should still do a cleanup if the window was closed manually.
if (glview->isOpenGLReady())//释放opengl
{
director->end();
director->mainLoop();
director = nullptr;
}
glview->release();
return true;
}
这里面Director这个类出镜率很高,之后我们单独分析这个类。
下面我们分析一下私人定制的applicationDidFinishLaunching函数在程序启动中都干了些什么。
bool AppDelegate::applicationDidFinishLaunching() {
// initialize director
auto director = Director::getInstance();//获取director对象,具体Director类是什么玩意,下文分析,目前可以知道这是个大管家
auto glview = director->getOpenGLView();//获取opengl渲染对象,注意这里的 auto用法,这是c++11的新特性,大家可以去百度,就是根据后面的初始化来自动识别变量类型,真是方便啊。
if(!glview) {
glview = GLView::create("Cpp Empty Test");
director->setOpenGLView(glview);
}//如果获取opengl失败那么重新创建一个opengl对象。
director->setOpenGLView(glview);// 将opengl对象绑定到大管家,大导演身上。
// Set the design resolution
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
// a bug in DirectX 11 level9-x on the device prevents ResolutionPolicy::NO_BORDER from working correctly
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::SHOW_ALL);
#else
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::NO_BORDER);
#endif
//这段代码是判断平台来设置此app的长宽及边框模式。还有一些预定义在AppMacros.h里面定义的,可以翻看一下。
Size frameSize = glview->getFrameSize();
vector<string> searchPath;
// In this demo, we select resource according to the frame's height.
// If the resource size is different from design resolution size, you need to set contentScaleFactor.
// We use the ratio of resource's height to the height of design resolution,
// this can make sure that the resource's height could fit for the height of design resolution.
// if the frame's height is larger than the height of medium resource size, select large resource.
if (frameSize.height > mediumResource.size.height){ searchPath.push_back(largeResource.directory);
director->setContentScaleFactor(MIN(largeResource.size.height/designResolutionSize.height, largeResource.size.width/designResolutionSize.width));}
// if the frame's height is larger than the height of small resource size, select medium resource.
else if (frameSize.height > smallResource.size.height)
{
searchPath.push_back(mediumResource.directory);
director->setContentScaleFactor(MIN(mediumResource.size.height/designResolutionSize.height, mediumResource.size.width/designResolutionSize.width));
}
// if the frame's height is smaller than the height of medium resource size, select small resource.
else
{
searchPath.push_back(smallResource.directory);
director->setContentScaleFactor(MIN(smallResource.size.height/designResolutionSize.height, smallResource.size.width/designResolutionSize.width));
} // set searching path
FileUtils::getInstance()->setSearchPaths(searchPath);
// 上面的那几段代码是针对不同分辨率读取不同的资源,并且计算了缩放比例,设置了资源路径。
// turn on display FPS 设置帧速率的显示
director->setDisplayStats(true);
// set FPS. the default value is 1.0/60 if you don't call this
director->setAnimationInterval(1.0 / );
//这里设置了帧速率,回想上面我们看Application::run代码里面while循环就是依据这块设置的速率来实现的。
// create a scene. it's an autorelease object
auto scene = HelloWorld::scene();//这里又出现了一个新的类 HelloWorld 这是什么玩意?后面再说。肯定是定义了一个场景。
// run
director->runWithScene(scene);//最后一行代码是让大总管,大导演,run这个HelloWorld场景。
return true;
}
总结:到这里我们通过HelloWorld及跟踪代码,了解了cocos2d-x的启动流程每个平台都要有一个Application类继承自ApplicationProtocol来驱动整个程序。
每个项目都要有一个自己的App类继承自相应平台的Application调用Application::run方法来实现程序的启动。
在run里面可以定制自己的启动初始化 用Application::applicationDidFinishLaunching来实现 还涉及到了几个重要的类 Director, HelloWorld里面的Layer,Scene这几个类.
下章我们来继续刨根问底从 Director Layer Scene这几个类开始小鱼看代码喜欢一层一层的看,也就是广度优先,而不是一个类看到底的方式。 备注:此系列文章为小鱼自己学习cocos2d-x源码的一个过程,并非教程,有些内容在前面可能在前面章节说的不准确(因小鱼也不知道),但后面涉及到后肯定会给出明确的解释。
Cocos2d-X3.0 刨根问底(二)----- 从HelloWorld开始的更多相关文章
- Cocos2D v2.0至v3.x简洁转换指南(二)
触摸处理 我们在稍后将完成Cocos2d 3.0中触摸处理的完整教程.而现在最重要的是知道如何去启用触摸处理在你的CCNode中: self.userInteractionEnabled = TRUE ...
- 如何在Cocos2D 1.0 中掩饰一个精灵(六)
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 掩饰一个精灵:实现代码 打开HelloWorldLayer.m并 ...
- 如何在Cocos2D 1.0 中掩饰一个精灵(一)
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 原帖来自Ray Wunderlich写的精彩的文章 How To ...
- Cocos2D v2.0至v3.x简洁转换指南(三)
Cocos2D 3.3中的注意事项 如果你在使用Cocos2D 3.3+(是SpriteBuilder 1.3+的一部分)你将不得不替分别的换所有存在的UITouch和UITouchEvent为CCT ...
- 如何将各种低版本的discuz版本升级到discuz x3.0
最近在做discuz改版的项目,遇到了很多问题,相信很多拥有discuz论坛的版主,站长和程序猿在升级或改版discuz的过程中遇到过和我一样的问题,所以我开了一个discuz专栏,为大家讲解一下di ...
- cocos2d 2.0和UIKit混合编程, Push CCDirector的时候出现黑屏的天坑
症状 使用cocos2d 2.0和UIKit混合编程, 有一块用cocos2d编写的小程序, 将CCDirector push到一个UINavigationController里面. 虽然事先在后台初 ...
- 探索ASP.Net Core 3.0系列二:聊聊ASP.Net Core 3.0 中的Startup.cs
原文:探索ASP.Net Core 3.0系列二:聊聊ASP.Net Core 3.0 中的Startup.cs 前言:.NET Core 3.0 SDK包含比以前版本更多的现成模板. 在本文中,我将 ...
- 如何在Cocos2D 1.0 中掩饰一个精灵(二)
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 让我们开始吧 打开Xcode,从New Project中选择co ...
- cocos2d-x3.0创建第一个jsb游戏
第一步: 最新的cocos2d-x.下载地址https://github.com/cocos2d/cocos2d-x github上最新的引擎,值得注意的是官网上发布的引擎是稳定版.选择哪种就看个人喜 ...
随机推荐
- UESTC 898 方老师和缘分 --二分图匹配+强连通分量
这题原来以为是某种匹配问题,后来好像说是强连通的问题. 做法:建图,每个方老师和它想要的缘分之间连一条有向边,然后,在给出的初始匹配中反向建边,即如果第i个方老师现在找到的是缘分u,则建边u-> ...
- -bash: rz: command not found
rz,sz是Linux/Unix同Windows进行ZModem文件传输的命令行工具.优点就是不用再开一个sftp工具登录上去上传下载文件. sz:将选定的文件发送(send)到本地机器rz:运行该命 ...
- Dvwa writeup
DVWA(Dam vulnerable Web Application)是使用PHP+Mysql编写的一套用于常规漏洞教学和漏洞挖掘的一个测试学习程序,在此程序中包含了常见的web方面的漏洞,如命令行 ...
- Linq中查询List组合相同值数量大于1
List< select g.Key).ToList();
- 关于Java多态
什么是多态 同一个实现接口,使用不同的实例而执行不同的操作 子类转换成父类的规则: *将一个父类的引用指向一个子类对象时,称为上转型,自动进行类型转换 *此时通过父类引用变量调用的方法是子类覆盖或继承 ...
- 【转】【C#】异常类 Exception 枚举所有类型的异常
一.基础 在C# 里,异常处理就是C# 为处理错误情况提供的一种机制.它为每种错误情况提供了定制的处理方式,并且把标识错误的代码与处理错误的代码分离开来. 对.NET类来说,一般的 异常类System ...
- WinForm中异步加载数据并使用进度条
在WinForm程序中,有时会因为加载大量数据导致UI界面假死,这种情况对于用户来说是非常不友好的.因此,在加载大量数据的情况下,首先应该将数据加载放在另一线程中进行,这样保证了UI界面的响应:其次可 ...
- Linux Linux程序练习十一(网络编程大文件发送UDP版)
//网络编程发送端--大文件传输(UDP) #include <stdio.h> #include <stdlib.h> #include <string.h> # ...
- C# 【无法修改XX返回值,因为它不是变量】
using UnityEngine; using System.Collections; using System.Xml.Linq; using UnityEditor; using System; ...
- JavaScript及其异步实现续:Promise让一切更简单
在写这篇文章之前,我参考了以下文章.所以我文中的例子都是精准的,而且有循可依.下面抛出例子的链接: Understanding JQuery.Deferred and Promise Deferred ...