UnityのPanda BTでシンプルにBehaviour Treeを実装する


# 前提

この記事では、UnityでシンプルにBehaviour Treeが実装できる**Panda BT**というアセットについて書きます。

![banner2006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58282/f50f1fe2-3516-81f1-b489-d305a17a5405.png)

[Panda BT Free](https://assetstore.unity.com/packages/tools/ai/panda-bt-free-33057?utm_source=twitter&utm_medium=social&utm_campaign=jp-advent-calendar-summer)
[Panda BT Pro](https://assetstore.unity.com/packages/tools/ai/panda-bt-pro-58170?utm_source=twitter&utm_medium=social&utm_campaign=jp-advent-calendar-summer)
[Panda BTのドキュメント](http://www.pandabehaviour.com/?page_id=23)

# Behaviour Treeとは

AIのふるまいをツリー構造に細かく分けていくことで実装するAI技術です。
例えば目玉焼きを作る場合、以下のように処理を細かく分けていってそのふるまいを記載することができます。

```
目玉焼きを作る
	フライパンを温める
		フライパンを持つ
		フライパンをコンロにかける
		コンロに火をつける
	卵を割る
	卵をフライパンに入れる
	五分間待つ
```

テキストの各行は処理の**ノード**を表します。Tab文字による字下げによりノード間の親子関係を表します（字下げされると子ノードになる）。

Panda BTでは、上のような処理の手順を**構造化ノード**、**ビルトインノード**、**カスタムノード**を組み合わせて書くことでAIのふるまいとして記述していきます（各ノードの説明については後から詳述します）。

# Panda BTではBehaviour Treeがどのように実現されるのか

実際にPanda BT Freeに含まれるサンプルシーンを見ながら、Panda BTの使い方を解説していきます。無料でアセットストアからダウンロードできますので、自分でも動かしてみてください。

[Panda BT Free](https://assetstore.unity.com/packages/tools/ai/panda-bt-free-33057?utm_source=twitter&utm_medium=social&utm_campaign=jp-advent-calendar-summer)

では、Panda BT Freeに含まれるPlayTagというサンプルシーンを見てみます。

これは、プレイヤーとコンピューター（AI）が鬼ごっこをするサンプルシーンです（Tagというのは英語で鬼ごっこという意味）。最初はプレイヤーが鬼です。プレイヤーがコンピューターに触ると、鬼を交代してコンピューターが鬼になります。下の画像を見れば分かるように、プレイヤーは丸〇、コンピューターは四角□です。<font color="Red">鬼が赤</font>、<font color="Blue">追われる方は青</font>です。プレイヤーはマウスで丸〇を動かし、コンピューターはPanda BTで四角□を動かしています。

![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58282/1b3f8e57-1dc5-0579-bd67-9af818fb4876.gif)

### コンポーネントの構成
それでは、コンピューターのゲームオブジェクトにアタッチされているゲームオブジェクトを見てみましょう（下図参照）。

Mesh Filter、Mesh Renderer、Rigidbody、BoxColliderはごく普通のコンポーネントで、どんなキャラクターオブジェクトにもアタッチされている基本的なコンポーネントです。キャラクターの表示と接触判定を行うためにアタッチされています。

Panda BTでBehaviour Treeを実現するコンポーネントが残りの２つです。Panda Behaviourというコンポーネントと、Computerという自作スクリプトです。
![Clipboard01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58282/7e427604-5ada-9875-9f14-8002724e5615.png)
２つのコンポーネントのそれぞれを見てみます。

### Panda Behaviourコンポーネント

まずPanda Behaviourコンポーネントですが、こちらでBehaviour Treeのロジックを記述します。記述は**BTスクリプト**という独自のフォーマットのテキストファイルで記述して、そのBTスクリプトをPanda Behaviourコンポーネントにアサインします。Panda Bahaviourコンポーネントには複数のBTスクリプトをアサインできます。今回は２つのBTスクリプトがアサインされています（Computer.BT.TxtとPlayTag.commented.BT.txtの２つ）。
![Clipboard02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58282/ab4aeebf-f4da-3081-f596-681fd7a37b26.png)

ちなみにUnityエディタのプレイモード中は、BTスクリプトの各ノードは以下の画像のように色付けされます。ノードの各色は、そのノードがどのような状態にあるかを表します。<font color="Blue">Runningが青色</font>、<font color="Green">Succeededが緑色</font>、<font color="Red">Failedが赤色</font>、ノードが実行されていない場合灰色となります。ノードの状態（Running、Succeeded、Failed）については後述します。
![Clipboard01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58282/bea18110-1d9d-e68a-5ff0-0ccf17845238.png)



このようにPanda BTでは、インスペクタ上の字下げ表記だけでBehaviour Treeを表現します。実行時には、各ノードの状態は色で分かりますので動作状況も容易に把握できます。また、Pro版の機能からはインスペクタ上からのBTスクリプト編集、ブレークポイントの挿入などもできます。こういったアセットのコンパクトさのおかげで、とてもシンプルに開発・運用できるところがPanda BTの最大の魅力です。

### tree("Root")の解説

**Panda BTではまず初めにtree("Root")という構造化ノードから処理が始まります。**なので、今回はComputer.BTの以下の`tree`が最初に実行されます。

```C#:Computer.BT.txt
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")`という３つのツリーを並列に実行しています。

> parallel : 子ノード全てを並列に実行する

最後に`repeat mute`ですが、`repeat`も`mute`も構造化ノードでそれぞれ以下の機能があります。

> repeat：子ノードが失敗(Failed)するまで、子ノードの処理をリピートする

> mute：子ノードの失敗（Failed）・成功（Succeeded）に関わらず、その結果を成功（Succeeded）に変更する。子ノードが実行中（Running）の場合は実行中（Running）を返す。

という意味があります。**ここで<font color="Red">Failed（失敗）</font>、<font color="Green">Scceeded（成功）</font>、<font color="Blue">Running（実行中）</font>という概念が出てきました。これは各ノードの状態を表すもので、BTスクリプト上で実行されたノードは必ずこの３つのどれかの状態を返します。**

では`repeat mute tree("PlayTag")`を考えてみましょう。この行の`repeat`、`mute`は（子ノードが必ず１つであるので）略式記載されていて、実際には以下のようなツリー構造となっています。

```C#
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）という３つのタスクを並列処理していることが分かりますね。

### tree("CheckCollision")の解説

では、３つのツリー`tree("PlayTag")`、`tree("CheckCollision")`、`tree("Talk")`を並列実行するということだったので、その中の一つで衝突判定を行っている`tree("CheckCollision")`を見てみましょう。

```C#
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ノードをここで実行することで、鬼の交代をした後の１秒間は衝突判定を行わないようになっています。Waitによる待ちを完了しsequenceを抜けたあとは、tree("CheckCollision")がrepeat muteされているため、再度sequenceの先頭から処理が開始されます。

このように、`sequence`を用いれば子ノードの成功・失敗により、次のノードを実行するかどうかを選択するという、if文のような条件分岐が実現できます。

### tree("PlayeTag")の解説

では次に`tree("PlayTag")`を見てみましょう。

```C#
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")`の３つのtreeです。

`sequence`は複数の成功を積み重ねて順次処理を行うようなものでしたが、`fallback`の場合は子ノードは１つしか成功しません。今回の場合は、Playerを追いかける処理（ChasePlayer）が成功した場合は、Playerをよける処理（AvoidPlayer）とアイドル状態（Idle）は実行されない。ChasePlayerが失敗してAvoidPlayerが成功した場合は、Idleは実行されない。ChasePlayerとAvoidPlayerが失敗した場合は、Idleが実行される。のようになります。このように`fallback`を使うと、複数の状態を持つキャラクターコントローラのようなロジックが簡単に記述できます。

### tree("Talk")の解説

次に`tree("Talk")`を見てみます。

```C#
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`ノードは必ず２つの子ノードを持ちます。１つ目のノードが条件(condition)を表し、２つ目のノードがアクション(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`ノードは（必ず子ノードが１つなので）以下のように簡略化できます。

```
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）を返します。

```C#
while IsIt
	sequence				//子ノードRunningで実行中の状態でとまる（永遠にSucceededしない）
		Say("...I'm it.")	//IsItフラグが変化すると１回だけ処理されるノード
		Running				//常にRunningを返すビルトインノード
```

`fallback`+`while`+`while not`の書き方も大事です。このように書くと、フラグの状態により２つに分岐するツリーができます。これで、Behaviour Treeをステートマシーンのように扱うこともできます。

```C#
// フラグによるステートマシーンを実現する書き方
tree("StateMachine")
	fallback
		while condition
			action1
		while not condition
			action2
```

さて、解説していないtreeは残り`tree("ChasePlayer")`、`tree("AvoidPlayer")`、`tree("Idle")`だけとなりました。これらのtreeの説明は省略します。これらのtreeの内容は今まで説明した知識で読める内容になっていますので、実際にどのような動きをするかをご自分で解析し、理解してみてください。

### カスタムノードを自作する

さて、今までの説明でPanda Behaviourコンポーネントの説明がほぼ終わったのですが、１つだけまだ説明していないことがあります。それがカスタムノードです。Panda BehaviourコンポーネントのBTスクリプトで登場した`IsColliding_Player`、`Tag`、`IsIt`、`Say("...I'm it.")`などのことです。

このカスタムノードの中身はどこにあるでしょう？察しがついている方もいるかと思いますが、これらカスタムノードの内容はゲームオブジェクトにアタッチされているComputer.csという自作スクリプトに書いてあります。

それではスクリプトComputer.csを見てみましょう。

まず、`IsIt`カスタムノードですが、スクリプトComputer.csでは以下のように書いてあります。

```C#:Computer.cs
	[Task]
	bool IsIt = true; // Whether the agent is "It".
```

非常に簡単です。bool変数に`[Task]`という属性を加えてあげるだけでPanda Behaviour上のカスタムノードとして機能します。bool変数が`true`の場合Succeededを返し、`false`の場合Failedを返すわけです。

次に`IsColliding_Player`カスタムノードです。以下のようにboolプロパティも`[Task]`属性でカスタムノード化出来ます。

```C#:Computer.cs
	[Task]
	bool IsColliding_Player
	{
		get
		{
			return _IsColliding_Player;
		}
	}
```

次は`Say`カスタムノードを見てみましょう。こちらは関数での実装になっています。boolを返り値とする関数に対して`[Task]`属性を付与するとカスタムノードとしてPanda Behaviourコンポーネント上から利用できます。関数が`true`を返すとカスタムノードはSucceededを返し、`false`を返すとカスタムノードはFailedを返すわけです。引数には int/float/bool/string などが使えます（複数引数も可能です。GameObject、Transformなどは引数にできないようです。）

```C#:Computer.cs
	[Task]
	bool Say(string text)
	{
		//ここにカスタムノード内でやりたい処理を書く
		tagDialogue.SetText(text);
		tagDialogue.speaker = this.gameObject;
		tagDialogue.ShowText();

		//最後にbool値を返す
		return true; //常にSucceededを返す場合
	}
```

関数を使えば、Succeeded/Failedをカスタムノード上で決定できるようになります。

```C#:
	[Task]
	bool SomeFunk(string text)
	{
		if(何かの条件)
			return true; //Succeeded
		else
			return false; //Failed
	}
```

関数を使ったカスタムノードはもう１つ作り方があります。Computer.csの`MoveToDestination`関数を見てください。

```C#
	[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とするなどの処理ができます。

もう１つカスタムノードを作るときに重要な`Task.current.isStarting`について触れておきます。`Task.current.isStarting`は、カスタムノードに入った直後だけ`true`を返します。カスタムノードに入った時に一度だけ初期化処理を行いたいときなどに便利です。下のコードは`Task.current.isStarting`の使用例です。

```C#
	// 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;`と書くのを忘れないようにしてください。

```C#
using Panda;
```

# ここまでのまとめ

さて、Panda BTのデモシーンを題材に説明をしてきましたがいかがだったでしょうか。Panda Behaviourコンポーネントとカスタムノード用のスクリプト１つで、シンプルかつ可読性がよくBehaviour Treeが実現できていることが分かっていただけたのではないでしょうか。

ここまでの話をまとめてみます。

- ゲームオブジェクトにPanda Behaviourコンポーネントとカスタムノード用のスクリプトを１つアタッチすれば良い
- Panda Behaviourコンポーネント用にBTスクリプトを書き、登録する
- BTスクリプトは構造化ノード、ビルトインのノード、カスタムノードの３つで構成される
- 構造化ノードの機能を理解してBehaviour Treeのロジックを組み立てる
- 実際の処理はビルトインのノードの活用、カスタムノードの自作により実現する。
- カスタムノードは、C#スクリプト上の変数、プロパティ、関数で表現できる。

ここまで話したことの詳細は、公式のドキュメントでより詳細に記載されていますのでご参考になさってください。

[Panda BTのドキュメント](http://www.pandabehaviour.com/?page_id=23)

# 構造化ノードのまとめ

BTスクリプトでBehaviour Treeのロジックの要を担うのは構造化ノードです。
構造化ノードを把握しておくことはとても重要ですのでここでまとめておきます。
構造化ノードは全部で１０種類あります。

- tree
- sequence
- fallback
- parallel
- race
- random
- repeat
- while
- not
- mute

以下に、それぞれの構造化ノードの機能を文章でまとめました。ご参照ください。

また、公式サイトに構造化ノードの動作をデモしたUnity WebGLがあります。
こちらもあわせて確認してみて下さい。→　[Structual Nodes Demo](http://www.pandabehaviour.com/?page_id=236)

### tree

- `tree`ノードはツリー構造の一番上に必ず必要（ツリー構造をまとめる意味がある）
- `tree`ノードはstringの引数を必ず一つとる。その引数が`tree`の名前になる（ex. `tree("Patrol")`など）
- `tree("Root")`は必ず必要。`tree("Root")`から処理が開始される。
- `tree`ノードは子ノードは必ず１つ。複数の子ノードを持つとエラーになる。

```
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    |  少なくとも１つの子ノードがRunningの時 かつ Failedを返した子ノードが存在しないとき |
| Succeeded  |  全ての子ノードがSucceededを返したとき |
| Failed     |  いずれかの子ノードがFailedを返したとき |

### race

- `race`ノードは子ノードを何個でも持てる。
- `race`ノードは全ての子ノード並列に実行する。
- 全ての子ノードがFailedを返した時点で`race`ノードもFailedを返し処理は終了する。
- いずれかの子ノードがSucceededを返したら、`race`ノードもSucceededを返し処理は終了する。

```
race
	child_0
	child_1
	...
	child_k
```

| 返り値 | 条件 |
|:-:|:-:|
| Running    |  少なくとも１つの子ノードがRunningの時 かつ Succeededを返した子ノードが存在しないとき |
| Succeeded  |  いずれかの子ノードがSucceededを返したとき |
| Failed     |  全てのの子ノードがFailedを返したとき |

### random

- `random`ノードは子ノードを何個でも持てる。
- `random`ノードは全ての子ノードの中から１つの子ノードをランダムに選び、実行する。
- `random`ノードの状態は、ランダムに選択された子ノードの状態と同じなる。
- `random`ノードの引数でランダム選択の確率的な重みを指定できる。例えば子ノードが４つで、それぞれの確率を10%、20%、30%、40%としたい場合、`random(10.0, 20.0, 30.0, 40.0)`とする（合計100にする必要はない）。

```C#
random(w_0, w_1, ... ,w_k) //ウェイトは省略可能
	child_0
	child_1
	...
	child_k
```

| 返り値 | 条件 |
|:-:|:-:|
| Running    | ランダム選択された子ノードがRunningの時          |
| Succeeded  | ランダム選択された子ノードがSucceededを返したとき |
| Failed     | ランダム選択された子ノードがFailedを返したとき   |

### repeat

- `repeat`ノードは整数の引数を１つ持ち、子ノードを引数の数だけリピート実行する。
- 引数を省略すると子ノードを無限回リピート実行する。
- `repeat`ノードは、子ノードを必ず１つだけ持つ
- `repeat`ノードは、子ノードを引数回Succeededさせた場合にSucceededを返す（子ノードが引数以下の回数のSucceededであるならば、`repeat`ノードはRunningを返す）（引数を省略した場合、`repeat`ノードはSucceededを返すことはない。ずっとRunnging返す。Failedを返す場合はある。）
- `repeat`ノードは、子ノードがFailedを返した場合にFailedを返す。

```C#
repeat(n) //引数は省略可能
	child_0
```

| 返り値 | 条件 |
|:-:|:-:|
| Running    | 子ノードのSucceeded回数が引数よりも小さいとき       |
| Succeeded  | 子ノードのSucceeded回数が引数回数になった時（引数を省略した場合Succeededにはならない。） |
| Failed     | 子ノードがFailedを返したとき   |

### while

- `while`ノードは必ず２つの子ノードを持つ
- 1つ目のノードは条件(`condition`)を表す。2つ目のノードはアクション(`action`)を表す。
- `condition`ノードがFailedを返すまで、`condition`ノードと`action`ノードが繰り返し実行される。
- `action`ノードは、`condition`ノードの成功判定後に実行される。
- `action`ノードがSucceededを返した場合、`while`ノードもSucceededを返す。
- `condition`ノードまたは`action`ノードがFailedを返した場合、`while`ノードもFailedを返す。

```C#
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`ノードは必ず１つの子ノードを持つ
- `not`ノードは子ノードの状態を反転させる
- 子ノードがSucceededを返したとき、`not`ノードはFailedを返す
- 子ノードがFailedを返したとき、`not`ノードはSucceededを返す
- 子ノードがRunningを返したとき、`not`ノードもRunningを返す

```C#
not
	child

// もう一つの書き方
not child
```

| 返り値 | 条件 |
|:-:|:-:|
| Running    | 子ノードがRunning状態のとき |
| Succeeded  | 子ノードがFailedを返したとき |
| Failed     | 子ノードがSucceededを返したとき |

### mute

- `mute`ノードは必ず１つの子ノードを持つ
- `mute`ノードは子ノードがFailedの場合でもSucceededを返す（Failedには絶対にならなくなる）
- 子ノードがSucceededを返したとき、`mute`ノードはSucceededを返す
- 子ノードがFailedを返したとき、`mute`ノードはSucceededを返す
- 子ノードがRunningを返したとき、`mute`ノードもRunningを返す

```C#
mute
	child

// もう一つの書き方
mute child
```

| 返り値 | 条件 |
|:-:|:-:|
| Running    | 子ノードがRunning状態のとき |
| Succeeded  | 子ノードがSucceededまたはFailedを返したとき |
| Failed     | 絶対にFailedにはならない |


# ビルトインのノードを少し紹介

Panda BTに最初から用意されている便利なノードについても少しまとめておきます。
完全なビルトインのノードのリストは以下で確認できます。 
 
http://www.pandabehaviour.com/?page_id=23#Built-in_Tasks

### Status系

単に状態を返すだけのノードがあります。たまに使います。

```C#
Succeed //Succeededを返すだけ
Fail    //Failedを返すだけ
Running //Runningを返すだけ
```
### Wait系

一定時間処理をWaitする場合に使います。

```C#
Wait(3.0)			//3.0秒waitする
Wait(10)			//10フレームwaitする
RealtimeWait(3.0)	//3.0秒waitする。TimeScaleを無視する（Unscaled）
```

### Debug系

Debug.Logを仕込むこともできます。

```C#
DebugLog("StringMessage") //コンソールにログを表示したときに利用する
```

# アセットに含まれるサンプル紹介

最後にアセットに含まれるサンプルシーンをご紹介します。

一定時間ごとに色を変化させるサンプルです。
![ezgif.com-video-to-gif (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58282/8d5d9afd-f45b-14c8-ea7b-8f2d8a65eb0a.gif)

直方体を自動的に動かすサンプルです。
![ezgif.com-video-to-gif (2).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58282/e8a31f7d-a06d-5460-67ad-1fca5395126f.gif)

Hotlineマイアミのようなサンプルです。
敵キャラとプレイヤー両方ともPanda Behaviourコンポーネントを利用して実装されています。
![ezgif.com-video-to-gif (3).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58282/2be1937f-24c5-6b0e-d57f-b4eec81fefac.gif)

# 無料で全機能が使えます

Panda BTにはPro版とFree版があります。

Pro版では以下の３つの機能が強化されます。
1. BehaviourTree内にBreakPointが設定できる（デバッグ機能の向上です。）
2. インスペクタ上のドラッグ＆ドロップでBTスクリプトを編集できる（編集機能の向上です。エディタで修正する手間が省けるので割と便利です。）
3. 全ソースコードが付属する（Free版はDllとして提供される）（アセットの保守、改造が自分で出来るようになります。）

Pro版では、Free版よりもデバッグ／編集／保守などのゲーム制作ワークフロー上の機能が強化されるだけです。なので、Free版とPro版の間で出来上がったゲームの性能に違いは生まれません。より効率的に作業したくなったらPro版の購入を検討しましょう。

**UnityでシンプルにBehaviour Treeをやってみたい！と思う人はぜひPanda BTを使ってみてください！**

![f865cebe-b9cf-41e6-8078-61f9cc6dbbb2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58282/fcf2a8a0-154a-13c8-f2a1-cdb894101bbf.png)

[Panda BT Free](https://assetstore.unity.com/packages/tools/ai/panda-bt-free-33057?utm_source=twitter&utm_medium=social&utm_campaign=jp-advent-calendar-summer)
[Panda BT Pro](https://assetstore.unity.com/packages/tools/ai/panda-bt-pro-58170?utm_source=twitter&utm_medium=social&utm_campaign=jp-advent-calendar-summer)
[Panda BTのドキュメント](http://www.pandabehaviour.com/?page_id=23)

# 補足

この記事は、Unity アセット真夏のアドベントカレンダー 2020 Summer! 8月14日のために書かれた記事です。

http://assetstore.info/eventandcontest/adventcalendar/summer-advent-calendar-2020/
![summer_Advent_banner_3_La-1-1024x593.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58282/9ec88ade-62b3-c6e7-acfb-d7193a1054ad.png)