如何在cocos2d-x中使用ECS(实体-组件-系统)架构方法开发一个游戏?

引言

              在我的博客中,我曾经翻译了几篇关于ECS的文章。这些文章都是来自于Game Development网站。如果你对这个架构方式还不是很了解的话,欢迎阅读理解 组件-实体-系统和实现 组件-实体-系统。

              我发现这个架构方式,是在浏览GameDev上的文章的时候了解到的。很久以前,就知道了有这么个架构方法,只是一直没有机会自己实践下。这一次,我就抽空,根据网上对ECS系统的讨论,采用了一种实现方法,来实现一个。

             我很喜欢做游戏,所以同样的,还是用游戏实例来实践这个架构方法。我将会采用cocos2d-x来作为游戏开发的主要工具,这是一款十分强大的跨平台游戏引擎,感兴趣的读者,可以自行搜索了解。


ShapeWar

             我一直觉得,作为游戏程序员,能够自己独立的绘制游戏中的图片资源是一件非常好玩的事情。所以,没有美术功底的我,就选择了一种复古风格的艺术——像素艺术来学习。经过一段时间的学习,发现做像素画还是很有趣的,所以我就将我以前做的简单的像素图片,来融合成现在的这个游戏实例——ShapeWar 。

            这个游戏很简单,玩家通过键盘上的左右键来移动发射器,通过按下space键,来进行攻击,将所有掉落下来的立方体全都打掉。如果有立方体遗漏掉,那么将会丢掉一颗血,直到玩家死亡为止。这个游戏,开始的时候,可能会非常容易,但是,立方体下落的速度是逐渐增加的,到了后面,如果玩家还能够坚持住的话,那非常了不起!!!

            好了,游戏规则很简单,来看看游戏的截图吧!

如何在cocos2d-x中使用ECS(实体-组件-系统)架构方法开发一个游戏?_第1张图片如何在cocos2d-x中使用ECS(实体-组件-系统)架构方法开发一个游戏?_第2张图片

如何在cocos2d-x中使用ECS(实体-组件-系统)架构方法开发一个游戏?_第3张图片如何在cocos2d-x中使用ECS(实体-组件-系统)架构方法开发一个游戏?_第4张图片如何在cocos2d-x中使用ECS(实体-组件-系统)架构方法开发一个游戏?_第5张图片

                 好了,这个游戏很简单,有兴趣的同学,可以到这里来下载,试玩一下,并且在留言中,告诉我,你最高得了多少分哦!!!


架构设计

                从上面的截图,大家也能够明白,游戏只有两个场景,分别是开始场景,和游戏进行场景。需要完成的功能如下:

  •   能够产生立方体,控制立方体产生
  •   能够控制发射器,发射出球体
  •   能够检测出球体和立方体之间的碰撞
  •   对不同的立方体,需要碰撞不同的次数才能消灭
  •   立方体消灭之后,要播放动画
  •   玩家拥有血量和积分

               这个游戏大致就有这些功能。

               在ECS系统中,我们没有像传统的面向对象方法那样,为游戏中每一个实体定义一个类。比如,对于这里的玩家(Player)定义一个类,然后为绿色的立方体(GreenCube),红色的立方体(RedCube),橙色的立方体(OrangeCube)和紫色的立方体(PurpleCube)都定义一个类。对于这样的小游戏来说,你可以这么做,但是对于大一点的游戏来说,里面的实体有非常的多,如果每一个都定义一个类的话,那么系统将难以维护。所以,在ECS系统中,它将“多使用组合,少使用继承”的概念发挥到极致。


组件

              在系统中,并没有为每一个实体都定义一个类,而是为构成这些实体的基本单元,也就是前面两篇博文中讲述的Component(组件),一个一个的定义。下面是我游戏中,需要用到的所有的组件类型:

// File: Component.h
//------------------------------------------------------------------
// declaration	: Copyright (c), by XJ , 2014 . All right reserved .
// brief		: This file will define the Component base class of the 
//                Entity-Component-System.
// author		: XJ
// date			: 2014 / 6 / 8
// version		: 1.0
//-------------------------------------------------------------------
#pragma once
#include
using namespace cocos2d ;

namespace ShapeWar
{
#define COMPONENT_NONE 0x0

class Component
{
public:
	Component(){}
	virtual ~Component(){}
};

/**
* Define the Render Component
*/
#define COMPONENT_RENDER (1 << 1)
class RenderComponent: public Component
{
public:
	RenderComponent(){}
	~RenderComponent()
	{
		sprite->removeFromParentAndCleanup(true);
		delete sprite ;
	}

public:
	CCSprite* sprite ;
};

/**
* Define the Position Component
*/
#define COMPONENT_POSITION (1 << 2 )
class PositionComponent: public Component
{
public:
	PositionComponent(){}
	~PositionComponent(){}

public:
	float x ;
	float y ;
};

/**
* Define the Velocity Component
*/
#define COMPONENT_VELOCITY (1 << 3)
class VelocityComponent: public Component
{
public:
	VelocityComponent(){}
	~VelocityComponent(){}

public:
	float vx ;
	float vy ;
};

/**
* Define the Health Component
*/
#define COMPONENT_HEALTH (1 << 4)
class HealthComponent: public Component
{
public:
	HealthComponent(){}
	~HealthComponent(){}

public:
	unsigned int health ;
};

/**
* Define the Collidable Component
* brief	: Use the AABB's Min-Max representation
*/
#define COMPONENT_COLLID (1 << 5)
class CollidableComponent:public Component
{
public:
	CollidableComponent(){}
	~CollidableComponent(){}

public:
	float min_x ;
	float min_y ;
	float max_x ;
	float max_y ;
};

/**
* Define the EntityType component
* brief	: This component will indicate which type the entity is.
*/
#define COMPONENT_ENTITY_TYPE (1 << 6)
class EntityTypeComponent: public Component
{
public:
	EntityTypeComponent(){}
	~EntityTypeComponent(){}

public:
	static const unsigned int RED_CUBE = (1 << 1) ;
	static const unsigned int PURPLE_CUBE = (1 << 2) ;
	static const unsigned int ORANGE_CUBE = (1 << 3) ;
	static const unsigned int GREEN_CUBE = (1 << 4) ;
	static const unsigned int SPHERE_BALL = (1 << 5) ;
	static const unsigned int PLAYER = (1 << 6) ;

public:
	unsigned int type ;
};

/**
* Define the AnimateComponent
*/
#define COMPONENT_ANIMATE (1 << 7)
class AnimateComponent:public Component
{
public:
	AnimateComponent(){}
	~AnimateComponent(){}

public:
	cocos2d::CCAnimate* animate ;
	unsigned frames ;
};

};
            从上面的代码中,大家可以看到,我首先定义了一个基类Component,然后让所有的组件都继承于这个基类。这里,我并没有用到继承,读者可以发现Component中什么内容也没有。 我将其他组件继承于Component的组要原因是能够将他们统一的进行处理,仅此而已。

            在定义完了基类之后,分别定

你可能感兴趣的:(游戏开发,游戏编程,游戏开发,游戏开发,设计原则,游戏,架构设计)