天天看點

Unity Entity Component System --- System Update Order

通過Component System Groups來指定systems的執行順序。可以通過在系統的類的定義上使用[UpdateInGroup] Attribute來指定該系統在哪個group中執行。還可以使用[UpdateBefore] [UpdateAfter]來指定在該Group内的執行順序。

ECS架構建立了一組預設的system groups,可以利用這些groups來控制我們的系統的執行順序。還可以将一個Group建立到另一個Group内,這樣來進一步控制系統的執行順序(Group是可以嵌套的)。

Component System Groups

ComponentSystemGroup類組織若幹相關的Systems到一起,并以一定的順序執行。ComponentSystemGroup是ComponentSystemBase的派生類,是以它具有一個componenty system應該有的特性,可以跟其它系統關聯,有OnUpdate方法,等。最主要的,這意味着Component System Croups可以嵌套到其它Component System Group中,建立層次關系。

預設地,當ComponentSystemGroup的Update調用時,它會調用所有儲存的系統清單裡的系統的Update()。如果一個子Component System是group時,會遞歸調用它的子系統清單,按照深度優先周遊整棵層次樹。

System Ordering Attributes

目前系統維護了一套順序Attributes:

  • [UpdateInGroup] — 為該系統指定是哪個group的成員。如果沒有該修飾,預設會添加到World的SimulationSystemGroup中。
  • [UpdateBefore] [UpdateAfter] — 控制組内系統的相對執行順序。使用這些修飾的系統類型,必須在同一個group中。對于跨group的順序,按照包含2個systems的最深的group決定:

    例如:SystemA在GroupA,SystemB在GroupB,GroupA和GroupB都在GroupC,那麼SystemA和SystemB的隐含順序為Group A和GroupB的順序。

  • [DisableAutoCreation] — 禁止預設 World初始化時自動建立System。之後需要自己明确的建立和更新這些系統。當然,也可以建立完系統後,添加到一個ComponentSystemGroup中,那麼系統的Update會被Group自動調用。

Default System Groups

預設的World包含了一個ComponentSystemGroup執行個體的層級樹。僅三個根級system groups被添加到Unity的邏輯循環中。下面的清單展示了這三個組中預定義的子系統:

  • InitializationSystemGroup(在主循環的Initialization階段結束時執行)
    • BeginInitializationEntityCommandBufferSystem
    • CopyInitialTransformFromGameObjectSystem
    • SubSceneLiveLinkSystem
    • SubSceneStreamingSystem
    • EndInitializationEntityCommandBufferSystem
  • SimulationSystemGroup(主循環的Update結束時執行)
    • BeginSimulationEntityCommandBufferSystem
    • TransformSystemGroup
      • EndFrameParentSystem
      • CopyTransformFromGameObjectSystem
      • EndFrameTRSToLocalToWorldSystem
      • EndFrameTRSToLocalToParentSystem
      • EndFrameLocalToParentSystem
      • CopyTransformToGameObjectSystem
    • LateSimulationSystemGroup
    • EndSimulationEntityCommandBufferSystem
  • PresentationSystemGroup(主循環的PreLateUpdate結束時調用)
    • BeginPresentationEntityCommandBufferSystem
    • CreateMissingRenderBoundsFromMeshRenderer RenderingSystemBootstrap
    • RenderBoundsUpdateSystem RenderMeshSystem LODGroupSystemV1
    • LodRequirementsUpdateSystem
    • EndPresentationEntityCommandBufferSystem

這個清單的内容目前還在優化中,會發生變化。

Multiple Worlds

可以建立除了預設World的多個其它Worlds,或者替換預設World。同樣的Component System可以建立到多個World中,并且可以以不同的更新頻率,在不同的時間點更新。

現在,不支援手動地更新World内的系統;你隻能控制某個系統被建立到哪個World中的哪個System Group中。也即是,自定義的WorldB可以執行個體化SystemX和SystemY,并将SystemX添加到預設World的SimulationSystemGroup,将SystemY添加到預設World的PresentationSystemGroup中。這些Systems的順序關系在它們所在的Group中被管理,并按照Group的順序更新。

為了實作這種用法,提供了ICustomBootstrap 接口類:

public interface ICustomBootstrap
{
	List<Type> Initialize(List<Type> systems);
}
           

實作該接口時,一個完整的System類型的清單被傳遞到Initialize()方法中,而且它在預設World初始化前調用。自定義的啟動加載器可以周遊這個清單并且建立需要的System。可以傳回一個System清單,該清單内的系統将被預設World初始化。(不傳回則不建立)

例如,下面是個典型的MyCustomBootstrap.Initialize()的實作過程:

  1. 建立一個World和它的最上層的ComponentSystemGroups。
  2. 對所有的System類型:

    周遊ComponentSystemGroup層次,找到該System應該被添加到哪個Group中。

    如果找到Group,在該World中建立System并調用group.AddSystemToUpdateList()接口添加到層次結構中。

    如果沒有找到要添加到的Group,那麼,添加到傳回的System類型清單中,傳回到DefaultWorldInitialization。

  3. 調用所有頂層的groups的group.SortSystemUpdateList()。

    Optionally add them to one of the default world groups

  4. 傳回未處理的系統的清單給DefaultWorldInitializtion。

注:ECS架構通過反射使用者自定義的ICustomBootstrap實作。

建議:

  • 用[UpdateInGroup]來指定你的系統在哪個Group中執行。如果不指定,預設是SimulationSystemGroup。
  • 用手動更新的ComponentSystemGroups來在Unity主循環的其它階段更新Systems。為ComponentSystem或者ComponentSystemGroup添加[DisableAutoCreation]修飾來避免被自動添加到預設的SystemGroups中,可以手動地通過接口World.GetOrCreateSystem()來建立System并在主線程中調用MySystem.Update()來執行。這是将System添加到主循環其它階段去執行的簡單的辦法。(例如,你可以建立一個系統,在一幀的前面或者後面執行。)
  • 盡可能的使用已有的EntityCommandBufferSystem,而不要自己建立。一個EntityCommandBufferSystem代表一個SyncPoint,主線程要等待所有工作線程的工作完成,以執行它的緩存的EntityCommandBuffers。重複利用預定義在頂層SystemGroup中的Begin/End Systems來避免SyncPoints,提升效率。
  • 避免将自定義邏輯寫到ComponentSystemGroup.OnUpdate()中。因為ComponentSystemGroup本身是個ComponentSystem,讓人想要将使用者邏輯添加到它的OnUpdate()中來執行一些邏輯,建立Jobs,等。我們反對這麼做,因為從表面上很難馬上确定,它的Execute是在group‘s的其它成員System之前還是之後。最好就是讓SystemGroups來執行grouping機制,而在其它的System中實作我們的邏輯,并明确地指定它們的相對執行順序。