ビヘイビアツリーを使ってみよう！

# UE4でのAIを設計するために必要なこと
 UE４でAIを作るとき何をすべきか？
どうやればAIを作れるのかを解説したいと思います。

１，４コマまんがを描く
２，AIの構成要素
３、体の実装
４、センサー実装（視覚）
５，センサー実装（聴覚）
６，思考（ビヘイビアツリー）

# 4コマまんが風に描く
作りたいキャラがどんな動きをするのか、
絵にしてみましょう。
今回は３パターンに分けて描いてみました。
１，敵正面からプレイヤーが来る
２，敵背面からプレイヤーが攻撃
３，敵背面から来たプレイヤーが音を出す。
になります。

## パターン１、正面から視野へ入る場合
![1.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/cc480c62-9c85-5127-a3ae-33f2d859d8ee.jpeg)
１，自分（プレイヤー）と敵が居ます。

![2.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/efe6cd4a-7c76-bdfb-4b7e-239f05cc45aa.jpeg)
２，自分が敵の視野に入りました！

![3.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/79850cae-b8fc-4703-2e72-3ab268e9812f.jpeg)
３，敵が自分の方向を向きます！

![4.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/7e6f6c19-4069-6605-cc0e-ef7ffa9cb723.jpeg)
４，敵が自分へ特攻を掛けます！

![5.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/549e18f3-10fd-9dec-f0ab-1c83ae1c43f1.jpeg)
５，攻撃範囲内に入ったらチクっと攻撃します。

![6.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/a2acc335-45ee-8e61-9835-fe01931b2df3.jpeg)
自分(プレイヤー)を撃破、もしくは見失いました。

![7.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/af387e8b-a5f5-344a-7af3-df7b91871aef.jpeg)
定位置へ帰ります。

##パターン２、裏から回り込む場合
![uploading 13.jpg...]()


敵の裏側に自分(プレイヤー)が回りこみました。
![10.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/399994eb-615a-0b1f-7e23-bc4ac1f69c05.jpeg)
この場合は視野に入らずに裏から攻撃できます。
## パターン３、音を出してしまった場合
![11.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/47cc3ec7-3692-f5f7-22f9-31deddc751b9.jpeg)
音を出してしまいました！

![12.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/00af4161-820e-ec94-dd73-939b5c78caf9.jpeg)
敵がこちらを振り返ります！

## ※実際には紙とペンだけで十分です。
実際に描く場合は紙とペンで十分です。
UE4を開く前にどのような動きにしたいのか絵を描きましょう。


# AIの構成要素
下記のように分けます。

AIの置かれた環境
1. 体(敵)
2. センサー（目、耳、を持ちます）
3. 行動(攻撃、振り向き、追跡、帰還、)

AIの考えている事
1. 思考(ビヘイビアツリー)
2. 記憶(BlackBoard)

各項目を１つずつ実装する必要があります。

次章以降で「4コマまんが風に描く」で描いた絵を元に、
AIの置かれた環境、AIの考えていることを実装していきます。

![AIグラフ.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/7455fdb3-4e6f-b51e-e8a3-ad1e2e5e5058.jpeg)



# 体の実装
Mixamoのパッケージを使用しました。
https://www.unrealengine.com/marketplace/mixamo-animation-pack
Mixamoのアニメーションパックを開くと
全キャラクターのベースになっているActorに”MixamoCharacter_Master”が入っています。
コレをコピー＆ペーストし、MixamoCharacter_Master_Enemyを作成します。

次にMixamoCharacter_Master_Enemyの下記BPを全て削除します。
これ等は全て人がキャラを操作するための物なので、AIには不要なものになります。
![master actor.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/b5bbf97b-6f29-f467-abfb-e294b3e9ce55.jpeg)
コレ全部削除

派生されたCharacterである「Mixamo_Jill」たんのParent class に先ほど作成した
"MixamoCharacter_Master_Enemy"に設定します。
![zombie.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/71a91fb5-0438-af15-4795-27d0b8d016c5.jpeg)
このゾンビたん（Mixamo_Jill）を使用しました。

