关于Unity 2018的实体组件系统(ECS)一

孙广东  2018.5.19

 

 

首先来自ECS的概念。

 

什么是ECS?

首先什么是ECS? ECS是一种新的架构模式(只是在Unity中算新)。

总之,这是一个(作为目标)取代GameObject / Component 的模式。 其模式遵循组合优于继承原则,游戏内的每一个基本单元都是一个实体,每个实体又由一个或多个组件构成,每个组件仅仅包含代表其特性的数据(即在组件中没有任何方法)。系统便是来处理拥有一个或多个相同组件的实体集合的工具,其只拥有行为(即在系统中没有任何数据)。

实体与组件是一个一对多的关系,实体拥有怎样的能力,完全是取决于其拥有哪些组件,通过动态添加或删除组件,可以在(游戏)运行时改变实体的行为。

 

ECS旨在比GameObject / MonoBehaviour更容易处理大量物体。

 

ECS的特点是,由于面向数据的设计 , 很容易并行高速处理,和 C# Job System 一起工作。

 

Unity技术演示, 移动大量对象

 

启用Burst编译器时的性能差异,可以与ECS结合使用

 

 

现在已经提供了只有基本功能。例如没有刚体系统或动画系统,甚至没有体面的渲染器。大多数实现需要由你自己完成。(注意是我写文章的时候没有, 现在已经有了)

但是,如果功能可用,性能比GameObject好 。

 

 

顺便说一句,配合C# Job System, 可以使CPU利用率接近100% 。

 

 

以下是 (未优化) 性能结果比较。 传统的脚本OC, C# Job System, Entity Component System, 和ECS with Burst Compiler。测试从1.3万对象到6.8万个。

 

 

 

 

ECS术语

ECS有几个术语。

例如,实体Entity组件数据Component Data组件系统ComponentSystem组Group 等4项。

  • 实体Entity:像容器一样
  • 组件数据Component Data:要存储在实体中的数据(不包括处理)
  • 组件系统ComponentSystem:处理
  • 组Group:组件系统运行所需的ComponentData列表

 

还有很多其他的东西,但是目前这四个内容最重要。

 

它与 起源(传统)ECS术语略有不同。

  • Entity=Entity
  • ComponentData =Component
  • ComponentSystem = System

 

 

在这个术语中,与Unity的GameObject /Component相比,有一个稍微接近的地方。如果完全粗略地说明,则它与以下项目匹配。

 

  • Entity=GameObject
  • ComponentData =Component的字段
  • ComponentSystem =Component的Update方法
  • Group = 无

 

 

 

ECS与Component结合使用

Unity的GameObject和Component, 通过给GameObject 提供MonoBehaviour 来定义行为。有一种情况是使用一个Manager,并指示他们移动的功能

 

此外, 会有移动角色的组件。

例如,当一个名为Move的组件移动时,Move组件是通过GetComponent访问Transform得到并移动该对象。

 

 

另一方面,ECS的工作就是这样:

  • ECS的行为 (System系统)和数据 (Component组件)将分别实现。
  • Entity实体中存储了多种类型的数据(Component组件)。
  • 如果存储在对象(实体)中的数据(组件)满足本组请求的数据列表,则调用行为(系统)。

 

MonoBehaviour有1:1的数据和处理,但在ECS中它处理的是 ComponentData的组合。

例如,ComponentData有Transform和 Move作为一组,并通过Group请求系统进行移动 。

 

处理时,称为变换和移动的组件信息直接传递到系统。

 

像这样,调用什么样的处理由System(和Group)的组合来决定,实体是在所有系统来匹配批处理。

如下表所示,可能很容易理解哪种处理将起作用。

 

无论如何,ECS被定义为ComponentData的组合......

 

补充

首先是实体,这是从EntityManager生成的。建议从头开始使用ComponentData生成实体,但您可以稍后添加它。

实体在游戏中有很多像GameObject一样的东西。在某种意义上,实体≈游戏对象。

 

系统为每个实体执行处理。像下图所示 。

在两个系统的情况下,如果组匹配,都会工作。这可能在一个线程中运行,有时由C# Job System并行化。

 

 

例1

 

例如,让我们考虑一个实体,它具有在碰到障碍物时简单的前向右转的功能。

考虑到表示此实体所需的ComponentData,它如下所示。

  • 坐标
  • 前方障碍的距离
  • 运动方向

顺便说一句,如果你想用这个参数来实现运动,可以考虑下面的实现。

1、从“坐标coordinates”和“运动方向direction”中查找“到前方障碍物的距离distance and obstacle 

2、如果“前方障碍物Obstacles in front of”小于某个值,则更改“移动方向direction of movement

3、沿“移动方向movement”方向移动“坐标coordinate

 

 

我把它们放入系统中。

系统负责实现 检查距离,更新方向, 更新坐标。 因为这些都是行为!!!!!

 

 

 

示例问题2

那么,这次你想让一个实体像“朝指定坐标方向移动”那样?

 

这个实体似乎有以下ComponentData。

  • 坐标
  • 指定坐标
  • 运动方向

系统看起来像。

1、从指定坐标坐标中寻找移动方向

2、在移动方向的方向上移动坐标

 

那么,这是第二个系统,使用与例1中完全相同的东西。 由于请求组是相同的。

如果你很好地理解系统,系统在很大范围内是很好的,但是它也使得实现更加麻烦。似乎有必要考虑这里的平衡。

 

 

ComponentData组合的补充

它是ComponentData的组合,但实际上可以设置多个组。

例如,创建GameObjectEntity(只有一个)和Unit Entity(有很多)的组合,你可以期待的十日或一次全部停止根据游戏管理的情况下该股的操作。

 

另外,ComponentData不包含任何特别的内容,它有时指定ComponentData仅作为组的定义, 作为一个熊。

例如,如果你想有一个特殊处理,“熊猫”和“熊”是熊,需要PandaComponentData出现。

 

 

您可以对ComponentData进行添加,删除,设置(覆盖?)操作。也有点像游戏对象

 

 

 

 

 

谁调用了ComponentSystem?

到目前为止,有一点有趣的是“谁调用系统?”

定义后自动调用!!!!!应该是世界在调用吧1

但是调用顺序,你也可以控制。

 

 

 

 

 

 

 

 

实体之间的消息传递

实体之间的消息交换是不可能的。

 

如果要将消息发送到特定实体,然后用实体内容覆盖ComponentData,则系统处于处理中。

 

 

 

 

 

 

补充

ECS并不是面向对象的,所以不能很好地理解,并试图在OOP的背景下去理解(经验

“不知何故FOWA!好像不可能理解”,你可能期待着面向数据的设计,而且可能会更好。

 

  • 观察者模式,可以被用于在系统间发送事件。
  • 策略模式,算是ECS模式的基石。

 

 

 

其它链接 可以更好的了解:

官方开源, 也有文档可也查阅!

 

阅读更多

没有更多推荐了,返回首页