Behavior DesignerでAIを組んでみる

Behavior Desinger
https://www.assetstore.unity3d.com/jp/#!/content/15277

Behavior Designerを使って簡単なAIを組んでみます。

##概要
Behavior DesignerはBehavior Tree形式を利用してNode/GUIベースでAIが組めるアセットです。Behavior Treeの形式を理解していれば割とすんなりBehavior Designerを使えるようになるかと思います。
ゲーム再生中にAI Nodeの結果が見れたり拡張性が高かったりと割と便利なので、今後AIを作る際は使っていきたいアセットの１つ。
ドキュメントもしっかりしているので安心。

##導入
普通にアセットからインポートしてツールを起動する。
<img width="1335" alt="スクリーンショット 2017-01-12 1.07.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/256b1510-145a-857f-69f8-9fad27ee4ead.png">
割と見やすいUIになっている。
UIの説明はドキュメントを参照
http://www.opsive.com/assets/BehaviorDesigner/documentation.php?id=1

設定とかは特に必要なくこのまま使える。

##超簡単なAIを書いてみる。
Behavior Designerが使っているBehavior TreeというAI実装形式はTaskという処理単位でAI実装が行われます。
Taskは実行結果を必ず返します。Running(実行中),Success(成功したよ),Failure(失敗したよ)等。
Taskは4つの種類があります。
1: Action (何かを実行する。ex:攻撃アニメーションを開始する)
2: Conditional (何かを判断する。ex:体力が5以下であるか)
3: Composites (1つ、または複数のタスクを子タスクとして内包できる。内包した子タスクを指定した方法で実行する)
4: Decorator (タスクの結果を変更する。ex:失敗を返す。リピートする等)

これらのTaskを組み合わせることで任意のAIをフレキシブルに作成することが可能です。
Behavior Desginerでは基本的なTask(ex:Animatorを制御する。ボタンが押されている等)はあらかた用意されています。もちろん用意されているだけのTaskでは複雑なAIを組めません。そのためBehavior Designerでは簡単にTaskを追加しやすいように設計されており、これによってエンジニアは自由に、そして簡単に新しいTaskをいくつでも作成することができます。

新しいTaskの追加方法はこちら
http://www.opsive.com/assets/BehaviorDesigner/documentation.php?id=5

とはいえ最初なのでデフォルトで用意されているTaskだけを使ってAIを組んでいこうと思います。
とっても簡単に
"Key入力があったら" + "X座標0.1移動する"
AIを作ろうと思います。


思考としては、
1. ずっと処理をさせたいのでリピートさせる
2. Key入力があったか判定
3. 座標を移動させる
があります。

これをBehavior Designerで実装するとこうなりました。(各NodeのInspectorをいじっています)
![2017-01-14 02.49.27.jpg](https://qiita-image-store.s3.amazonaws.com/0/67575/c56c21bc-cb29-3d72-0fc4-7d2055aca9a0.jpeg)

簡単 :) 

##Compositesについて
ActionやConditionalsは分かりやすいのですが、Compositesタスクがいまいちわかりにくいのでいろいろ調査してみます。
Composites（コンポジット）の意味は”複合”とのこと。自分の子タスクを複合していろいろできるよってことでしょうか。

デフォルトで用意されているCompositesタスクの種類
- Sequence
- Selector
- Parallel
- Parallel Selector
- Priority Selector
- Random Selector
- Random Sequence
- Selector Evaluator
- Utility Selector

###Sequence
SequenceタスクはAndオペレーションと似ています。いくつでも子タスクをセットでき、左から順番に子タスクを実行していきます。子タスクが一つでもFailureを返した場合は、子タスク実行をやめて、すぐさま自身もFailureを返して自身のタスクも終了させます。すべての子タスクがSuccessを返した場合のみ自分もSuccessを返して終了します。

###Selector
SelectorタスクはOｒオペレーションと似ています。いくつでも子タスクをセットでき、左から順番に子タスクを実行していきます。子タスクが一つでもSuccessを返した場合は自身もすぐさまSuccessを返して終了します。子タスクがFailureを返した場合はすぐさま次の子タスクを実行し、すべての子タスクがFailureを返した場合は、自身もFailureを返して終了します。
子タスクがSuccessを返した場合は残りの子タスクが実行されないことに注意ですね。

###Parallel（パラレル）
パラレルの意味は平行です。パラレルワールドのパラレルですね。
ParallelタスクはSequenceタスクに似ています。子タスクがFailureを返すまで子タスクを実行させます。
Sequenceとの違いは、子タスクをいっぺんに実行させる点です。子タスクが一つでもFailureを返した場合は、すべての子タスクを終了させ、自身もFailureを返して終了します。

###Parallel Selector
このタスクはSelectorに似ています。いっぺんに子タスクを実行し、一つでもSuccessが返ってきた場合は、すぐさまほかの子タスクを終了させ、自身もSuccessを返します。
すべての子タスクがFailureを返した場合は自身もFailureを返します。

###Priority Selector
このタスクはSelectorに似ています。左から順に子タスクを実行するのではなく、各子タスクのPriorityをチェックし、Priorityの高い子タスクから実行していきます。一つでも子タスクがSuccessを返せば自身もSuccessを返して終了します。

###Random Selector
このタスクはSelectorに似ています。子タスク実行時にSuccessが返れば自身もSuccessを返します。違いは、子タスクの実行順序をランダムで決めることです。シードを指定してランダムさせることも可能です。

###Random Sequence
Random SelectorのSequence版です。

###Selector Evaluator
Selector Evaluatorはすべての子タスクを毎チック時に再評価するタスクです。Runningステートを返す子タスクの内、Priorityがもっとも低い子タスクから実行されます。毎チック時にこの処理が行われます。もしPriorityの高い子タスクがRunningを返してきて、次のフレームにPriorityの低い子タスクをRunしようとした場合は、Priorityの高い子タスクに割り込み処理を入れます。Selector Evaluatorは一番最初に実行が終わった子タスクの評価がSuccessだった場合のみ自身もSuccessを返します。そうでない場合は、Priorityの高い子タスクたちを実行し続けます。このタスクはconditional abortの模倣です。また、子タスクはConditionalである必要はありません。Actionでも可能です。


###Utility Selector
Utility Selectorは子タスクを utility theory aiを使って評価するタスクです。子タスクはUtility値をいつでも設定することができます。一番高いUtility値を持つ子タスクが実行され、その際、既存のRunning中だった子タスクは中断されます。Utility Selector は毎チック子タスクを再評価します。