介绍
实体组件系统是一种面向对象的架构技术。
关于术语的含义,与面向对象编程相同,尚无共识。但是,很明显,实体组件系统专门用作继承的体系结构替代。继承层次结构很自然地表达对象是什么,但是在某些类型的软件(例如游戏)中,您宁愿表达对象的作用。
它是与“类和继承”不同的对象模型,您最常使用C ++或Java来熟悉它。实体就像类一样具有表现力,就像JavaScript或Self中的原型一样,所有这些系统都可以彼此实现。
例子
比方说,Player
是一个实体Position
,Velocity
和KeyboardControlled
组件,它们做明显的事情。
entity Player:
Position
Velocity
KeyboardControlled
我们知道Position
必须受到Velocity
和Velocity
的影响KeyboardControlled
。问题是我们如何建模这些效果。
实体,组件和系统
假设组件之间没有相互引用;外部Physics
系统遍历所有Velocity
组件并更新Position
相应实体的;一个Input
系统遍历所有的KeyboardControlled
组件和更新Velocity
。
Player
+--------------------+
| Position | \
| | Physics
/ | Velocity | /
Input | |
\ | KeyboardControlled |
+--------------------+
满足条件:
实体未表达任何游戏/业务逻辑。
组件存储描述行为的数据。
系统现在负责处理事件并制定组件描述的行为。它们还负责处理实体之间的交互,例如冲突。
实体和组件
但是,假设组件之间确实存在相互引用。现在,实体只是一个构造函数,它创建一些组件,将它们绑定在一起,并管理其生命周期:
class Player:
construct():
this.p = Position()
this.v = Velocity(this.p)
this.c = KeyboardControlled(this.v)
实体现在可以将输入和更新事件直接分派到其组件。Velocity
将响应更新,并KeyboardControlled
响应输入。这仍然满足我们的标准:
实体是一个“哑”容器,仅将事件转发到组件。
每个组件都执行其自己的行为。
在这里,组件交互是显式的,不是系统从外部强加的。描述行为的数据(什么是速度量?)和实现该行为的代码(什么是速度?)是耦合的,但是是自然的。可以将数据视为行为的参数。而且某些组件根本不起作用-这Position
是在某个地方的行为。
交互可以在实体级别(“当Player
与Enemy
… 碰撞时”)或在各个组件的级别(“当一个实体与Life
与Strength
… 碰撞时”进行处理)。
组件
实体存在的原因是什么?如果它仅仅是一个构造函数,那么我们可以返回一个函数替换它集组件。如果以后我们要按实体类型查询实体,我们也可以有一个Tag
组件让我们做到这一点:
function Player():
t = Tag("Player")
p = Position()
v = Velocity(p)
c = KeyboardControlled(v)
return {t, p, v, c}
实体尽可能的愚蠢-它们只是组件集。
组件像以前一样直接响应事件。
互动必须现在由抽象查询处理,完全脱钩实体类型的事件。没有更多的实体类型可查询— Tag
与游戏逻辑相比,任意数据可能更适合用于调试。
结论
实体不是功能,规则,参与者或数据流组合者。它们是模拟具体现象的名词,也就是说,它们是对象。就像Wikipedia所说的那样,实体组件系统是用于对通用对象进行建模的软件体系结构模式。