Unity2018新功能之Entity Component System(ECS)一
Entities介绍
Entities是Unity2018新引入的一个全新游戏设计框架,我们称之为实体组件系统(Entity Component System,简称ECS),它的出现使我们能够集中精力解决实际问题:构成游戏的数据和行为。它利用了C# Job System和Burst,使我们能够充分利用当今的多核处理器。通过从面向对象的设计转向面向数据的设计,我们将更容易重用代码,也更容易让其他人理解和使用ECS。
在Unity2018引入Entities之前,其实ECS框架早已经出现,但是ECS还是因为守望先锋采用了这个框架才被我们所熟知,后来Git上面出现了一个Entitas的插件可以直接用在Unity上面,我在以前的公司参与过一个项目就是用的Entitas插件。
实体Entity:一个ID,它可以用于间接的组件查找,用于在容器里面遍历。
组件数据ComponentData:存储在实体中的数据。
组件系统ComponentSystem:处理游戏,系统逻辑和行为的地方。
组Group:组件系统运行所需的ComponentData列表,相对于判断条件。
| Entities名称 | 传统ECS名称 |
| Entity | Entity |
| ComponentData | Component |
| ComponentSystem | System |
| Entities | MonoBehaviour |
| Entity | GameObject |
| ComponentData | Component的字段变量 |
| ComponentSystem | Component的Update方法 |
Entities的安装
- 点击菜单Window > Packages Manager > All,选择Entities,然后点击Install按钮安装。
- 打开PlayerSettings>Other Settings>Scripting Runtime Version,我们选择.Net 4.x Equivalent。
注意:安装Entities后会报错是因为Unity默认的Scripting Runtime Version是.Net 3.5 Equivalent,我们改为.Net 4.x Equivalent即可。
Entities的使用
我们用一个简单的例子来讲解一下Entities的使用方法。
我们先用传统的写法写一个Cube的自转。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class RotationCube : MonoBehaviour { public float speed; // Use this for initialization void Start () { } // Update is called once per frame void Update () { transform.Rotate(Vector3.up * speed * Time.deltaTime); } }
接下来我们混合加入ECS,把上面的代码拆分成Component和System。我们先写一个Component,只有一个字段变量。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class RotationCubeComponent :MonoBehaviour { public float speed; }
然后我们再写一个System,作为逻辑的处理。首先我们要继承ComponentSystem,然后重写OnUpdate,这里相当于MonoBehaviour的Update,我们在这里处理逻辑。Group则是组件系统运行所需的ComponentData列表,可以随意命名,我们可以在这里写很多不同的Group,作为处理逻辑的条件。GetEntities<Group>()表示获取指定的实体,所有符合条件的实体都将被获取到(这里符合条件的是所有带有RotationCubeComponent组件的实体都将被获取到)。
using System.Collections; using System.Collections.Generic; using Unity.Entities; using UnityEngine; public class RotationCubeSystem : ComponentSystem { struct Group { public RotationCubeComponent rotation; public Transform transform; } protected override void OnUpdate() { foreach (var enitites in GetEntities<Group>()) { enitites.transform.Rotate(Vector3.up * enitites.rotation.speed * Time.deltaTime); } } }
我们也可以用另外一种方式来写System。Inject表示注入数据,在Unity启动时会自动赋值合适的值
using System.Collections; using System.Collections.Generic; using Unity.Entities; using UnityEngine; public class RotationCubeSystem : ComponentSystem { struct Group { public readonly int Length; public ComponentArray<RotationCubeComponent> rotationCubeComponents; //public RotationCubeComponent rotation; //public Transform transform; } [Inject] Group group; protected override void OnUpdate() { //foreach (var enitites in GetEntities<Group>()) //{ // enitites.transform.Rotate(Vector3.up * enitites.rotation.speed * Time.deltaTime); //} for (int i = 0; i < group.rotationCubeComponents.Length; i++) { group.rotationCubeComponents[i].transform.Rotate(Vector3.up * group.rotationCubeComponents[i].speed * Time.deltaTime); } } }
最后,我们创建一个Cube,附加上GameObjectEntity给他一个实体ID标识,附加上RotationCubeComponent组件,我们把旋转速度调为100,再创建几个Cube并且附加上GameObjectEntity,但不附加RotationCubeComponent组件,运行Unity后发现,带有RotationCubeComponent组件的实体会自转,没有带RotationCubeComponent组件的实体不会自传。
我们讲的这个案例主要是让大家了解ECS这个框架的基本思想和传统的开发思路的区别,即数据和逻辑分离。
我将在下一篇文章中继续深入讲解ECS的框架。
浙公网安备 33010602011771号