この記事は書きかけです。2022/12/17~
Behavior Treeアドオン「Beehave」について
Godotアドオンです。Godot3, Godot4で使用できます。
Behavior Tree(以下BT)のGodot実装といえます。
BTノードのみで構成したシーンをつくっておき、使用したいシーンで、対象にしたいノードにBTシーンをひもづけます。
複雑な行動パターンを持ったステートマシンのような使い方をします。
汎用的なアクション・条件をBTノードで作成することで、複雑な行動パターンをいい感じに管理することができます。
一見むずかしそうですが、慣れると複雑なゲームAIをかんたんに扱えるようになります。
内部でやっていることは_processで条件分岐して関数を呼び出しているだけやろという心意気で触ってみることをおすすめします。
Behavior Treeとは
Behaviour trees are a modular way to build AI logic for your game. For simple AI, behaviour trees are definitely overkill, however, for more complex AI interactions, behaviour trees can help you to better manage changes and re-use logic across all NPCs.
Behavior Treeは、ゲームのAIロジックを構築するためのモジュール化された方法です。
単純なAIの場合、Behavior Treeは確かにやりすぎですが、より複雑なAIの場合、Behavior Treeは変更をうまく管理し、すべてのNPCでロジックを再利用するのに役立ちます。
https://github.com/bitbrain/beehave/tree/godot-3.x
はじめに、Behavior Tree についてはこのスライドに目を通すのが良いです。(Unityですが)
https://www.slideshare.net/torisoup/unity-behavior-treeai
BeehaveのBehavior Tree 各Nodeの解説
ドキュメントを日本語訳したものに簡単な解説をつけました。
Leaf
末端のBTノードです。
アクションを実行するBTノードと、条件を判定するBTノードの2つです。
アクション内容や条件判定などの処理は自分でコードを書いて作成します。
Beehave内のクラスをextends
したスクリプトファイルを作成します。
ConditionLeaf コンディション
条件判定をするBTノードです。
このノードはシンプルなほど良く、単一の条件に応じてSUCCESS
かFAILURE
を返します。
複数の条件をチェックするようなノードを作ると、再利用が難しくなるため、避けます。
また、しょっちゅう呼び出される想定のものは、パフォーマンスにも注意する必要があります。
毎フレームget_node()
などはしないようにし、変数にキャッシュするなどがよいかもです。
- コンディションのコード 例IsVisibleCondition.gd
class_name IsVisibleCondition
extends ConditionLeaf
func tick(actor, blackboard):
if actor.visible:
return SUCCESS
return FAILURE
ActionLeaf アクション
アクションを実行します。
この場合、RUNNING
というコードを返します。
- コンディションのコード 例MakeVisibleAction.gd
class_name MakeVisibleAction
extends ActionLeaf
func tick(actor, blackboard):
if actor.visible:
return FAILURE
actor.visible = true
return SUCCESS
Blackboard
Blackboardは、複数のBTノード間でデータの保存とアクセスを行うために使用できるオブジェクトです。
BTノードからは、tick(actor, blackboard)
関数の引数 blackboard
からアクセスします。
他のデータアクセス方法として、actor
のプロパティや関数を通じてアクセスする方法もあります……が、書く場所が散らかってしまうのでBTノードのみで完結するデータに限定しておくのが無難そうな気がします。
Composite コンポジット
Compositeは子BTノードを特定の方法で実行するBTノードです。
条件とアクションを使ったノードツリーを作成するためには、Compositeノードを組み合わせて、条件・アクションを実行する。
Selector セレクター
Selectorはその子のそれぞれを実行しようとし、子のうちの1つがSUCCESS
ステータスコードを報告した場合にSUCCESS
ステータスコードを報告します。
すべての子がFAILURE
ステータスコードを報告した場合、このノードはFAILURE
ステータスコードも返します。
このノードは、たとえそのうちの1つが現在すでにRUNNING
中であっても、1つのtick()
実行ごとにすべての子BTノードを処理しようとします。
Selector Star セレクタースター
Selector StarノードはSelectorと似ていますが、子BTノードの1つが現在RUNNING
状態の場合、前に実行されたすべての子BTノードをスキップします。
これは、実行時間に関係なく、一度に一つのアクションしか実行されないようにしたい場合に使用します。
Sequence シーケンス
Sequenceは、その子BTノードを上から順にすべてを実行します。
子BTノードのすべてがSUCCESS
を返した場合に、SequenceはSUCCESS
を返します。
子BTノードがFAILURE
を返した場合に、SequenceはFAILURE
を返します。その後の子BTノードは実行されません。
実行する子BTノードがRUNNING
中の状態でも関係なく、1つのtick()
実行ごとにそのすべての子を実行しようとします。(Sequence Starとの差)
Sequence Star シーケンススター
Sequence StarノードはSequenceと似ていますが、子BTノードの1つが現在RUNNING
状態の場合、その前に成功した子BTノードをすべてスキップします。
これは、実行時間に関係なく、一度に1つのアクションしか実行されないようにしたい場合に使用します。
Decorator
Decoratorは、上記の他のノードと組み合わせて使用することができるノードです。
Failer フェイラー
Failerは常にFAILURE
ステータスコードを返します。
Succeeder サクシーダー
Succeederは必ずSUCCESS
のステータスコードを返します。
Inverter インバーター
Inverterは、子機がSUCCESS
のステータスコードを返した場合はFAILURE
を、子機がFAILURE
のステータスコードを返した場合はSUCCESS
を返します。
Limiter リミッター
Limiterは、子機をx回実行します。最大刻み回数に達すると、FAILURE
ステータスコードを返します。