
前回:UE5 State Tree に入門してみる - Self-Taught CODE Tokushima Tech Blog
前回はクイックスタートを行いましたが、今回はそこで利用した State と他の State に遷移する Transition の挙動を確認しておきます。
準備
STTask_PrintStateEvent
State がどのように呼ばれているかを確認します。基本的にはこのタスクしか使いません。
| 全体 |
|---|
![]() |
| Enter State 後の Finish Task 部分 |
![]() |
| variables |
![]() |
CallFinishTask:Finish Task を呼ぶかどうか- false の場合は Finish Task しない
ForceFailed:Finish Task する場合に失敗させるか- false の場合は、成功になる
DelayBeforeFinish:Finish Task 前に Delay を入れるか- false の場合は、Enter State 時に即 Finish となる
DelayDulation:Delay の長さ
Delay の設定に関しては、おそらく多くの場合、Enter State して即 Finish することは無いと思うのと、State の終了順での挙動確認のために入れています。
また、Tick に関しては、ログの抑制と Tick の呼ばれる順が見たかっただけなので Do Once としています。
BP_StudyTransitionActor
今回利用する Actor です。これにテスト用の State Tree を設定しています。
State Tree の Run Status の変化を見るためだけのイベントハンドラをつけています。
![]() |
![]() |
Debugger
Debugger を出しておきます。

State のイベントの呼び出し確認
| State Tree | Child_1 | Child_2 |
|---|---|---|
![]() |
![]() |
![]() |
# PIE 開始 [STTask_PrintStateEvent_C] [Child_1] Enter State [STTask_PrintStateEvent_C_0] [Child_2] Enter State [BP_StudyTransitionActor_C_1] State Tree Status Changed: Running [STTask_PrintStateEvent_C] [Child_1] First Tick [STTask_PrintStateEvent_C_0] [Child_2] First Tick # PIE 停止 [STTask_PrintStateEvent_C_0] [Child_2] Exit State [STTask_PrintStateEvent_C] [Child_1] Exit State [BP_StudyTransitionActor_C_1] State Tree Status Changed: Stopped
Enter Stateは Root からリーフに向かって実行- State Tree の Run Status は、リーフの選択ができた時点で
Runningのように見えるが、たまたまかも Tickも Root からリーフに向かって実行されているようExit Stateは逆にリーフから Root (遷移先) に向かっている- この例では、
Finish Taskを全く呼ばないので、Child_2の State の Task が終了せず PIE 停止まで動かない
State の終了の確認
親のみ終了
| Child_1 (親) | Child_2 (子) |
|---|---|
![]() |
![]() |
Debugger
| Start Frame | Next Frame |
|---|---|
![]() |
![]() |
Output Log
[Child_1] Enter State [Child_2] Enter State [Child_1] First Tick [Child_2] First Tick [Child_1] Finish Task # Finish したのは親 [Child_2] Completed Succeeded [Child_1] Completed Succeeded [Child_2] Exit State [Child_1] Exit State [Child_1] Enter State # 以降繰り返し
- Output Log から、Finish したのは親 (Child_1) であるとわかる
- その後、先に子 (Child_2) が成功で完了、続いて親が成功で完了している
- Debugger から、Start Tree 時点で
active statesはRoot,Child_1,Child_2が選ばれているのがわかる- 次のフレームに移動したところで、
State(s) Completedとなり、Child_2,Child_1,Rootの順で表記されている - 続いて
Tick Transitions - Trigger Transitionsになり、また Root からの選択が繰り返されている - これは、遷移先が現状 Root になっており、また Root が選ばれると
Child_2までの選択が繰り返されるからだろう
- 次のフレームに移動したところで、
子のみ終了
| Child_1 (親) | Child_2 (子) |
|---|---|
![]() |
![]() |
Debugger
| Start Frame | Next Frame |
|---|---|
![]() |
![]() |
Output Log
[Child_1] Enter State [Child_2] Enter State [Child_1] First Tick [Child_2] First Tick [Child_2] Finish Task # Finish したのは子 [Child_2] Completed Succeeded [Child_1] Completed Succeeded [Child_2] Exit State [Child_1] Exit State [Child_1] Enter State # 以降繰り返し
- 親のみ終了時と異なるのは以下
- Debugger で Next Frame の
Tick State TreeのTick Tasksで実行されているのが、先程はChild_2(終了しない方) だったが、今回もChild_1と終了しない方が実行されている。 - おそらく前の Tick で Finish Task されているため、そちらは実行されていないのだろう
- Debugger で Next Frame の
State の終了順序の確認
続いて、両方が終了する場合を確認する。
即親が失敗する

Delay 無しなので Enter State で即 Finish Task で失敗させる。
Output Log
[Child_1] Enter State [Child_1] Finish Task Failed [Child_1] Completed Failed [Child_1] Exit State [Child_1] Enter State # 以降繰り返し
Debugger

