今回はECSのComponentSystemも実行順番をコントロールする方法についてです。
- ComponentSystemの実行順番は非常に重要
- 実行順の確認方法
- 特定のComponentSystemの前に実行する、後に実行する
- UpdateInGroupで処理のタイミングを大まかに纏める
- 関連
ComponentSystemの実行順番は非常に重要
ECSは無数に存在するComponentDataをComponentSystemで一括制御する事で実現しています。ソレが単なる技術デモでComponentDataとComponentSystemが一対一の関係なら大した問題にはなりません。
問題になるのは複数のComponentSystemで複数のComponentDataを制御する場合で、その場合ComponentSystemの実行順によって結果が変わってきます。
例えば「Entity生成」「Entityの向きをターゲットへ変更」「Entityの向きに従って前方をチェック」「当たっているならEntityを生成」といったシステムを考えてみます。
これが順番通り動くなら問題はないのですが、「Entityの向きをターゲットへ変更」の前に「Entityの向きに従って前方をチェック」が入ると、最初に向いていた方へチェックが入る事になり、思ったとおりの結果を得られなくなります。
実行順の確認方法
まず実行順の確認方法です。
使っていて気づいたのですが、EntityDebuggerのSystem並び順は実行順で並ぶみたいです。
例えば下の場合、SampleSystem1~3を用意したのですが、実行してみると実行順はSampleSystem 2、SampleSystem 3、SampleSystm1の順でした。
まぁ一番確実なのはProfilerで順番を見る事ですが、処理時間が短いと探すのが大変なので、多分大丈夫だろう程度で使えそうです。
特定のComponentSystemの前に実行する、後に実行する
ComponentSystemはScript Execution Orderのような機能はありません。その代り、UpdateAfter
とUpdateBefore
というAttributeが使えます。
このAPIはComponentSystemを指定したシステムより前もしくは後に実行するように指定するというものです。PlayerLoopに登録する時、依存関係を見て実行順を作ってくれるとか云々。
下のコードの場合、System1よりSystem2が先に実行されるようになります。
なお、実はこのUpdateAfter
とUpdateBefore
、PlayerLoopのAPIにも使用できます。例えば下のように記述すると、Updateの前後に処理を挟むことも出来ます。
なお実行のタイミングによってEntityDebuggerの表示される場所が微妙に変わる事があります。例えば下のコードでは[UpdateBefore(typeof( UnityEngine.Experimental.PlayerLoop.Initialization))]
と記述した所、所属するグループがInitializationに変化しました。
UpdateInGroupで処理のタイミングを大まかに纏める
次にUpdateAfterを特定のシステムではなく、システムをまとめた「グループ」を指定してみます。これは複数人で開発する時に重要な要素です。
例えば[A][B][C]という3つのシステムがあり、この処理後に何かをしたい場合です。この場合はUpdateAfter(c)で良いです。
では[A][B][C]に追加で[D]というシステムが増え、処理結果は[D]以降に取らなくてはいけなくなった場合、チーム全体にDというシステムが増えた事を共有する必要が出てきます。
そこでグループを使用します。
[A][B][C]を纏めてグループ:[G]に登録しておきます。そうすると他の人はABCの最後のシステムを把握せずともUpdateAfter(G)で良くなります。逆に「前」で実行する場合もUpdateBefore(G)で良くなります。
gist.github.com上のコードを実行すると、ABCの前にX1、後にX2が実行されます。新しいシステムを追加しても、グループで囲ってる範囲に入り込むことはありません。
なお、Xをグループに紛れ込ませるとバグります。