用户:Lijinyu25775/实体-组件-系统(ECS)
实体-组件-系统 (ECS)模式是一种主要用于游戏软件开发的架构模式。 ECS模式遵循组合优于继承原则,使得在一个每个对象都是实体(比如敌人,子弹,车辆等)的游戏场景中,定义实体具有更大的灵活性。每个实体由一个或多个添加其他行为或功能的组件构成。因此,通过添加或删除组件可以在(程序)运行时改变实体的行为。这消除了关于继承层次结构的深度(纵向)和广度(横向)的,难以理解、维护和扩展的歧义问题。一般的ECS模式实践通常是高度兼容的,经常与面向数据的设计技术相结合。
历史
1998年发行的游戏《神偷:黑暗计划》是公认使用ECS模式的最早的游戏。[1]然而它的技术细节在其他的ECS模式实践公开后很久才公布。[2]
据2002年Scott Bilas在GDC大会的演讲中记载,同年发行的游戏《地牢围攻》是第一个被详细描述的ECS模式实现。[3]
Bilas的讲话明确提到了现在成为标准的概念有:基于数据库的组合模式,数据驱动模式不仅是属性,组件是一个自包含项等。
在2007年,开发《闪点行动:龙之崛起》的团队尝试使用包括由Bilas/《地牢围攻》提到的一些ECS模式设计;Adam Martin后来撰写了一份ECS模式设计的详细介绍,[4]其中包括一些核心术语和概念的定义。[5]特别是,Martin普及了一些思想,如各系统作为顶级要素、实体既是ID,组件既是原数据和在系统,而非组件或实体中保留处理代码。
Unity引擎在2008年至2010年期间变得大受欢迎,使得他们对实体和组件的不同使用方式变得众所周知并被广泛应用。然而,Unity引擎并没有正式描述他们的技术。除非另有说明,否则通常将ECS模式作为术语来指代Bilas在2002年公开的技术。
术语
当今广泛使用的Martin的术语[5]:
游戏中的例子
假设有一个绘图函数。 它就是一个系统,它遍历具有物理和可见组件的所有实体并描绘它们。 可见组件一般具有关于实体的外表(例如人类、怪物、火花飞行、飞箭)的一些信息;使用物理组件来知道要在什么位置描绘该实体。
再如碰撞检测系统。 它将遍历具有物理组件的所有实体,单它不会关心实体的描绘状态。 然后假设有一个场景,该系统将检测与怪物相碰撞的箭,并在这种情况发生时生成一个事件。 碰撞检测系统无需了解箭是什么,或当另一个(不带物理组件的)对象被箭击中时要做什么。
还有一个包含健康数据的组件以及一个管理健康的系统。 健康组件将附加到人类和怪物实体上,而不能是箭实体。 健康管理系统将订阅碰撞产生的事件,并相应地更新健康状态。 该系统还能够不时遍历具有健康组件的所有实体,并重新生成健康状态。
实体设计
实体只包含一个ID和一个组件的容器。 思路是没有游戏方法被嵌入到实体中。 容器不必与实体物理上联系在一起,但要容易找到和访问。
对每个实体使用唯一的ID是常见的做法。 这不是一个强制要求,但它有几个优点:
- 可以使用ID而不是指针来引用实体。更强大的是,它允许不用指针来销毁该实体。
- 它有助于外部保存状态。当状态再次加载时,不需要重新创建指针。
- 数据可以根据需要在内存中随意传播。
- 实体ID可以作为一个实体的全局标识被用于网络间通信。
这些优点中的一些也可以用智能指针来实现。
缺点
ECS模式设计存在几个问题。
内部系统间通信
在系统之间发送数据的常规方法是将数据存储在组件中。 例如,可以定期更新对象的位置。然后该位置数据被其他系统使用。
如果有很多不常见的事件,一个或多个组件将需要很多标志。系统将不得不在每次迭代监视这些标志,这可能变得越来越没有效率。解决方案可能是使用观察者模式。 依赖于事件的所有系统都订阅它。因此,事件触发的动作仅当事件发生时被执行一次,而不必再需要轮询处理。
实体间迭代的成本
在一些ECS架构中,一个基本思想是为所有实体提供一个大的列表。每个系统然后遍历完整的列表,并仅选择所需的实体。如果系统数量增加,或者实体数量很大,则所有系统的总迭代成本可能过大。
在另一些ECS架构中,每个组件类型都存储在单独的列表中,因此无论哪个系统对这些类型的组件进行操作,只是在默认情况下迭代他们关心的对象。 在这种常见的ECS架构中,所描述的缺点通过更有效地利用CPU指令和数据高速缓存而实际上成为主要的性能优势。
优势
依赖性的安全管理
ECS架构以非常安全和简单的方式处理依赖关系。由于组件是简单的数据容器,因此它们没有依赖关系。每个系统为了操作相应的实体,通常会注册一些该实体必须具有的组件。例如,渲染系统需要注册模型组件,转换组件和可绘制组件。然后,渲染系统将检查每个实体,如果某个实体拥有全部注册组件,则该系统将对该实体执行相应逻辑处理。反之,则此实体被系统忽略,即不需要处理复杂的依赖关系树。然而,这可能是bug隐藏的地方,因为通过组件将值从一个系统传播到另一个系统可能很难调试。将数据与逻辑分离不会有助于减少依赖性,而是通过适当的代码设计来减少依赖性。您可以将数据从一个具有100个依赖关系的类移动到一个组件中,但这并不能解决依赖问题,而是使该类更难调试。如果需要将未绑定的数据绑定到既存的生命周期(的实体),则可以使用ECS模式。
组合模式
ECS架构使用组合技术,而不是复杂的继承树技术。实体通常由一个ID和一组绑定的组件构成。可以通过向实体添加正确的组件来创建任何类型的游戏对象。这也可以允许开发人员轻松地将一种类型的对象的功能添加到另一种对象,而不会有任何依赖性问题。例如,玩家实体可以添加一个子弹组件,然后它将达到某些“bulletHandler”之类的系统的操纵的要求,而这可能导致该玩家被相应系统对其或其装备进行破坏性处理。
参阅
引用
- ^ Leonard, Tom. Postmortem: Thief: The Dark Project. [19 January 2015].
- ^ Church, Doug. Object Systems. Chris Hecker's Website (Powerpoint). [19 January 2015].
- ^ Bilas, Scott. A Data-Driven Game Object System (PDF). [25 December 2013].
- ^ Martin, Adam. Entity Systems are the Future of MMOG Development. [25 December 2013].
- ^ 5.0 5.1 Martin, Adam. Entity Systems are the Future of MMOG Development Part 2. [25 December 2013].
- ^ 6.0 6.1 Entity Systems Wiki. [9 February 2014].