- Debugger を見ても、Output Log を見ても 子(Child_2)がそもそも選択されないことがわかる
- 親が Enter State 時点で失敗するのはあまり無いケースかもしれないが一応
親が失敗し、子が成功する
| 親が先 | ![]() |
![]() |
| 子が先 | Delay Duration を 0.2に |
Delay Duration を 0.1に |
親が先に失敗 Output Log
[Child_1] Enter State [Child_2] Enter State [Child_1] First Tick [Child_2] First Tick [Child_1] Finish Task Failed # 親が失敗 [Child_2] Completed Failed [Child_1] Completed Failed [Child_2] Exit State [Child_1] Exit State [Child_1] Enter State # 以降繰り返し
子が先に成功 Output Log
[Child_1] Enter State [Child_2] Enter State [Child_1] First Tick [Child_2] First Tick [Child_2] Finish Task Succeeded # 子が成功 [Child_2] Completed Succeeded [Child_1] Completed Succeeded [Child_2] Exit State [Child_1] Exit State [Child_1] Enter State # 以降繰り返し
0.1secの差をつけているので、終了のフレームがズレていると思われる- よって、それぞれ先に終了した方の結果で State の結果も
Failed/Succeededが決まっている
⚠️異なるパターン
いくつかサンプルを作っているとほぼ同じサンプルにも関わらず結果が変わるケースが出ました。
![]() |
![]() |
![]() |
親が先に失敗 Output Log
[Parent] Enter State [Child] Enter State [Parent] First Tick [Child] First Tick [Parent] Finish Task Failed [Child] Finish Task Succeeded # 親が先に成功しているのに子のログが出る時間を延ばしても同じ [Child] Completed Succeeded # 成功してしまう [Parent] Completed Succeeded [Child] Exit State [Parent] Exit State
- 当然子が先に成功するに関しても成功になる
- 気になるのは、
ChildのDelay時間を延ばすと、その分ログが出るのも待機するようになる - 先程の例では、同じように
ChildのDelayの時間を延ばしても待機しない - UE Editor を再起動しても挙動は変わらない
同時に起こる場合
一応同じフレームで発生する場合も調べておく。これは最初に行った「即親が失敗」とな異なり、Delay 有りなので、子も選択(active) になる。
Output Log
親が失敗・子が成功
[Child_1] Enter State [Child_2] Enter State [Child_1] First Tick [Child_2] First Tick [Child_1] Finish Task Failed # 親が先に失敗 [Child_2] Finish Task Succeeded [Child_2] Completed Failed [Child_1] Completed Failed [Child_2] Exit State [Child_1] Exit State [Child_1] Enter State [Child_2] Enter State [Child_2] Finish Task Succeeded # 子が先に成功 [Child_1] Finish Task Failed [Child_2] Completed Failed [Child_1] Completed Failed [Child_2] Exit State [Child_1] Exit State # 以降繰り返し
親が成功・子が失敗
[Child_1] Enter State [Child_2] Enter State [Child_1] First Tick [Child_2] First Tick [Child_1] Finish Task Succeeded # 親が先に成功 [Child_2] Finish Task Failed [Child_2] Completed Failed [Child_1] Completed Failed [Child_2] Exit State [Child_1] Exit State [Child_1] Enter State [Child_2] Enter State [Child_2] Finish Task Failed # 子が先に失敗 [Child_1] Finish Task Succeeded [Child_2] Completed Failed [Child_1] Completed Failed [Child_2] Exit State [Child_1] Exit State # 以降繰り返し
- どうやら同フレームで Finish Task した場合には、失敗が優先される ように見える
- 🚧ここに関してはこの挙動が正しいか分からない上に、あまり起こり得ないような状況なので一旦保留する
Transition の確認
Task の結果による Transition の確認

| Child_1 | Child_2 |
|---|---|
![]() |
![]() |
Transitions は Completed が最後になるようにしてある。
これは Completed が先にあると、成功・失敗にかかわらず Completed に遷移してしまうため。
| 条件 | 結果 |
|---|---|
| 親 (Child_1) が先に成功 | Child_1 Succeeded |
| 親 (Child_1) が先に失敗 | Child_1 Failed |
| 子 (Child_1-2) が先に成功 | Child_1-2 Succeeded |
| 子 (Child_1-2) が先に失敗 | Child_1-2 Failed |
Output Log
# 親が先に成功 [Child_1] Enter State [Child_1-2] Enter State [Child_1] First Tick [Child_1-2] First Tick [Child_1] Finish Task Succeeded [Child_1-2] Completed Succeeded [Child_1] Completed Succeeded [Child_1-2] Exit State [Child_1] Exit State [Child_1 Succeeded] Enter State
# 親が先に失敗 [Child_1] Enter State [Child_1-2] Enter State [Child_1] First Tick [Child_1-2] First Tick [Child_1] Finish Task Failed [Child_1-2] Completed Failed [Child_1] Completed Failed [Child_1-2] Exit State [Child_1] Exit State [Child_1 Failed] Enter State
# 子が先に成功 [Child_1] Enter State [Child_1-2] Enter State [Child_1] First Tick [Child_1-2] First Tick [Child_1-2] Finish Task Succeeded [Child_1-2] Completed Succeeded [Child_1] Completed Succeeded [Child_1-2] Exit State [Child_1] Exit State [Child_1-2 Succeeded] Enter State
# 子が先に失敗 [Child_1] Enter State [Child_1-2] Enter State [Child_1] First Tick [Child_1-2] First Tick [Child_1-2] Finish Task Failed [Child_1-2] Completed Failed [Child_1] Completed Failed [Child_1-2] Exit State [Child_1] Exit State [Child_1-2 Failed] Enter State
Debugger
最後の「子が先に失敗」の Debugger を一部掲載しておきます。

- 結果として、ほぼ期待通りの遷移となった
- Debugger を見ても、失敗時には
Root,Child_1-2 Failedが新しく active states となっているのが分かる
Transition 先の深さによる State 選択の確認

Child_2 からの遷移はシンプルに Succeeded 時です。
| 遷移先 | 結果 |
|---|---|
| Level1 | Level -> Level2 -> Level2-2 |
| Level2 | Level -> Level2 -> Level2-2 |
| Level2-2 | Level -> Level2 -> Level2-2 |
| Level3 | Level -> Level3 |
| Child_1-3 | Child_1 -> Child_1-3 |
Output Log
# 遷移先 Level1 # 遷移先 Level2 # 遷移先 Level2-2 [Child_1] Enter State [Child_1-2] Enter State [Child_1] First Tick [Child_1-2] First Tick [Child_1-2] Finish Task Succeeded [Child_1-2] Completed Succeeded [Child_1] Completed Succeeded [Child_1-2] Exit State [Child_1] Exit State [Level1] Enter State [Level2] Enter State [Level2-2] Enter State [Level1] First Tick [Level2] First Tick [Level2-2] First Tick [Level2-2] Exit State [Level2] Exit State [Level1] Exit State
# 遷移先 Level3 [Child_1] Enter State [Child_1-2] Enter State [Child_1] First Tick [Child_1-2] First Tick [Child_1-2] Finish Task Succeeded [Child_1-2] Completed Succeeded [Child_1] Completed Succeeded [Child_1-2] Exit State [Child_1] Exit State [Level1] Enter State [Level3] Enter State [Level1] First Tick [Level3] First Tick [Level3] Exit State [Level1] Exit State
# 遷移先 Child_1-3 [Child_1] Enter State [Child_1-2] Enter State [Child_1] First Tick [Child_1-2] First Tick [Child_1-2] Finish Task Succeeded [Child_1-2] Completed Succeeded [Child_1] Completed Succeeded [Child_1-2] Exit State # Child_1 に Enter していない? [Child_1-3] Enter State [Child_1-3] First Tick [Child_1-3] Exit State [Child_1] Exit State
- Root の別の子ツリー (Level1 以下) への遷移は期待通りに動作している
- 中間ノードを選択したとしても、
Child_1-2から遷移先までを一度 Root まで戻りLevel1を通り、リーフまで選択している
- 中間ノードを選択したとしても、
- 遷移元である
Child_1のツリー内のChild_1-3への遷移は興味深い- 期待通りではあるのだが、Root まで戻り
Child_1に再度 Enter するかと思っていたが、Enter していない - 以下のように Debugger としては active states として
Child_1も含めて選択されているものの、Enter Satesには入っていないことがわかる
- 期待通りではあるのだが、Root まで戻り

まとめ
- 今回は
Stateノードがどのように選択され、イベントが実行されるかを確認した - また、Transition についても、基本的な部分を確認した
- 特に複雑な条件も付与していないため、おおまか期待通りの動作となった
- ただ、親と子が時間差で終了するとき、子の Finish Task を待つケースとそうでないケースが偶然ながら見られた。
- このケースは再現性に乏しいが、例えば
Move ToTask やAI Move Toを使った Task を使うと簡単に再現できる - 今回利用した Print と Delay だけするタスクの場合は、再現できたりできなかったりするのがよくわからない
- いずれにしろ、不用意に中間ノードで Finish Task はしない方がベターというのが現状での認識になりそうである
- このケースは再現性に乏しいが、例えば
- もう少し実践的なサンプルで試してみないと、Print だけの確認では限界がありそう






















