Unity ECS System在什么時候更新?如何自定義這個更新的時機?
在什么時候更新?
在其他用戶代碼都執行完之后。
去Netcode的ClientServerBootstrap里可以找到CreateLocalWorld函數,里面有類似這樣的代碼:
public static World CreateLocalWorld(string defaultWorldName = "Default World")
{
var world = new World(defaultWorldName, WorldFlags.Game);
var systems = DefaultWorldInitialization.GetAllSystems(WorldSystemFilterFlags.Default);
DefaultWorldInitialization.AddSystemsToRootLevelSystemGroups(world, systems);
ScriptBehaviourUpdateOrder.AppendWorldToCurrentPlayerLoop(world);
return world;
}
其中ScriptBehaviourUpdateOrder.AppendWorldToCurrentPlayerLoop就是將World更新附加到UnityEngine.LowLevel.PlayerLoop后面的函數。這個函數內容也很簡單,本質上是通過world.GetExistingSystemManaged分別獲得InitializationSystemGroup,SimulationSystemGroup和PresentationSystemGroup;然后作為PlayerLoopSystem的SubSystem,構造出新的PlayerLoop之后,通過PlayerLoop.SetPlayerLoop應用到當前環境里。
沒有Netcode的情況下也是類似的,只不過是通過DefaultWorldInitialization這個類來完成了。
如何自定義?
知道在哪里創建的,自然就知道該怎么自定義了。只要把ScriptBehaviourUpdateOrder.AppendWorldToCurrentPlayerLoop換成自己的東西就行了。比如:
var initGroup = world.GetExistingSystemManaged<InitializationSystemGroup>();
var simGroup = world.GetExistingSystemManaged<SimulationSystemGroup>();
var presGroup = world.GetExistingSystemManaged<PresentationSystemGroup>();
//找個地方調用initGroup.Update()
//找個地方調用simGroup.Update()
//找個地方調用presGroup.Update()
//順序不要搞錯了
以FishNet為例,就可以在TimeManager.OnPostTick里運行所有WorldSystemFilterFlags.ServerSimulation的System,于是這些基于GameObject的網絡庫也就可以用ECS設計模式了。
不過自定義了更新之后,在Editor的Systems界面里就看不到了,也算是一個小缺點吧。

浙公網安備 33010602011771號