Unity ECS学习笔记(7)System执行顺序

2023-05-16

最近在学习unity的ecs框架,转载几篇写的比较好的文章帮助理解

原文日期 2019-12-5 避免误导未来使用正式版的开发者。

 

1.逻辑的先后顺序

我们已经知道,System的OnUpdate函数会在每一帧自动被调用。

唔,实际上,更准确的,应该分两种情况:

ComponentSystem的OnUpdate:每帧都会被调用。

JobComponentSystem的OnUpdate:取决于Job里筛选出来的实体数量是否大于0,如果是,则每帧都会调用OnUpdate;如果筛选出来的实体数量是0,那么,OnUpdate不会被调用。

这个不太重要。

重要的是,我们的System是处理游戏逻辑,游戏逻辑肯定就会涉及到先后顺序。

比如…玩家走到某个地方后,我才能做一些操作。假设【走动的逻辑】和【做一些操作的逻辑】分别在两个System里。那么,【走动的逻辑】的应该在【做一些操作的逻辑】前面执行。

这时候就涉及到先后顺序了,没错,为了解决这类问题,System的OnUpdate函数的执行是有先后顺序的。

2.系统分组(ComponentSystem Group)

在了解系统如果控制先后顺序之前,需要先了解系统的分组。

唔,其实很简单,就是分组…

比如,SystemA和SystemB都属于一个叫做SystemGroupHello的分组(名字无所谓),SystemC和SystemD属于SystemGroupOther分组。

就是这么简单,就是我们所认知的普通的分组概念。

3.System的执行顺序(System Update Order)

InitializationSystemGroup(负责初始化工作的系统分组)

SimulationSystemGroup(负责逻辑运算的系统分组)

PresentationSystemGroup(负责图形与渲染工作的系统分组)

以上三个是ECS默认的系统分组,很重要,这三个分组里的System从上到下按照顺序被执行。(实际上SystemGroup本身也属于System,也会被调用OnUpdate函数)。

