前提
この記事では、UnityでシンプルにBehaviour Treeが実装できるPanda BTというアセットについて書きます。
Panda BT Free
Panda BT Pro
Panda BTのドキュメント
Behaviour Treeとは
AIのふるまいをツリー構造に細かく分けていくことで実装するAI技術です。
例えば目玉焼きを作る場合、以下のように処理を細かく分けていってそのふるまいを記載することができます。
目玉焼きを作る
フライパンを温める
フライパンを持つ
フライパンをコンロにかける
コンロに火をつける
卵を割る
卵をフライパンに入れる
五分間待つ
テキストの各行は処理のノードを表します。Tab文字による字下げによりノード間の親子関係を表します(字下げされると子ノードになる)。
Panda BTでは、上のような処理の手順を構造化ノード、ビルトインノード、カスタムノードを組み合わせて書くことでAIのふるまいとして記述していきます(各ノードの説明については後から詳述します)。
Panda BTではBehaviour Treeがどのように実現されるのか
実際にPanda BT Freeに含まれるサンプルシーンを見ながら、Panda BTの使い方を解説していきます。無料でアセットストアからダウンロードできますので、自分でも動かしてみてください。
では、Panda BT Freeに含まれるPlayTagというサンプルシーンを見てみます。
これは、プレイヤーとコンピューター(AI)が鬼ごっこをするサンプルシーンです(Tagというのは英語で鬼ごっこという意味)。最初はプレイヤーが鬼です。プレイヤーがコンピューターに触ると、鬼を交代してコンピューターが鬼になります。下の画像を見れば分かるように、プレイヤーは丸〇、コンピューターは四角□です。鬼が赤、追われる方は青です。プレイヤーはマウスで丸〇を動かし、コンピューターはPanda BTで四角□を動かしています。
コンポーネントの構成
それでは、コンピューターのゲームオブジェクトにアタッチされているゲームオブジェクトを見てみましょう(下図参照)。
Mesh Filter、Mesh Renderer、Rigidbody、BoxColliderはごく普通のコンポーネントで、どんなキャラクターオブジェクトにもアタッチされている基本的なコンポーネントです。キャラクターの表示と接触判定を行うためにアタッチされています。
Panda BTでBehaviour Treeを実現するコンポーネントが残りの2つです。Panda Behaviourというコンポーネントと、Computerという自作スクリプトです。
2つのコンポーネントのそれぞれを見てみます。
Panda Behaviourコンポーネント
まずPanda Behaviourコンポーネントですが、こちらでBehaviour Treeのロジックを記述します。記述はBTスクリプトという独自のフォーマットのテキストファイルで記述して、そのBTスクリプトをPanda Behaviourコンポーネントにアサインします。Panda Bahaviourコンポーネントには複数のBTスクリプトをアサインできます。今回は2つのBTスクリプトがアサインされています(Computer.BT.TxtとPlayTag.commented.BT.txtの2つ)。
ちなみにUnityエディタのプレイモード中は、BTスクリプトの各ノードは以下の画像のように色付けされます。ノードの各色は、そのノードがどのような状態にあるかを表します。Runningが青色、Succeededが緑色、Failedが赤色、ノードが実行されていない場合灰色となります。ノードの状態(Running、Succeeded、Failed)については後述します。
このようにPanda BTでは、インスペクタ上の字下げ表記だけでBehaviour Treeを表現します。実行時には、各ノードの状態は色で分かりますので動作状況も容易に把握できます。また、Pro版の機能からはインスペクタ上からのBTスクリプト編集、ブレークポイントの挿入などもできます。こういったアセットのコンパクトさのおかげで、とてもシンプルに開発・運用できるところがPanda BTの最大の魅力です。
tree("Root")の解説
**Panda BTではまず初めにtree("Root")という構造化ノードから処理が始まります。**なので、今回はComputer.BTの以下のtree
が最初に実行されます。
tree("Root")
//Play Tag, check for collision and Talk at the same time.
parallel
repeat mute tree("PlayTag")
repeat mute tree("CheckCollision")
repeat mute tree("Talk")
tree
という構造化ノードは、ツリーの一番上の親に必ず一つ書く決まりになっています。最初に実行されるtree
には"Root"
という名前を付けます。処理はtree
ノードから順番に子ノードへと移動します。子ノードはタブ文字による字下げで表現します。
// の行はコメント行なので無視されて、その次の行に移ります。
次の行はparallel
ノードです。Parallel
ノードはPanda BTに付属の構造化ノードで、全ての子ノードを並列に実行するという機能があります。今回の場合はtree("PlayTag")
、tree("CheckCollision")
、tree("Talk")
という3つのツリーを並列に実行しています。
parallel : 子ノード全てを並列に実行する
最後にrepeat mute
ですが、repeat
もmute
も構造化ノードでそれぞれ以下の機能があります。
repeat:子ノードが失敗(Failed)するまで、子ノードの処理をリピートする
mute:子ノードの失敗(Failed)・成功(Succeeded)に関わらず、その結果を成功(Succeeded)に変更する。子ノードが実行中(Running)の場合は実行中(Running)を返す。
という意味があります。ここでFailed(失敗)、Scceeded(成功)、Running(実行中)という概念が出てきました。これは各ノードの状態を表すもので、BTスクリプト上で実行されたノードは必ずこの3つのどれかの状態を返します。
ではrepeat mute tree("PlayTag")
を考えてみましょう。この行のrepeat
、mute
は(子ノードが必ず1つであるので)略式記載されていて、実際には以下のようなツリー構造となっています。
repeat
mute
tree("PlayTag")
まず、tree("PlayTag")
からその実行状態が返ってきます(Failed、Succeeded、Runningのいずれか)。ですがmute
により、その結果がFailedの場合でもSucceededに変更されます。mute
の影響でrepeat
以下の実行状態は常にSucceeded(またはRunning)なので、repeat
は永遠にmute
以下のツリー構造をrepeat
し続けます。要するに、repeat mute tree
と書けばtree
以下の処理を無限に繰り返し実行するということです。
それでは、tree("Root")
全体をもう一回見てみましょう。tree("Root")
はtree("PlayTag")
、tree("CheckCollision")
、tree("Talk")
を並列に無限回繰り返す処理であることがわかります。コンピューターが、鬼ごっこをプレイする(Play)、衝突判定を行う(CheckCollision)、話す(Talk)という3つのタスクを並列処理していることが分かりますね。
tree("CheckCollision")の解説
では、3つのツリーtree("PlayTag")
、tree("CheckCollision")
、tree("Talk")
を並列実行するということだったので、その中の一つで衝突判定を行っているtree("CheckCollision")
を見てみましょう。
tree("CheckCollision")
//Tag when we collide with the player.
//Leave 1 sec of cooldown between each "Tag".
sequence
IsColliding_Player
Tag
Wait(1.0)
tree("CheckCollision")
では、まずsequence
という構造化ノードが処理されます。sequence
は以下の機能があります。
sequence : 子ノードの処理が失敗するまで、子ノードを順次実行する(子ノードが成功したら、次の子ノードを実行する)。子ノードが実行中(Running)の場合は、sequenceもRunningの状態を返す。子ノードが失敗(Failed)した時点で、sequenceもFailedを返して処理を終了する。全ての子ノードが成功(Succeeded)したら、sequenceもSucceededを返して処理を終了する。
ですので処理の手順を日本語で説明すると、以下のようになります。
まずIsColliding_Playerノードで、コンピューターがPlayerと接触したかを判定します。
接触していない場合、IsColliding_PlayerノードはFailedを返します。子ノードがFailedを返したのでsequenceはそこで処理を終了して自らもFailedを返します。ですが、tree("CheckCollision")はrepeat muteされているので繰り返し処理されます。結果、次のフレームで再度IsColliding_Playerノードが実行されます(毎フレーム衝突判定を行うことになります)。
接触している場合、IsCollinding_PlayerノードはScucceededを返します。成功したので次のノードに移ります。Tagノードが実行されます。ここでは鬼のフラグ(IsIt)を反転させます。また青・赤の色も変更します。このノードは必ず成功します(スクリプトでそう記述しています)。Tagノードが成功したのでWait(1.0)ノードに移ります。WaitノードはPanda BTのビルトインノードでして、指定した秒数だけ処理を待ちます(待っている間はRunning、待ちが終了した状態でSucceededを返す)。Waitノードをここで実行することで、鬼の交代をした後の1秒間は衝突判定を行わないようになっています。Waitによる待ちを完了しsequenceを抜けたあとは、tree("CheckCollision")がrepeat muteされているため、再度sequenceの先頭から処理が開始されます。
このように、sequence
を用いれば子ノードの成功・失敗により、次のノードを実行するかどうかを選択するという、if文のような条件分岐が実現できます。
tree("PlayeTag")の解説
では次にtree("PlayTag")
を見てみましょう。
tree("PlayTag")
//Do whatever is appropriate:
//Chase the player, Avoid the player or just Idle.
fallback
tree("ChasePlayer")
tree("AvoidPlayer")
tree("Idle")
tree("PlayTag")
ではfallback
という構造化ノードを使っています。fallback
ノードは以下のような機能があります。
fallback : 子ノードの処理が成功を返すまで、子ノードを順次実行する。子ノードの実行中(Running)の場合は、fallbackもRunningを返す。子ノードが成功(Succeeded)したら、fallbackもSucceededを返してそこで処理を終了する。子ノードが失敗したら次の子ノードを実行する。すべての子ノードが失敗(Failed)したら、fallbackもFailedを返して処理を終了する。
fallback
の子ノードは、tree("ChasePlayer")
、tree("AvoidPlayer")
、tree("Idle")
の3つのtreeです。
sequence
は複数の成功を積み重ねて順次処理を行うようなものでしたが、fallback
の場合は子ノードは1つしか成功しません。今回の場合は、Playerを追いかける処理(ChasePlayer)が成功した場合は、Playerをよける処理(AvoidPlayer)とアイドル状態(Idle)は実行されない。ChasePlayerが失敗してAvoidPlayerが成功した場合は、Idleは実行されない。ChasePlayerとAvoidPlayerが失敗した場合は、Idleが実行される。のようになります。このようにfallback
を使うと、複数の状態を持つキャラクターコントローラのようなロジックが簡単に記述できます。
tree("Talk")の解説
次にtree("Talk")
を見てみます。
tree("Talk")
//Say something when changing.
fallback
while IsIt
sequence
Say("...I'm it.")
Running
while not IsIt
sequence
Say("Tag, you're it!")
Running
fallback
は先程説明しました。子ノードのwhile IsIt
、while not IsIt
のどちらかが実行されます。
while
ノードという新しい構造化ノードが出てきました。while
ノードは必ず2つの子ノードを持ちます。1つ目のノードが条件(condition)を表し、2つ目のノードがアクション(action)を表します。
while
codition
action
別の書き方として、以下のようにも書けます。
while codition
action
while
ノードには以下のような機能があります。
while : conditionノードがFailedになるまで、conditionノードとactionノードの処理を実行する(conditionノードがSucceededであることを確認後にactionノードは処理実行される)。whileノードは、conditionノードがSucceededかつactionノードがSucceededの場合Succeededを返す。conditionノードとactionノードのいずれかがFailedの場合Failedを返す。conditionノードとactionノードのいずれかがRunningの場合Runningを返す。
要するにC#プログラミングのwhileと同じような機能を果たします。
次にnot
ノードですが、こちら子ノードの結果を反転させます。
not
child
childノードがSucceededの場合はnot
ノードはFailedを返し、childノードがFailedの場合はnot
ノードはSucceededを返すわけです。not
ノードは(必ず子ノードが1つなので)以下のように簡略化できます。
not child
では、改めてtree("Talk")
の内容を見てみます。
鬼かどうかを表すIsIt
ノードがSucceeded
を返す場合、while IsIt
ノード以下のsequence
ノードが実行されます。sequence
ノードでは、Say("...I'm it.")
というカスタムノードで"...I'm it."
というテキストメッセージを表示した後、ビルトインのRunning
ノードが実行されます。Running
ノードは常に実行中(Running)の状態を返します。ですのでsequence
ノードはそこで処理を実行中のままで保留します。この書き方はあるフラグがたったら一回だけ処理を実行したい場合に有効です。
余談ですがRunning
ノードと同様のノードにSucceed
ノード、Fail
ノードがあります。Succeed
ノードは常に成功(Succeeded)を返し、Fail
ノードは常に失敗(Failed)を返します。
while IsIt
sequence //子ノードRunningで実行中の状態でとまる(永遠にSucceededしない)
Say("...I'm it.") //IsItフラグが変化すると1回だけ処理されるノード
Running //常にRunningを返すビルトインノード
fallback
+while
+while not
の書き方も大事です。このように書くと、フラグの状態により2つに分岐するツリーができます。これで、Behaviour Treeをステートマシーンのように扱うこともできます。
// フラグによるステートマシーンを実現する書き方
tree("StateMachine")
fallback
while condition
action1
while not condition
action2
さて、解説していないtreeは残りtree("ChasePlayer")
、tree("AvoidPlayer")
、tree("Idle")
だけとなりました。これらのtreeの説明は省略します。これらのtreeの内容は今まで説明した知識で読める内容になっていますので、実際にどのような動きをするかをご自分で解析し、理解してみてください。
カスタムノードを自作する
さて、今までの説明でPanda Behaviourコンポーネントの説明がほぼ終わったのですが、1つだけまだ説明していないことがあります。それがカスタムノードです。Panda BehaviourコンポーネントのBTスクリプトで登場したIsColliding_Player
、Tag
、IsIt
、Say("...I'm it.")
などのことです。
このカスタムノードの中身はどこにあるでしょう?察しがついている方もいるかと思いますが、これらカスタムノードの内容はゲームオブジェクトにアタッチされているComputer.csという自作スクリプトに書いてあります。
それではスクリプトComputer.csを見てみましょう。
まず、IsIt
カスタムノードですが、スクリプトComputer.csでは以下のように書いてあります。
[Task]
bool IsIt = true; // Whether the agent is "It".
非常に簡単です。bool変数に[Task]
という属性を加えてあげるだけでPanda Behaviour上のカスタムノードとして機能します。bool変数がtrue
の場合Succeededを返し、false
の場合Failedを返すわけです。
次にIsColliding_Player
カスタムノードです。以下のようにboolプロパティも[Task]
属性でカスタムノード化出来ます。
[Task]
bool IsColliding_Player
{
get
{
return _IsColliding_Player;
}
}
次はSay
カスタムノードを見てみましょう。こちらは関数での実装になっています。boolを返り値とする関数に対して[Task]
属性を付与するとカスタムノードとしてPanda Behaviourコンポーネント上から利用できます。関数がtrue
を返すとカスタムノードはSucceededを返し、false
を返すとカスタムノードはFailedを返すわけです。引数には int/float/bool/string などが使えます(複数引数も可能です。GameObject、Transformなどは引数にできないようです。)
[Task]
bool Say(string text)
{
//ここにカスタムノード内でやりたい処理を書く
tagDialogue.SetText(text);
tagDialogue.speaker = this.gameObject;
tagDialogue.ShowText();
//最後にbool値を返す
return true; //常にSucceededを返す場合
}
関数を使えば、Succeeded/Failedをカスタムノード上で決定できるようになります。
[Task]
bool SomeFunk(string text)
{
if(何かの条件)
return true; //Succeeded
else
return false; //Failed
}
関数を使ったカスタムノードはもう1つ作り方があります。Computer.csのMoveToDestination
関数を見てください。
[Task]
void MoveToDestination()
{
var task = Task.current;
var delta = destination - transform.position;
if (transform.position != destination)
{
// 目的地に近づく処理
// ...
// ...
}
//目的地に到着したら実行される
if (transform.position == destination)
task.Succeed();
}
このMoveToDestination
関数の返り値はbool型でなくてvoid型です。void型の関数をカスタムノードとする場合、以下のルールによりそのカスタムノードの状態が変わります。
Task.current.Succeed()が呼び出されたとき、カスタムノードはSucceededを返す。Task.current.Fail()が呼び出されたとき、カスタムノードはFailedを返す。どちらも呼び出されなかったとき、カスタムノードはRunningを返す。
要するに、void型の関数でカスタムノードを作るとRunning状態を表現できます。上のコードの例で言うと、目的地に到達していない状態ではRunning状態にしながら目的地に近づいていき、目的地に到着したらTask.current.Succeed()
を呼び出してSucceededとするなどの処理ができます。
もう1つカスタムノードを作るときに重要なTask.current.isStarting
について触れておきます。Task.current.isStarting
は、カスタムノードに入った直後だけtrue
を返します。カスタムノードに入った時に一度だけ初期化処理を行いたいときなどに便利です。下のコードはTask.current.isStarting
の使用例です。
// Task.current.isStartingの使用例
// numberOfFramesのフレーム数だけRunning状態でWaitするカスタムノードの例
private int counter;
[Task]
public void WaitFrames(int numberOfFrames)
{
var task = Task.current;
if (task.isStarting)
{
// このカスタムノードに入った時に一回だけ実行される
counter = 0;
}
// Running状態でカウンターをプラスしていく
counter++;
if (counter >= numberOfFrames)
{
// counterが10以上になったら
// Succeededを返してこのカスタムノードを抜ける
task.Succeed();
}
}
最後に、[Task]
属性を使う場合はスクリプトの最初にusing Panda;
と書くのを忘れないようにしてください。
using Panda;
ここまでのまとめ
さて、Panda BTのデモシーンを題材に説明をしてきましたがいかがだったでしょうか。Panda Behaviourコンポーネントとカスタムノード用のスクリプト1つで、シンプルかつ可読性がよくBehaviour Treeが実現できていることが分かっていただけたのではないでしょうか。
ここまでの話をまとめてみます。
- ゲームオブジェクトにPanda Behaviourコンポーネントとカスタムノード用のスクリプトを1つアタッチすれば良い
- Panda Behaviourコンポーネント用にBTスクリプトを書き、登録する
- BTスクリプトは構造化ノード、ビルトインのノード、カスタムノードの3つで構成される
- 構造化ノードの機能を理解してBehaviour Treeのロジックを組み立てる
- 実際の処理はビルトインのノードの活用、カスタムノードの自作により実現する。
- カスタムノードは、C#スクリプト上の変数、プロパティ、関数で表現できる。
ここまで話したことの詳細は、公式のドキュメントでより詳細に記載されていますのでご参考になさってください。
構造化ノードのまとめ
BTスクリプトでBehaviour Treeのロジックの要を担うのは構造化ノードです。
構造化ノードを把握しておくことはとても重要ですのでここでまとめておきます。
構造化ノードは全部で10種類あります。
- tree
- sequence
- fallback
- parallel
- race
- random
- repeat
- while
- not
- mute
以下に、それぞれの構造化ノードの機能を文章でまとめました。ご参照ください。
また、公式サイトに構造化ノードの動作をデモしたUnity WebGLがあります。
こちらもあわせて確認してみて下さい。→ Structual Nodes Demo
tree
-
tree
ノードはツリー構造の一番上に必ず必要(ツリー構造をまとめる意味がある) -
tree
ノードはstringの引数を必ず一つとる。その引数がtree
の名前になる(ex.tree("Patrol")
など) -
tree("Root")
は必ず必要。tree("Root")
から処理が開始される。 -
tree
ノードは子ノードは必ず1つ。複数の子ノードを持つとエラーになる。
tree("Name")
child
返り値 | 条件 |
---|---|
Running | 子ノードがRunningの時 |
Succeeded | 子ノードがSucceededを返したとき |
Failed | 子ノードがFailedを返したとき |
sequence
-
sequence
ノードは子ノードを何個でも持てる。 -
sequence
ノードは子ノードを上から順に順番に実行していく。 - 順番に実行していく途中で、子ノードがFailedを返した時点で
sequence
ノードもFailedを返し処理は終了する。 - 順番に実行していき、全ての子ノードがSucceededを返したら、
sequence
ノードもSucceededを返し処理は終了する。
sequence
child_0
child_1
...
child_k
返り値 | 条件 |
---|---|
Running | 子ノードがRunningの時 |
Succeeded | 全ての子ノードがSucceededを返したとき |
Failed | いずれかの子ノードがFailedを返したとき |
fallback
-
fallback
ノードは子ノードを何個でも持てる。 -
fallback
ノードは子ノードを上から順に順番に実行していく。 - 順番に実行していく途中で、子ノードがSucceededを返した時点で
fallback
ノードもSucceededを返し処理は終了する。 - 順番に実行していき、全ての子ノードがFailedを返したら、
fallback
ノードもFailedを返し処理は終了する。
fallback
child_0
child_1
...
child_k
返り値 | 条件 |
---|---|
Running | 子ノードがRunningの時 |
Succeeded | いずれかの子ノードがSucceededを返したとき |
Failed | 全ての子ノードがFailedを返したとき |
parallel
-
parallel
ノードは子ノードを何個でも持てる。 -
parallel
ノードは全ての子ノード並列に実行する。 - 全ての子ノードがSucceededを返した時点で
parallel
ノードもSucceededを返し処理は終了する。 - いずれかの子ノードがFailedを返したら、
parallel
ノードもFailedを返し処理は終了する。
parallel
child_0
child_1
...
child_k
返り値 | 条件 |
---|---|
Running | 少なくとも1つの子ノードがRunningの時 かつ Failedを返した子ノードが存在しないとき |
Succeeded | 全ての子ノードがSucceededを返したとき |
Failed | いずれかの子ノードがFailedを返したとき |
race
-
race
ノードは子ノードを何個でも持てる。 -
race
ノードは全ての子ノード並列に実行する。 - 全ての子ノードがFailedを返した時点で
race
ノードもFailedを返し処理は終了する。 - いずれかの子ノードがSucceededを返したら、
race
ノードもSucceededを返し処理は終了する。
race
child_0
child_1
...
child_k
返り値 | 条件 |
---|---|
Running | 少なくとも1つの子ノードがRunningの時 かつ Succeededを返した子ノードが存在しないとき |
Succeeded | いずれかの子ノードがSucceededを返したとき |
Failed | 全てのの子ノードがFailedを返したとき |
random
-
random
ノードは子ノードを何個でも持てる。 -
random
ノードは全ての子ノードの中から1つの子ノードをランダムに選び、実行する。 -
random
ノードの状態は、ランダムに選択された子ノードの状態と同じなる。 -
random
ノードの引数でランダム選択の確率的な重みを指定できる。例えば子ノードが4つで、それぞれの確率を10%、20%、30%、40%としたい場合、random(10.0, 20.0, 30.0, 40.0)
とする(合計100にする必要はない)。
random(w_0, w_1, ... ,w_k) //ウェイトは省略可能
child_0
child_1
...
child_k
返り値 | 条件 |
---|---|
Running | ランダム選択された子ノードがRunningの時 |
Succeeded | ランダム選択された子ノードがSucceededを返したとき |
Failed | ランダム選択された子ノードがFailedを返したとき |
repeat
-
repeat
ノードは整数の引数を1つ持ち、子ノードを引数の数だけリピート実行する。 - 引数を省略すると子ノードを無限回リピート実行する。
-
repeat
ノードは、子ノードを必ず1つだけ持つ -
repeat
ノードは、子ノードを引数回Succeededさせた場合にSucceededを返す(子ノードが引数以下の回数のSucceededであるならば、repeat
ノードはRunningを返す)(引数を省略した場合、repeat
ノードはSucceededを返すことはない。ずっとRunnging返す。Failedを返す場合はある。) -
repeat
ノードは、子ノードがFailedを返した場合にFailedを返す。
repeat(n) //引数は省略可能
child_0
返り値 | 条件 |
---|---|
Running | 子ノードのSucceeded回数が引数よりも小さいとき |
Succeeded | 子ノードのSucceeded回数が引数回数になった時(引数を省略した場合Succeededにはならない。) |
Failed | 子ノードがFailedを返したとき |
while
-
while
ノードは必ず2つの子ノードを持つ - 1つ目のノードは条件(
condition
)を表す。2つ目のノードはアクション(action
)を表す。 -
condition
ノードがFailedを返すまで、condition
ノードとaction
ノードが繰り返し実行される。 -
action
ノードは、condition
ノードの成功判定後に実行される。 -
action
ノードがSucceededを返した場合、while
ノードもSucceededを返す。 -
condition
ノードまたはaction
ノードがFailedを返した場合、while
ノードもFailedを返す。
while
condition
action
// もう一つの書き方
while condition
action
返り値 | 条件 |
---|---|
Running | conditionノードがRunning状態のとき(conditionがRunningでactionが未実行の場合とconditionがSucceededでactionがRunningの場合の2パターンがある) |
Succeeded | actionノードがSucceededを返したとき(conditionがSucceededでactionがSucceededの場合) |
Failed | conditionノードまたはactionノードがFailedを返したとき(conditionがFailedでactionが未実行の場合とconditionがSucceededでactionがFailedの場合の2パターンがある) |
以下はconditionノード, actionノードの状態によってwhileノードの状態がどう変化するかを表した図です。conditionがrunning/failedの場合、whileの状態はconditionに依存する、conditionがsucceededの場合はactionに依存するようになります。
condition : Succeeded | condition : Running | condition : Failed | |
---|---|---|---|
action : Succeeded | Succeeded | Running | Failed |
action : Running | Running | Running | Failed |
action : Failed | Failed | Running | Failed |
not
-
not
ノードは必ず1つの子ノードを持つ -
not
ノードは子ノードの状態を反転させる - 子ノードがSucceededを返したとき、
not
ノードはFailedを返す - 子ノードがFailedを返したとき、
not
ノードはSucceededを返す - 子ノードがRunningを返したとき、
not
ノードもRunningを返す
not
child
// もう一つの書き方
not child
返り値 | 条件 |
---|---|
Running | 子ノードがRunning状態のとき |
Succeeded | 子ノードがFailedを返したとき |
Failed | 子ノードがSucceededを返したとき |
mute
-
mute
ノードは必ず1つの子ノードを持つ -
mute
ノードは子ノードがFailedの場合でもSucceededを返す(Failedには絶対にならなくなる) - 子ノードがSucceededを返したとき、
mute
ノードはSucceededを返す - 子ノードがFailedを返したとき、
mute
ノードはSucceededを返す - 子ノードがRunningを返したとき、
mute
ノードもRunningを返す
mute
child
// もう一つの書き方
mute child
返り値 | 条件 |
---|---|
Running | 子ノードがRunning状態のとき |
Succeeded | 子ノードがSucceededまたはFailedを返したとき |
Failed | 絶対にFailedにはならない |
ビルトインのノードを少し紹介
Panda BTに最初から用意されている便利なノードについても少しまとめておきます。
完全なビルトインのノードのリストは以下で確認できます。
Status系
単に状態を返すだけのノードがあります。たまに使います。
Succeed //Succeededを返すだけ
Fail //Failedを返すだけ
Running //Runningを返すだけ
Wait系
一定時間処理をWaitする場合に使います。
Wait(3.0) //3.0秒waitする
Wait(10) //10フレームwaitする
RealtimeWait(3.0) //3.0秒waitする。TimeScaleを無視する(Unscaled)
Debug系
Debug.Logを仕込むこともできます。
DebugLog("StringMessage") //コンソールにログを表示したときに利用する
アセットに含まれるサンプル紹介
最後にアセットに含まれるサンプルシーンをご紹介します。
Hotlineマイアミのようなサンプルです。
敵キャラとプレイヤー両方ともPanda Behaviourコンポーネントを利用して実装されています。
無料で全機能が使えます
Panda BTにはPro版とFree版があります。
Pro版では以下の3つの機能が強化されます。
- BehaviourTree内にBreakPointが設定できる(デバッグ機能の向上です。)
- インスペクタ上のドラッグ&ドロップでBTスクリプトを編集できる(編集機能の向上です。エディタで修正する手間が省けるので割と便利です。)
- 全ソースコードが付属する(Free版はDllとして提供される)(アセットの保守、改造が自分で出来るようになります。)
Pro版では、Free版よりもデバッグ/編集/保守などのゲーム制作ワークフロー上の機能が強化されるだけです。なので、Free版とPro版の間で出来上がったゲームの性能に違いは生まれません。より効率的に作業したくなったらPro版の購入を検討しましょう。
UnityでシンプルにBehaviour Treeをやってみたい!と思う人はぜひPanda BTを使ってみてください!
Panda BT Free
Panda BT Pro
Panda BTのドキュメント
補足
この記事は、Unity アセット真夏のアドベントカレンダー 2020 Summer! 8月14日のために書かれた記事です。
http://assetstore.info/eventandcontest/adventcalendar/summer-advent-calendar-2020/