来源:https://github.com/Unity-Technologies/EntityComponentSystemSamples
可以在Git上获取最新的ECS示例项目
ECS项目指南
- 打开Unity编辑器(最好是2019.1及以上)
- 创建一个新项目(什么项目都可以,推荐先使用3D)
- 打开PackageManager,并显示Preview Package
- 添加下列包至项目中:Entities、Hybrid.Renderer、Burst、Collections、Jobs、Mathematics
来源:https://docs.unity3d.com/Packages/com.unity.entities@0.0/manual/index.html
我会对官方文档内容略作整理,有需要可以查看官方文档
ECS简介
ECS即实体组件系统,是Unity数据导向技术堆栈的核心,由三个部分组成:
- Entity——组成游戏/项目的实体
- Component——与实体相关联的数据,但数据本身并不是按照实体组织(这种组织上的差异就是面向对象和面向数据的关键性差异)
- System——负责改变实体数据的逻辑
0、管理器——World/EntityManager
你可以看你喜欢创建许多World,通常会常见一个用于逻辑的World和一个用于渲染的World
一个World中包含一个EntityManager和一堆ComponentSystems(在Components中会解释)
0.1、World
- 通常而言,我们会有一个默认的World,这个World会在我们进入Play Mode的时候自动创建,并且会将所有的ComponentSystems填充进这个World
- 当然你也可以禁用这个默认的World,然后通过一个全局的声明,使用自己创建的World取代它
0.2、EntityManager
- EntityManager提供用于创建,读取,更新和销毁实体的API
- 一个World有一个EntityManager,这个EntityManager负责管理该世界所有的实体
1、实体——Entity
实体本质上就是一个ID,你可以认为它是一个超级轻量级的GameObject,它甚至可以没有名字;实体的ID是唯一的,并且这也是唯一的方式去储存另一个实体或组件的方式。
从0.2我们知道,一个EntityManager管理者所有的Entity,因此这个EntityManager维持着一系列的Entities,管理着与实体相联系的数据,以此来获得最佳的性能。
尽管实体并没有类型,但是可以通过与这些实体(Entity)相联系的组件(Component)的类型来进行分类。当你创建一个实体,并且对其添加了组件,EntityManager就会对这个实体上的独一无二的组件组合保持追踪,而这个独一无二的组件组合,我们就称之为Archetype(原型)。
当你向一个实体添加组件的时候,EntityManager就会创建一个EntityArchetype(实体原型)结构,你可以使用现有的EntityArchetype来创建新的实体,也可以事先创建EntityArchetype并用其来创建实体。
1.1、创建实体
- 创建实体最简单的方法就是使用Unity编辑器,你可以在运行时将场景中的GameObjects或者Prefabs转换成实体
- 对于游戏或程序中更多的动态场合,可以通过创建一个生成系统(spawning system)来创建多个实体
- 可以通过EntityManager.CreateEntity函数来创建一个实体
1.1.1、通过EntityManager创建实体
通过EntityManager.CreateEntity函数来创建一个实体,这个实体会和创建它的EntityManager在同一个World中
可以通过以下几种方式创建单个实体
- 通过一组ComponentType来创建一个拥有组件的实体
- 通过EntityArchetype来创建一个拥有组件的实体
- 通过Instantiate克隆一个数据相同的实体
- 创建一个空的实体然后为其添加组件(可以马上添加,也可以按照需求添加)
可以通过以下几种方式创建多个实体
- 通过CreateEntity函数使用EntityArchetype来创建多个实体并放入NativeArray中
- 通过Instantiate克隆多个数据相同的实体并放入NativeArray中
- 通过CreateChunk函数明确的创建一个区块(chunk),根据指定的原型创建指定数量的实体
1.1.2、添加和删除组件
在创建了一个实体之后,我们就可以对这个实体添加或删除组件,在这个时候,该实体的原型收到了影响发生了改变,而EntityManager必须将改变后的数据移动到新的区块中,并压缩原区块中的组件数据。
- 导致实体结构更改(即添加删除组件、修改共享组件中的数据、释放实体)的行为都不能在Job中进行,因为这些操作都有可能会使当前Job中的行为无效
- 相反,通过使用EntityCommandBuffer添加指令来对实体结构进行更改,这些命令会在Job完成之后执行
1.1.3、迭代实体
迭代所有匹配组件的实体集,是ECS结构的核心(之后会说)