基本概念
ECS(Entity-Component-System)由三部分组成
- Entity:是一个id,目的是将Component逻辑地分组在一起,在源码中是一个结构体,包含一个int类型的id和int类型的版本号
- Component:只是数据存储(没有代码逻辑的struct)
- System:对数据进行逻辑处理,本身不含数据
我们的处理流程是创建一个Entity,包含一系列Component,然后用System来处理Component数据,比如修改Translation或者拿出使用Component数据计算的结果作为后面的流程使用
Entity
这个id是稳定的使用它们来存储对另一个Component或Entity的引用。例如,层次结构中的子Entity可能需要引用其父Entity。
查看源码如下
结构体里面包含包含一个int类型的id和int类型的版本号,唯一的目的就是标识Component 把他们串在一起
创建Entity
由EntityManager来创建Entity,EntityManager.CreateEntity提供了多个重载方法
说到Entity就不得不提EntityManager,相关的Entity操作都是由他完成的
- 创建Entity
- 为Entity添加关联的Component
- 删除Entity
- 获取相关的数据块
一个world中包含一个EntityManager实列
后面会介绍这些相关的操作
Component
Component:是一个结构体(struck),只包含数据,没有方法,不进行逻辑处理
内存分布
- 原型(archetype):拥有相同组Component属于同一个原型(archetype)
- 举例
A拥有Component:Position,Ratation,Renderer,RigidBody
B拥有Component:Position,Ratation,Renderer,RigidBody
C拥有Component:Position,Ratation,Renderer
A,B 就是相同的archetype,C与A,B就不是,因为C少一个Component
- 举例
- 块(Chunk)相同archetype储存在同一个内存块中,称为Chunk,每个Chunk16k大小,一系列Chunk直接是列表的形式连接起来的称之为archetypes
- 在内存中一个archetype有多少类型component就是有多少个数组
- 在Chunk内部是数组的形式,但是里面数据是不能保证顺序的,如有A,B,C,D 四个数据删除B会把最后一个位置补上来,也就是A,D,C.一般情况下我们不关心里面数据的顺序,正因为如此拆分到多个job线程才方便。
由于这种数据组织方式,对每一个Entity 添加或者减少component都好改变改Entity的archetype(structural change),即改Entity包含的component都需要移动到另外的archetype中,或者创建一个archetype,这些都是数据拷贝会产生消耗,这点需要注意
结构改变( structural change)
结构改变都会引发ECS的同步点
- 创建Entity
- 销毁Entity
- 给Entity添加组件
- 移除Entity组件
- 修改共享组件的值
结构改变不只是同步点影响,对于数据的直接引用都将要失效如:DynamicBuffer
以及直接访问数据的方法如:ComponetSystemBase.GetComponentDataFormEntity.
同步点
同步点会等待之前的全部job任务执行完成之后,同步点也会阻止新的job执行。直到同步点任务完成,我们应该尽可能避免
- 避免同步点
可以使用 entity command buffers (ECB) ,在各需要(立即执行的地方)在同步点处理的任务集中起来到一个地方统一处理。ECB 在帧后面执行
后面会详细介绍ECB
Systems
ECS里面的S用来执行逻辑的地方,里面不包含数据。用于把component 数据从当前状态转换成下一个状态,如当前位置根据速度和时间更新
unity ECS 会自动检查项目中的System类,并在运行时实列化他们
- 默认时在当前默认World
- 默认在SimulationSystemGroup
World:ECS运行的一个独立环境,每个world有一个EntityManager实列,每个world触发同步点的时候不会影响另外一个
SystemGroup:系统更新组SimulationSystemGroup 是其中之一,后面会介绍
(系统类型)System types
ECS提供了好几种不同的类型的System一般我们的逻辑使用的继承SystemBase还有一些特殊目的的类型
- SystemBase:system 基类
- EntityCommandBufferSystem:在SystemGroup 每个类型在开始和结束都提供一个,主要用来解决同步点的问题
- ComponentSystemGroup: 提供控制不同System之间的执行顺序,ECS 默认提供了基本的3个Group
- GameObjectConversionSystem: