この記事について
表題のとおりです。
UnityでBehavior Treeを扱うことができるアセット「Behavior Designer」ですが、「Updateのみ」を行うことに非常に苦戦しました。
- Unity Asset Store
Behavior Designer - Behavior Trees for Everyone
Compositeノードの「Abort Type」を設定したりいろいろ試しましたが、Behavior Tree自体が「状態が変わったら再評価を行う」ための仕組みですので、「Selector」ノードや「Sequence」ノードを設定するとただUpdateを行いたいだけなのに再評価が走ってしまいます。
それでもなんとかツリー内で処理を完結させたい。そんな場合の対処法備忘録です。
本題
私がやりたかったのは以下のケースです。
- 「Behavior Designer」別売りの「Movement Pack」にある「Can See Object」が便利なので毎フレーム更新して対象の取得を行いたい。
- でも、別にツリー内の判定に使いたいわけではない。
- ツリーに配置すると「見えている(Success)」「見えていない(Failure)」の状態が変わるたびに他のノードにも再評価の被害が及ぶため、それを阻止したい。裏でUpdateが回っているような感じにしたい。
ということになります。
解決方法
解説
Entry直下の「Parallel」ノードは「並列実行」とよく解説されています。
確かにその通りなのですが、並列実行できるということは「複数の状態を持てる」「ある状態を持っていても別の更新を行うことができる」ということになります。
これを根っこに設定すると、ざっくりと同時更新を行うブロックを複数設けることができます。
実行後の挙動を順を追ってみていくと以下のとおりです。
Treeの開始と同時にまず左側のブロックが評価されます。Repeaterを「Repeat Forever」に設定しているので、これ以降ずっとRepeaterは「Running」を返します。1フレームに無限ループしてしまわないよう、「Instant」のチェックを外しておきます。
そして、Repeaterが稼働し、「Can See Object」や「Can Hear Object」のUpdateが走ります。
根っこがParallelなので、左のブロックのRepeaterがRunningになったら、そのまま右のブロックの評価に移ります。右のブロックは普通のツリーと同じように振る舞います。
そして、例えば「Idle」のRunningに結果が決まったら次のフレームに移ります。
次のフレームでは、また左側のブロックのRepeaterが稼働し、「Can See Object」や「Can Hear Object」のUpdateが走ります。
通常、ツリーでは左側のノードの結果が変わった場合右側のノードの再評価が走りますが、Parallelなので左ブロックの結果は右ブロックに影響しません。
そしてそのまま右側のツリーは前フレームの続きから稼働を継続する、という挙動になり、要件が満たせました。
おわりに
改めてになりますがこの設計が有用になるケースは
・別スクリプトで左側ブロック相当の処理を行ってもいいが、ツリーで内でUpdateすることで解決したい
という場合に限ります。
他に賢い方法があるかもしれませんが、以上が私なりの解決策になります。
お読みいただきありがとうございました。