您的位置:首页 > 移动开发 > Cocos引擎

7、Cocos2dx 3.0游戏开发找小三之3.0版本的代码风格

2014-05-30 16:45 537 查看
重开发者的劳动成果,转载的时候请务必注明出处: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 的代码风格。 
这么做的主要原因如下:
出于对 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 命名空间下。
在游戏中,我们常使用引擎提供的另一个宏 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();


若想了解更多信息,官方网站上有 3.X与 2.X 之前的差异说明:
cocos2d-x 3.0 与cocos2d-x 差异说明链接

构造函数与初始化
在 Cocos2d-x 中创建对象的方法与 C++开发者的习惯迥乎不同。 在 C++中, 我们只需要调用类的构造函数即可创建一个对象,既可直接创建一个栈上的值对象,也可以使用
new 操作符创建一个指针,指向堆上的对象。而在 Cocos2d-x 中,无论是创建对象的类型,还是创建对象的方法都与 C++不同。

Cocos2d-x 不使用传统的值类型,所有的对象都创建在堆上,然后通过指针引用。
创建 Cocos2d-x 对象通常有两种方法:
第一种是首先使用 new 操作符创造一个未初始化的对象,然后调用
init 系列方法来初始化;
第二种是使用静态的工厂方法直接创建一个对象。

下面我们首先介绍第一种方法。

在 Objective-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)来初始化精灵。

第二种方法则是使用类自带的工厂方法来创建对象。
在 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 开发类似。
例如在 Hello World 中,我们从 Layer 类派生出 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 中创建选择器语法的宏,用来创建函数指针。
这些宏都只有一个参数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()方法。
可以看到,初始化菜单的后两个参数分别是被调用对象与Cocos2d-x 选择器:
auto closeItem = MenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
CC_CALLBACK_1(HelloWorld::menuCloseCallback,this));


其中CC_CALLBACK_1宏是将函数与对象绑定在一起,1表示这个函数有一个参数。当点击这个按钮时,会调用这个回调函数。

除了基于c++11的这个形式的改变,使用方法与先前相同。

属性
C++的类成员只有方法与字段,没有属性和事件,这给开发者带来了不便。
为了实现 Objective-C 中提供的属性功能,我们不得不使用方法来模拟
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 来切换到新场景。

郝萌主友情提示:
熟悉新风格,新特性,使用cocos2d-x引擎会更方便噢、、、
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