(以上三个分组的中文翻译参考来源:https://connect.unity.com/p/unity-ecs-wu-liao-jie-systemzhi-xing-shun-xu)

 

  • InitializationSystemGroup

    • BeginInitializationEntityCommandBufferSystem
    • CopyInitialTransformFromGameObjectSystem
    • SubSceneLiveLinkSystem
    • SubSceneStreamingSystem
    • EndInitializationEntityCommandBufferSystem
  • SimulationSystemGroup

    • BeginSimulationEntityCommandBufferSystem
    • TransformSystemGroup

      • EndFrameParentSystem
      • CopyTransformFromGameObjectSystem
      • EndFrameTRSToLocalToWorldSystem
      • EndFrameTRSToLocalToParentSystem
      • EndFrameLocalToParentSystem
      • CopyTransformToGameObjectSystem
    • LateSimulationSystemGroup
    • EndSimulationEntityCommandBufferSystem
  • PresentationSystemGroup

    • BeginPresentationEntityCommandBufferSystem
    • CreateMissingRenderBoundsFromMeshRenderer
    • RenderingSystemBootstrap
    • RenderBoundsUpdateSystem
    • RenderMeshSystem
    • LODGroupSystemV1
    • LodRequirementsUpdateSystem
    • EndPresentationEntityCommandBufferSystem

    以上全部都是ECS自带的System,这是基于0.3.0版本,以后的版本可能会发生变化。

    注意粗体部分的内容:InitializationSystemGroup,SimulationSystemGroup,PresentationSystemGroup。

    这三个是我们刚刚提到的默认系统分组,实际当中,我们大部分人可能都会在默认的分组下搞事情。

    每个分组下有很多个System,而某些System下又可能包含子System。

    至于这些System有什么用,大家当然是先不用管了。

    以上贴出的所有System,都会按照罗列的顺序执行OnUpdate函数,如果System又包含了子System,那么就子System也会执行OnUpdate函数。

    这个有什么用呢?大家可以理解为”生命周期”(实际上官方没有提到这个东西),这些按顺序执行的System,会影响到我们的某些决策。

    比如,我们想在初始化之前搞事情,那就看看初始化的第一个System是谁,然后让我们自己的System在它之前执行。

    如果大家之前有看过Entity Debugger(Window->Analysis->Entity Debugger)的话,应该就会发现,上面列出的部分System就在Debugger里:

    Debugger里的System也是按照执行顺序逐一罗列的,未来我们新增的System也会出现在这里。

    4.控制System的执行顺序

    等等,怎么样可以让我们的System在别的System之前搞事情呢?

    我们来看看三个特性(Attribute)

    UpdateInGroup:指定当前System在哪个分组下

    UpdateBefore:指定当前System在哪个System之前执行

    UpdateAfter:指定当前System在哪个System之后执行

    我们直接看代码,随便创建一个场景,然后场景一个System类:

    1

    2

    3

    4

    5

    6

    7

    using Unity.Entities;

     

    [UpdateBefore(typeof(SceneSystem))]

    public class MutouSystem : ComponentSystem

    {

        protected override void OnUpdate () { }

    }

    我创建了一个很简单的System,但是附加了UpdateBefore特性,并指定了SceneSystem类型。

    这样的话,我们的MutouSystem肯定就会在SceneSystem之前执行了。

  • 然后,什么都不用做,直接运行,然后看看Entity Debugger:

  • 怎么样,MutouSystem是不是出现在SceneSystem之前了…

    对…没错…才怪啊喂!竟然不是!很奇怪,MutouSystem出现的地方和我们想象的不一样,这是为什么呢?

    唔,很重要的一点,System的执行顺序首先是按照System Group排序的,比如InitializationSystemGroup一定是在SimulationSystemGroup之前执行,那么,InitializationSystemGroup下的所有System肯定也是在SimulationSystemGroup下所有System之前执行。

    有点绕,换句话说,先按分组排序,然后分组内部自己再排序,无论你内部怎么排序,都不可能跨越分组的排序。

    所以,我们要指定System的执行顺序,首先就得确认System所属的分组,然后System就在分组内部调整排序。

    如果我们不知道System所属分组,那么,它就会默认分配到SimulationSystemGroup分组下。

    所以,我们的MutouSystem是属于SimulationSystemGroup分组的,而这个分组下不存在SceneSystem,因此,我们的UpdateBefore特性是无效的。

    于是,改改代码:

    1

    2

    3

    4

    5

    6

    7

    8

    using Unity.Entities;

     

    [UpdateInGroup(typeof(InitializationSystemGroup))]

    [UpdateBefore(typeof(SceneSystem))]

    public class MutouSystem : ComponentSystem

    {

        protected override void OnUpdate () {}

    }

    我在MutouSystem顶部又加了一个UpdateInGroup特性,指定MutouSystem所属分组,于是,再次运行:

    好了,正常了。

    不过,MutouSystem和SceneSystem中间还隔了很多System,也就是说,UpdateBefore只能保证在某个System之前执行,而不能保证是严格地在某个System的上一个执行。

    我们再改改,新增一个System:

    1

    2

    3

    4

    5

    6

    [UpdateInGroup(typeof(InitializationSystemGroup))]

    [UpdateAfter(typeof(MutouSystem))]

    public class LoveSystem : ComponentSystem

    {

        protected override void OnUpdate () {}

    }

    这次我们指定LoveSystem在MutouSystem之后执行,运行看看效果:

    结果和我们预想一样。

    我们再改改,把MutouSystem放到SceneSystem之后执行:

    1

    2

    3

    4

    5

    6

    [UpdateInGroup(typeof(InitializationSystemGroup))]

    [UpdateAfter(typeof(SceneSystem))]

    public class MutouSystem : ComponentSystem

    {

        protected override void OnUpdate () {}

    }

    运行看看效果:

    好,依旧完美,LoveSystem永远跟在MutouSystem身后了。

    好了,关于System的执行顺序,就介绍这么多吧。

     

    注意,本系列教程基于DOTS相关预览版的Package包,是预览版,不代表正式版的时候也适用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Unity ECS学习笔记(7)System执行顺序 的相关文章

随机推荐