[toc]

# 前言

看了一下午 Entitas, 最终发现这个插件的问题有点多,所以选择一个较轻量级的框架进行 ECS 的学习,即 Svelto-ecs

# 我所理解的 ECS

通常 ECS 的架构会如上图所示,即 System 驱动 Entity, 而 Entity 下则挂上属于他的 Component 组件,ECS World 负责驱动所有的 System. 其中,System 负责管理 Entity 和 Component 通常在 C# 中为了实现高效的 ECS, 会将 Component 抽象成只有数据的 struct , 而 Entity 则负责维护他身上所有的非托管的组件数据 业务逻辑实际上只是负责更改 Component 的基础数据,而不负责更改实际的 Unity 层的组件数据,所以这就需要再从 Componengt 中抽象出一个 View 层
即构成如下的结构 即在 Logic 的最后阶段,通过 View 对实际的数据进行更新 基于这个结构还可以进行进一步的优化,由于所有的 Component 是在逻辑的结束,渲染前进行更新的,则可以在更新前对所有的数据进行统一的处理,而 统一的处理 ,则意味着大量相同的逻辑运算。而大量相同的逻辑运算则可以使用 Unity 的 Jobsystem 进行多线程的优化,如下所示:

# 抽离渲染

当然,如果想要进一步的将渲染也从 Unity 接管出来,其实也可以做到。同时还可以借助 StructedBuffer 将同一个 Mesh, 不同参数的渲染进行合并,只不过会产生更大的编程方面的消耗

# Svelto.ECS

Svelto.ECS 是一款开源的 ECS 系统,它的底层已经无缝衔接了 Unity 的 NativeCollection , 且使用了 IOC (控制反转) 的思想进行组件与实体的结合。 Svelto.ECS 与传统 ECS 的差别:

  • Svelto 将 System 改成 Engine
  • Entity 改成 Descriptor
  • Feature (Systems/World) 改成了 EngineRoot
  • 使用了 IOC 进行组件与实体的结合

# Svelto.ECS 实体创建流程

上图是 Svelto.ECS 的实体构建流程,最终的 Components 在经过一系列操作后会被保存到 _groupEntityComponentsDB 中。即类似于数据收集器 Collection

但是我还是觉得这个框架将 ECS 的构建流程复杂化了,而且复杂的不止一星半点 而且有一个很糟糕的点,以 Animation 为例,不知道是否是为了保证数据的非托管性,导致它的框架在更新 Animation 时,直接暴力的 GetCOmponent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public void Step()
{
var groups = entitiesDB.FindGroups<GameObjectEntityComponent, AnimationComponent>();
//animation sync
GroupsEnumerable<GameObjectEntityComponent, AnimationComponent> groupsEnumerable = entitiesDB
.QueryEntities<GameObjectEntityComponent, AnimationComponent>(groups);

foreach (var ((entity, animations, count), _) in groupsEnumerable)
{
for (int i = 0; i < count; i++)
{
ref var animationState = ref animations[i].animationState;

if (animationState.hasBeenSet == true)
{
var go = _manager[entity[i].resourceIndex];

//could probably do with a check if the state actually changed
var animator = go.GetComponent<Animator>();

animator.SetBool(animationState.animationID, animationState.state);

animationState.hasBeenSet = false;
}
}
}
}