【UE4】「AIが動かない！」そんな時にチェックするべき項目

# はじめに
[UE4 AnswerHub](https://answers.unrealengine.com/spaces/16/japanese.html) の中でよく見る質問の１つに **「AIが動かない」「プレイヤーに向かって歩いてくれない」** 等があります。動かないというのは想像できる原因があまりにも多く浮かびますが、実際はほとんどが何らかの設定ミスだったり、追跡対象となるアクタをきちんと取得できていなかったりといった単純なものです。（特定の状況で稀に発生してしまうテクニカルな原因もあると思います）

この記事ではAIが動かない原因（特に移動しないもの）とその解決方法を紹介します。


# 原因：NavMeshBoundsVolumeの配置し忘れ
Nav MeshをUE4で生成するためのコンポーネントが**NavMeshBoundsVolume**です。このコンポーネントをレベル上に配置しない限りUE4のAIは移動可能範囲を認識できず追いかけるべき対象（プレイヤー等）への移動経路を見つけられずにスタック（立ち往生）し続けてしまいます。

ゲーム上でAIが動くためには ** [Nav Mesh（Navigation Mesh）](https://wiki.denfaminicogamer.jp/ai_wiki/ナビゲーション・メッシュ) ** が必須となります。AIにとってゲーム中に描画されるメッシュはただの頂点の集合にしか見えておらず、その頂点の集合が「歩けるもの」か否かが判断できません。そこでAIに対し「ここの範囲は移動可能ですよ」「ここから先は進めません」「ここは一方通行です」といった意味を与えた頂点の集合をNav Meshといいます。

### 確認方法
NavMeshBoundsVolumeをきちんと配置しているか確認する方法として**Pキー**を押す方法とWorld Outlinerで同名のアクターがあるか確認する方法があります。

### 解決方法：NavMeshBoundsVolumeを配置する
解決方法は単純でNavMeshBoundsVolumeをレベル上に配置するだけです。この時にAIが歩ける範囲（歩いて欲しい範囲）に合わせて適切なサイズに調整することも忘れないでください。NavMeshBoundsVolumeは必ずレベル上に１つだけという制約はありません。地形に合わせて複数個配置しても問題なく動作します。

配置した後は**Pキー**を押して緑色の領域が描画されるかチェック、もしくはWorld Outlinerで同名のアクターがあるか確認します。

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104467/0d80980c-8c3b-a983-096e-ad49f049d196.png">
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104467/23fd752d-6787-870b-c0cb-8e7d23fde1a9.png">

---

# 原因：Nav Meshが生成されていない
NavMeshBoundsVolumeは配置されているのにAIが動かない場合ももちろんあります。数多くある原因の１つに「Nav Meshが生成されていない」があります。頻繁に起こるような問題ではありませんがプロジェクトフォルダに生成される「Savedフォルダ」「Intermediateフォルダ」等を削除したり、エンジンバージョンをアップした際に実行されるプロジェクトのアップデート時にうまくNav Meshが生成されずプレイしてもAIがスタックし続けることがあります。（NavMeshBoundsVolumeやNavModfierVolumeの座標を詳細パネルで直接値を入力したときにも、同様の問題が発生することがあります）

### 確認方法
確認方法として、原因１でも紹介した**Pキー**を押して緑色の領域が表示されるかどうかで判断するのが確実です。
World Outlinerに同名のアクターがあるにも関わらず緑色の領域が表示されないときはこの原因を疑ってみるべきだと思います。

Pキーで緑色の領域を表示する際の罠として**ビューポートのリアルタイム描画**をオフにしているとPキーを押しても表示されないので確認する際にはリアルタイム描画をONにすることを確実に行ってください。

### 解決方法その１：NavMeshBoundsVolumeやNavModifierVolumeをちょっぴり動かす
Nav Meshが生成されていないのなら、またNav Meshを生成させればいいじゃないという考えです。
NavMeshBoudsVolumeを選択して移動ツールのいずれかの軸を1目盛り動かして1目盛り戻します。この時に更新処理が実行されNav Meshが生成されます。

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104467/bcb708b9-1f0f-fc5e-5e52-ba517e38bcb8.png">

### 解決方法その２：Project Settings->Engine->Navigation Mesh->Runtime->Force Rebuild on LoadをTRUEにする
Project SettingsではNav Meshに対するオプション項目がいくつか用意されています。その中に**Force Rebuild on Load**というものがあります。文字通りレベル読み込み時にNav Meshの生成を強制的に行うというものです。（デフォルトではレベル読み込み時点で正常に構築されたNav Meshがあれば生成処理はスキップされます）
解決方法その１でも解決しなかった場合にこのオプションを有効にしてみると改善されるかもしれません。（ほとんどはその１の方法で解決出来ます）

---

# 原因：Move To系のGoal Actor/Target Actorに有効な値が渡されていない
プレイヤーを追いかけ回したい時に何らかの方法（All Actors Of Classを使ったり、AI Perceptionを使ったり）でプレイヤーのオブジェクトを取得すると思いますがうまくプレイヤーのオブジェクトが取得出来ていなければ当然AIは動きません。

### 確認方法：ブレークポイントを置く
有効な値が渡されているかを確認するにはIs Validノードを使う方法もありますが、Move To系ノードにブレークポイントを置く方法が最も簡単で手軽です。
ブレークポイントで停止しているときにGoal ActorやTarget Actorにつながるピンにカーソルを合わせるとピンの内容を読み取る事が出来ます。中身のcurrent valueに長いURLがあれば有効な値で、Noneの場合は無効な値が入っています。

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104467/bb976b8d-ab9c-ef8a-52a7-9ad8d9d6f3c7.png">

### 解決方法：追跡対象の取得方法、取得過程を見直す
Get All Actors Of Classノードで追跡対象のオブジェクトを取得する場合は追跡対象のクラス名が希望通りのものであるか、追跡対象のアクタはレベル上に配置されているのかをきちんと見直す必要があります。
Get All Actors Of Classで指定したクラス名が何らかの理由によって製作中に変更された（BP_PlayerをBP_MeleePlayerに名前を変更した等）場合、Get All Actors Of ClassのActor Classが**None**になっていることがあります。
Get All Actors Of Classは**レベル上にあるオブジェクトを検索対象**とします。プレイヤーと追跡対象としたのにレベルにプレイヤーを配置していなかったために無効な値が渡され移動しない、ということもあります。

パトロールをするAIを作る際にありがちなことですがパトロールの経路を**Target Point**を使ってコントロールする場合、TargetPoint型の変数を作成後に**編集可能**のチェックを付けて詳細パネルでTarget Pointを指定出来るようにしたにも関わらずTarget Pointを指定し忘れてしまう、といううっかりミスもあります。

![2019-10-28_16h16_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104467/2aab7b57-9597-632e-9802-ce35d34fea0a.png)

AI Perceptionを使っている場合はそもそもAI Perceptionがプレイヤーを認識しているかをチェックする必要があります。
[【UE4】AI Perception の紹介と使い方](https://qiita.com/Dv7Pavilion/items/741402f4da609ec595a2)

---

# 原因：Move To系のGoal Location/Destinationに有効な値が渡されていない
Goal Actor/Target Actorと同じです。Move To系のノードではアクターオブジェクトだけではなくVector3型の値も指定することが出来ます。この時に何らかの理由で無効な値が渡されていたり、そもそもNav Meshが敷かれていない場所を指定していた場合もAIが動くことはありません。

### 確認方法：ブレークポイントを置く。もしくは目視で座標を確認。
１つ上の原因で紹介した方法はこちらでも使えます。ブレークポイントで停止した時にカーソルをピンに合わせた時**極端に大きい/小さい値**が入っていたら無効な値です。
Target Pointやその他アクタを使ってAIに移動位置を指定する場合は**目視でNav Mesh上にアクタがあるか**確認する必要があります。

### 解決方法その１：座標が確実にNav Mesh上にあるように修正する
Target Point等のアクタを使って移動先を指定する場合は確実にNav Mesh上にあるように移動させてください。制作が進みレベルがどんどん複雑になるにつれてTarget Pointが他のオブジェクトの下敷きになっていたりすることがあります。（World Outlinerで漏れが無いようにチェックしてください）
アクタが宙に浮いている場合は**Endキー**を押して確実に地面へスナップさせてください。

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104467/9cc67b5b-0c86-5c79-a1d0-e2b2d076b907.png">

### 解決方法その２：位置が動的に決まる場合はProject Point To Navigationを使う
EQSやブループリントで何らかの計算によりAIの目標位置が動的決まってしまう場合、解決方法その１のような手作業での位置修正は行なえません。そんな悩みにきちんと答えてくれる便利機能がUE4にはあります。それが**Project Point To Navigationノード**です。使い方については[【UE4】EQSを使わずにプレイヤーを周回するような位置を求める](https://qiita.com/Dv7Pavilion/items/66c71f17199e462de0e3)を参照してください。

Project Point To Navigationノードは与えられた座標をQuery Extent内にあるNav Meshに投影され座標が補正されることになります。求めた位置が空中になってしまった時、Project Point To Navigationノードを使ってNav Meshが敷かれている地面に補正することが出来ます。
活躍の機会はあまりないノードではありますが、非常に便利なノードの１つです。覚えておいて損はないでしょう。

---

# 原因：Acceptance Radiusの値が大きすぎる
Move To系のノードには**Acceptance Radius**という項目があります。これは移動先の座標に**どれだけ近づいた時に移動完了とするか**を決める項目です。例えばAcceptance Radiusが50の場合は目標位置の半径50以内に近づくと移動完了と判断し移動処理を停止します。（デフォルトの-1.0の場合Agent Radiusの0.1倍の大きさがAcceptance Radiusになります。PathFollowingComponent.cppの665行目を参照）
設定されたAcceptance Radiusの値が非常に大きい値だった場合、Move To系ノードを呼び出した時点で既にゴールがAcceptance Radiusの範囲内に入ってしまっているため移動完了と判断されていしまい、AIが動かないことになります。

### 確認方法：Acceptance Radiusの値を小さくしてみる
Move To系ノードに直接Acceptance Radiusの値が設定されていれば、その値を小さく（デフォルトの-1.0等）して動作を確認してみるのが確実な方法だと思います。変数等で設定されている場合は変数の中身や計算過程を見直す必要があります。

### 解決方法：まずはデフォルト値で動かして徐々に値を大きくする
最初にデフォルト値である-1.0で動作確認をします。もしこれでもAIが動かなかった場合は他に原因があるはずです。無事に動作したら値を少しずつ大きくしていって調整します。

---

# 原因：AI Controllerがスポーン時にPossessされていない
地味にハマる問題です。AIキャラクターはAI ControllerがPossessされて初めてAIとして活動することが出来ます。AIキャラクターをスポーンさせるときは**Spawn AI from Class**ノードを使いますが、このときAIキャラクターのClass Defaults内にある**Auto Possess AI**がデフォルトの**Placed in World**のままだとスポーン時にAI ControllerがPossessされず動きません。

### 確認方法：エディタをプレイしたときWorld Outliner内にAI Controllerがあるか確認する
プレイした時に動的に生成されたものはWorld Outliner内では黄色っぽい色でアクタ名が表示されます。この中にAIキャラクターがPossessするべきAI Controllerクラスが存在するか確認する方法があります。
<img height="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104467/2f6ee455-a5ce-e1a8-5284-19ebbb932d87.png">

### 解決方法：Auto Possess AI を Placed in World or Spawned に変更する
Auto Possess AIから選びる項目の中に**Placed in World or Spawned**があります。見ての通りレベルに配置されたときもしくはスポーンされた時は自動でAI ControllerをPossessするよを意味します。ここの項目は常にPlaced in World or Spawnedにしてしまってもいいと思います。
<img height="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104467/963ddb2f-5be4-0240-41ea-d917bb5896c4.png">

---

# 原因：AIキャラクターをSpawn Actor from Classでスポーンした
**Spawn AI from Class**ではなく通常のSpawn Actor from Classでスポーンさせたときも同様に動きません。原因は上と同じです。

### 確認方法：上と同じ

### 解決方法：上と同じ
上と同様にAuto Possess AIをPlaced in World or Spawnedにしておけば問題なく動作しますが、他にも解決方法があります。（以下を参照）
[UE4 スポーン時のアクター（SpawnActor）が動かない理由と対処方法](http://unrealengine.hatenablog.com/entry/2015/06/22/220000)

---

# 原因：Movementコンポーネントの追加し忘れ
これに該当する方はあまりいないかもしれませんが、自分は過去にこの罠を踏んだことがあります。
何らかの理由によって**PawnクラスやActorクラス**をAIのベースクラスとして選択したとき、生成されたブループリントのコンポーネントには**DefaultSceneRoot**のみがあります。これにCapsule CollisionやSkeletal Meshコンポーネントを追加して今まで書いてきたチェック項目を全て通過したとしてもAIは動きません。原因は見出しにもあるように**Movementコンポーネント**が追加されていないからです。

### 確認方法：構成されているコンポーネントにMovementコンポーネントがあるか確認

### 解決方法：ベースクラスをCharacterクラスに変更。もしくはFloating Pawn Movementコンポーネントを追加。
Character MovementコンポーネントやFloating Pawn Movementコンポーネントがきちんと追加されていればOKなので、ベースクラスをCharacterクラスに変更するかFloating Pawn Movementコンポーネントを追加すれば解決します。
個人的な考えですがよっぽど大量のAIキャラクターを動かしたりしない限りはCharacterクラスをベースにしてしまっても良い気がします。

多くの方がMovementコンポーネントの有無を意識することは無いと思います。ネットにあるAIのチュートリアルでは殆どが**Characterクラス**をベースに派生させたAIキャラクターブループリントを作成しますので、わざわざ意識する必要はありません。Characterクラスをベースにしてしまえば勝手にCharacter Movementコンポーネントが付いてきます。しかし、何らかの理由によってそういった「いつもの流れ」からほんの少し外れただけでもAIは動かなくなりますのでこの解決方法は知っておくべきだと思います。

> 余談ですが全てのAIキャラクターをCharacterクラスをベースにする必要もありません。セキュリティカメラや**設置型タレット**等の場合はそもそも移動する必要が無いのでMovementコンポーネントが不要になります。そういった場合はPawnクラスやActorクラスをベースにしてしまっても良いでしょう。