UnityECS中的“S”
来源:https://www.youtube.com/watch?v=k07I-DpCcvE
一个System的基础结构
通常一个System是每一帧都运行的。
1 | [ ] |
- 每一个System实例都属于一个World
- 基本上,一个World里的Entities只会被自己World里面的System处理。这只是一种原则,其实System内的代码和Mono Behaviour的代码可以处理任何world里的Entities。
- SystemState 包含了此System所在的World和EntityManager
SystemGroup
我们可以使用SystemGroup来给某个World的System进行层级处理。
1 | public class MySystemGroup : ComponentSystemGroup |
System在Group内的执行顺序
SystemGroup的更新方式是可以被重载修改的,一旦修改,当前Group下的所有System更新方式都会改变。
默认情况下,一个SystemGroup内的各种System是通过伪随机数排序的,Group内部System的Update顺序也根据这个排序进行。当Group内发生一个System增删操作时,Group需要重新排序。
如果你想控制一个System在SystemGroup中的排序来保证它和其他System的Update顺序,需要添加UpdateBefore
特性和UpdateAfter
特性
1 | [ ] |
在WIndows——Entities——System窗口中,展示了各个SystemGroup随机后的顺序:
- Initialization System Group:各种初始化System
- Simulation System Group:核心游戏逻辑需要的System
- Presentation System Group:渲染需要的System
我们一个SystemGroup中重载OnUpdate,可以让其内部的System有选择地进行更新,或者每一帧更新多次。
在Simulation System Group中,Fixed Step Simulation System Group内的System按照每秒的fixed rate进行更新,所以会出现有时其内部的System在好几帧都不更新,或者每帧更新好几次的情况。
System放在特定的Group中
当进入playmode时,Unity ECS System会有一个自动引导过程,先创建一个Default World,在向这个World中放入一套标准程序集的实例和上面的三种默认SystemGroup和各种定义的SystemGroup的实例。
如果想把自定义的System放在一个特定的SystemGroup中,可以使用UpdateInGroup
特性
1 | [ ] |
关闭System的自动引导
如果你想完全关闭Unity ECS System的自动引导,需要在IDE中添加脚本定义:
1 |
使用了这个之后,我们就能够创建任何自定义的World,在其中加入想要的System实例和SystemGroup实例。
SystemState
在一个System struct中,SystemState 除了包含此System所在的World和EntityManager外,还包含了GetEntityQuery
和GetComponentTypeHandle<T>
两个需要介绍API,前者顾名思义,后者用来对chunks内的component arrays进行操作来获得component。
注意:
在System内只能使用SystemState提供的GetEntityQuery
和GetComponentTypeHandle<T>
这个API来获取queries和component type handles,不能使用EntityManager。原因是:
SystemState提供的GetEntityQuery
和GetComponentTypeHandle<T>
可以将component type注册到这个System当中去(这两个API都会进行这个操作)。
System Dependency
将component type注册到这个System当中是很重要的,想要理解这一点,我们还需要知道在SystemState当中还有一个重要的属性:Dependency。Dependency是一种Job Handle
当一个System 执行Updates之前,需要先做两件事情:
- SystemState的Dependency调用
isCompleted
- 就像在Job System中讲的,当当前System的Dependency调用isCompleted时,联系这个Dependency的Job Handle,也就是其他System的Dependency才会执行,而其他System如何知道自己需要当前System的Dependency呢?就是通过SystemState提供的
GetEntityQuery
和GetComponentTypeHandle<T>
获取的queries和component type handles,其他System只要发现自己注册进的component type相同,就明白自己的Dependency是当前System
举个例子,如果一个Foo component注册进了My System里,那其他也被Foo Component注册的System的Dependency就会设为My System的Dependency,所以能够将这些Job Handle统一起来,这个过程是在每帧都做一次的。这样做的目的是为了我们在System内部使用Job时,这个Dependency是及时包含所有dependency信息的。
说白了,这个Dependency就是为了方便在System中使用Job System:
- 所有在当前System中Schedule的Job必须都直接或间接地依赖Dependency属性。
- 在System Update Returns之前,Dependeny属性必须赋予一个Job Handle,这个Job Handle是当前System所有的Schedule的Job的Job Handle的组合。
1 | //...in a system |
当然,如果上面代码中OtherJob
的dependency是MyJob
,我们直接把state的Dependency设为otherHandle即可。
1 | //...in a system |