重开发人员的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27691337
Cocos2d-x代码风格
前面我们已经多次提到 Cocos2d-x 源自于 Cocos2d-iPhone。Cocos2d-iPhone 是一个十分出色的游戏引擎,很多优秀的 iOS平面游戏都基于 Cocos2d-iPhone
开发,而它的实现语言是 Objective-C。因此,Cocos2d-x 也就沿袭了 Objective-C 的代码风格。
开发,而它的实现语言是 Objective-C。因此,Cocos2d-x 也就沿袭了 Objective-C 的代码风格。
这么做的主要原因例如以下:
出于对 Cocos2d-iPhone 程序猿习惯的照应,以及对该引擎的尊敬;
方便不同语言下 Cocos2d游戏的移植;
为了实现 Objective-C 风格的内存管理,要求引擎採用特殊的命名规范。
接下来我们将具体介绍 Cocos2d-x 的代码风格。
命名空间与类名称
Cocos2d-x 拥有一个包括其它所有头文件的文件"cocos2d.h"。通常,我们仅仅须要在使用时包括这个头文件,就能够使用引擎的所有功能了。
Cocos2d-x 的类都放置于 cocos2d 命名空间下。以引擎文件夹下的"cocos/2d/CCLayer.h"为例,我们能够看到文件的首位有两个宏:NS_CC_Begin
和 NS_CC_END。查看宏的定义可知,这两个宏相当于把全部的类型都包括在了 cocos2d 命名空间下。
和 NS_CC_END。查看宏的定义可知,这两个宏相当于把全部的类型都包括在了 cocos2d 命名空间下。
在游戏中,我们常使用引擎提供的还有一个宏 USING_NS_CC 来引用 cocos2d 命名空间:
#define USING_NS_CC using namespace cocos2d
类的命名与 Cocos2d-iPhone 一致,由类库缩写加上类名称组成,当中类库缩写採用大写,类名称採用驼峰法。
Cocos2d 2.0的 缩写是 CC,因此 Cocos2d-x 2.0的类都拥有 CC 前缀,比如表示动作的类就叫做 CCAction。
相比于Cocos2d 2.0,Cocos2d 3.0更简洁;
从此不再见到以CC开头的类,由于CC被废掉了,而且定义的时候用auto;
举个样例:
v2.2
CCSprite* sprite=CCSprite::create();
v3.0
auto sprite=Sprite::create();
构造函数与初始化
在 Cocos2d-x 中创建对象的方法与 C++开发人员的习惯迥乎不同。 在 C++中, 我们仅仅须要调用类的构造函数就可以创建一个对象,既可直接创建一个栈上的值对象,也能够使用
new 操作符创建一个指针,指向堆上的对象。而在 Cocos2d-x 中,不管是创建对象的类型,还是创建对象的方法都与 C++不同。
new 操作符创建一个指针,指向堆上的对象。而在 Cocos2d-x 中,不管是创建对象的类型,还是创建对象的方法都与 C++不同。
Cocos2d-x 不使用传统的值类型,全部的对象都创建在堆上,然后通过指针引用。
创建 Cocos2d-x 对象通常有两种方法:
第一种是首先使用 new 操作符创造一个未初始化的对象,然后调用
init 系列方法来初始化;
init 系列方法来初始化;
另外一种是使用静态的工厂方法直接创建一个对象。
以下我们首先介绍第一种方法。
在 Objective-C 中并没有构造函数,创建一个对象须要先为对象分配内存,然后调用初始化方法来初始化对象,这个过程就等价于
C++中的构造函数。
C++中的构造函数。
与 Objective-C 一样, Cocos2d-x 也採用了这个步骤。
Cocos2d-x 类的构造函数通常没有參数,创建对象所需的參数通过 init 开头的一系列初始化方法传递给对象。
创建对象的过程例如以下所看到的。
使用 new 操作符调用构造函数,创建一个没有初始化过的空对象。
选择合适的初始化方法,并调用它来初始化对象。
Cocos2d-x 的初始化方法都以 init 作为前缀,因此能够轻易辨认出来。初始化方法返回一个布尔值,代表是否成功初始化该对象。
以下我们提供一个从文件初始化精灵(CCSprite)的样例:
auto sprite1 = new CCSprite();
sprite1->initWithFile("bg.png");
在这个样例中,我们首先调用构造函数创建一个未经初始化的 Sprite 对象,然后在 Sprite 提供的初始化方法中选择了从文件创建精灵的初始化方法
Sprite::initWithFile(const char* filename)来初始化精灵。
Sprite::initWithFile(const char* filename)来初始化精灵。
另外一种方法则是使用类自带的工厂方法来创建对象。
在 Cocos2d-x 中,很多类会自带一系列工厂方法,这些工厂方法是类提供的静态函数。
仅仅要提供必要的參数,就会返回一个完毕了初始化的对象。
通常 init 系列的初始化方法都会有其相应的工厂方法,它们的名称类似,參数一致,都能够用于创建对象。
在 Cocos2d-x 的旧版本号中,工厂方法通常以类的名称(不包括前缀)开头,
而在 Cocos2d-x 2.0 及兴许版本号中,工厂方法的名称统一为 create。
在名称冲突的情况下,也可能採用以 create 作为前缀的其它函数名。
我们仍然以创建精灵为例,以下的两条语句等价;
前者为引擎旧版本号中的方法,后者为新版本号中的方法,它们都会创建一个与第一种方法所述类似的精灵:
Sprite* sprite2 = Sprite::spriteWithFile("bg.png");
Sprite* sprite3 = Sprite::create("bg.png");
这两种方法都能够创建 Cocos2d-x 对象,然而它们在内存管理方面还是有一点点差异的。
使用构造函数创建的对象,它的全部权已经属于调用者了,使用工厂方法创建的对象的全部权却并不属于调用者,
因此,使用构造函数创建的对象须要调用者负责释放,而使用工厂方法创建的对象则不须要。
在游戏中,我们须要不断地创建新的游戏元素,通常採取的方法是从 Cocos2d-x 提供的游戏元素类派生出新的类,并在初始化方法中建立好我们所需的游戏元素。这个过程与微软.NET
框架下的 Windows Form 开发类似。
框架下的 Windows Form 开发类似。
比如在 Hello World 中,我们从 Layer 类派生出 HelloWorld 类
(这是一个层) , 并重载了 HelloWorld 类的 init()方法, 在这种方法中为 HelloWorld层加入内容。
(这是一个层) , 并重载了 HelloWorld 类的 init()方法, 在这种方法中为 HelloWorld层加入内容。
为了保证初始化方法能够被子类重载,须要确保初始化方法声明为虚函数:
virtual bool init();
作为參考,我们提供一个典型的 init()方法框架例如以下:
bool init()
{
if(Layer::init()) {
//在此处写入初始化这个类所需的代码
return true;
}
return false;
}
选择器
在 Objective-C 中,选择器(Selector)是类似于 C++中的类函数指针的机制。
因为 Cocos2d-x 继承了 Cocos2d-iPhone 的代码风格,因此也提供了一系列类似于
Objective-C 中创建选择器语法的宏,用来创建函数指针。
Objective-C 中创建选择器语法的宏,用来创建函数指针。
这些宏都仅仅有一个參数SELECTOR,表示被指向的类方法。
在Cocos2d-x2.0中将这些宏列举例如以下:
schedule_selector(SELECTOR)
callfunc_selector(SELECTOR)
callfuncN_selector(SELECTOR)
callfuncND_selector(SELECTOR)
callfunc_selector(SELECTOR)
menu_selector(SELECTOR)
event_selector(SELECTOR)
compare_selector(SELECTOR)
从3.0開始,事件回调函数由原来的schedule_selector和menu_selector等变成CC_CALLBACK_0、CC_CALLBACK_1、CC_CALLBACK_2、CC_CALLBACK_3。
以下我们来看第 1 章中的 Hello World 样例。
在这个样例中,我们在 HelloWorld 类的 init()方法中加入了一个菜单,当用户点击该菜单时,就会触发此类中的
menuCloseCallback()方法。
menuCloseCallback()方法。
能够看到,初始化菜单的后两个參数各自是被调用对象与Cocos2d-x 选择器:
auto closeItem = MenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
CC_CALLBACK_1(HelloWorld::menuCloseCallback,this));
当中CC_CALLBACK_1宏是将函数与对象绑定在一起,1表示这个函数有一个參数。当点击这个button时,会调用这个回调函数。
除了基于c++11的这个形式的改变,用法与先前同样。
属性
C++的类成员仅仅有方法与字段,没有属性和事件,这给开发人员带来了不便。
为了实现 Objective-C 中提供的属性功能,我们不得不用法来模拟
get 和 set 訪问器。
get 和 set 訪问器。
Cocos2d-x 规定了属性訪问器的方法名称以 get 或 set 为前缀,后接属性名。
在 Node 中包括大量属性,
比如用于给节点做标记的 Tag 属性,它的訪问器分别为 getTag()和 setTag(int aTag),
事实上现原 理大致例如以下:
int _tag; ///< a tag. Can be any number you assigned just to identify this node
virtual int getTag() const;
virtual void setTag(int aTag) /// tag getter
int Node::getTag() const
{
return _tag;
} /// tag setter
void Node::setTag(int var)
{
_tag = var;
}
在这个样例中,属性的类型是 int,处理较为简单。
当涉及到内存管理,开发中我们对数值类型、结构体类型、Cocos2d-x对象的处理方法都不尽同样。
为每个属性编写一个或两个訪问器方法是一项十分枯燥的任务,为了避免反复性的工作,Cocos2d-x 提供了一系列宏来帮助我们方便地创建属性。
下表列举了全部属性相关的宏,它们定义在引擎文件夹中的"cocos\base\CCPlatformMacros.h"中。
Cocos2d-x 3.0中与属性相关的宏
这些宏仅仅要写在类的定义之中就可以。
每一个宏都有 3 个參数,各自是:varType,属性类型,假设属性类型是对象,须要写成指针的形式;
varName,属性的私有字段名称;funName,属性的訪问器名称,也就是紧接在 get 或 set 前缀后的部分。
利用 Cocos2d-x 提供的宏,以Layer为例,Layer属性定义就能够用以下一条语句取代了:
CC_SYNTHESIZE(cocos2d::Layer*, m_pLayer, Layer);
单例
相对于前面的内容,单例(singleton)则是一个非常易于理解的概念。
在 Cocos2d-x 引擎中,我们能看到大量单例的身影,它们大部分出如今一些系统资源管理类中。
单例模式保证了全局有且仅仅有一个实例对象,保证自己主动地初始化该对象,
使得程序在不论什么时候不论什么地方都能够訪问、获取该对象。
比如,Cocos2d-x 3.0的游戏流程控制器 Director 是一个独一无二的控制器,用于切换游戏场景。
换句话说,不可能同一时候存在两个 Director 实例。
在这样的情况下, Cocos2d-x 採用了单例的技巧。
用户能够通过类提供的静态方法获取独一无二的实例, 而不须要自己来创建。
观察 Director 的代码:
// singleton stuff
static DisplayLinkDirector *s_SharedDirector = nullptr;
Director* Director::getInstance()
{
if (!s_SharedDirector)
{
s_SharedDirector = new DisplayLinkDirector();
s_SharedDirector->init();
} return s_SharedDirector;
}
能够发现,Director 维护了一个静态的 Director 实例,在第一次使用前初始化。
为了訪问 Director 控制器,我们能够使用例如以下代码:
Director::getInstance()->replaceScene(newScene);
这条语句使用 Director::getInstance()获取 Director的唯一实例,然后调用
replaceScene 来切换到新场景。
replaceScene 来切换到新场景。
郝萌主友情提示:
熟悉新风格,新特性,使用cocos2d-x引擎会更方便噢、、、