![baseclass.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/f562c2d2-51de-68a5-1cb2-b6b40c6bef8d.jpeg)
ゾンビたん（Mixamo_Jill）のParent class に設定します。

# センサーの実装（視覚）
センサーは下記のようにサービス内での実装になります。
「BTPlayerFinder」というサービスが「視覚」を実装しているサービスになります。
処理完了後は”全体の流れ”の図の通りBlackBoardへ書き込みます。

![service.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/2bae3ed3-43ed-a50c-a38d-07e1a113c459.jpeg)

基本的には公式チュートリアルのこれ
https://docs.unrealengine.com/latest/JPN/Engine/AI/BehaviorTrees/QuickStart/11/index.html
を参考に作成しました。
この処理だけだとキャラの周囲全て見てしまうので
http://www.sousakuba.com/Programming/gs_two_vector_angle.html
ここのページを参考に下記の処理を作成しました。
![siki.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/41cff96e-2e46-142d-7944-62873e22afb4.jpeg)
この関数は引数で
自キャラの座標
敵キャラの座標
自キャラの正面を示す単位ベクトル
を入力すると、自キャラの正面に対する敵キャラ位置の角度を計算してくれます。

センサーの結果はブラックボードへ書き込みます。
![blackboard.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/c74b5e6e-29f0-907d-756b-721f52f6b4b0.jpeg)
Targetが見つけたターゲット
TargetFindedが、ターゲットを見つけた状態の場合はTrueにします。

# センサー実装(聴覚)
聴覚は通常のBPで実装します。
キャラの周りに聴覚エリア用のコリジョンを用意し、
コレにSoundObjectがOverLapした場合にBlackBoardへ書き込みます。
今回はプレイヤーがボタンを押すとSoundObjectをバラ撒くように設定しました。
結果はBlackBoardのSounded、SoundedPosへ書き込みます。

![collide.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/8f92a49d-b685-c68c-30dd-713515cd1ac1.jpeg)
聴覚用コリジョンエリア
![soundObject.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/06542c94-245b-7c79-dd39-00613c98eef9.jpeg)
SoundObject
![blackboard.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/c74b5e6e-29f0-907d-756b-721f52f6b4b0.jpeg)
聴覚用コリジョンエリアにSoundObjectが接触した時にBlackBoardのSounded、SoundedPosへ書き込むよう設定します。

# 行動の実装について
今回は下記の行動を実装しました。
・追跡（UE4に標準で入ってる）
・振り向き
・帰還（UE4に標準で入ってる）

# 思考(ビヘイビアツリー)
ビヘイビアツリーは階層化されたステートチャートと認識して下さい。
ノードの一つ一つは全て何らかのステートであり、名前を付けられるように設計して下さい。
下の図はUMLで言う所のステートチャートの区切りを赤枠で囲った図です。
ビヘイビアツリーは階層型ステートチャートなので下図のような形で、ステートの中にステートチャートが入っている構造になります。

![ビヘイビアツリー.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/836a9e14-8b3d-6ab8-ff1d-2988dac47d48.jpeg)

ビヘイビアツリーのステートチャートは下記の「IsNumEqual」デコレータで作成します。
「ブラックボードの数字」と「設定した数字」が同じ時、trueを返します。
非常に簡単なデコレータですが、最重要デコレータになります。
ブラックボード内の「stMain」が「メインのステート遷移」のステート番号を管理しています。
例えば「待機中＝0」「探索中＝1」「特攻中＝2」と言った形で番号を振り、
デコレータの「IsNumEqual」でステート遷移を作ります。
![is num equal.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/9d06c136-a4b8-5bbe-177c-651c76d2f30d.jpeg)

![blackboard.jpg](https://qiita-image-store.s3.amazonaws.com/0/32364/c74b5e6e-29f0-907d-756b-721f52f6b4b0.jpeg)
stMainがメインのステート遷移を維持しています。
尚、stCautionは作る予定で間に合わなかった残骸です。

※なお、このやり方は我流です。
　どっかのお手本とか参考にしてないのでセオリーではない可能性が高いです。