【Unity2021.3.2f1】NavMeshを使ってステージを作ってプレハブ化したい話

# モチベーション
- 敵を避けながらステージを進んでゴールまで行くようなゲームを作りたい。
- NavMeshというのが、キャラを動かすのに便利らしいので勉強してみたい。

# ステージを作る
ひとまず動くものを作りたいので、見た目はこだわらずにデフォルトのオブジェクト生成のPlateで地面を作成してCubeを作成しました。
はじめはBoxColliderを付与していたが、NavMeshを使う上では特に必要なさそうでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99896/d1f44234-1e75-baf1-0594-46c1de48b5a0.png)

# NavigationWindowからNavMeshをBakeする
後の方に記載するが、NavigationWindowからのBakeはシーンに対するもので、Prefabで作ったステージにNevMeshを張るのは **<font color="Red">全く別の方法になります。</font>**
似たような設定があるのに共通していない、という少し分かりにくい感じなのでシーンに対するNavMeshについて興味のない人は[オブジェクトに対してNavMeshをBakeする方法](#オブジェクトに対してNavMeshをBakeする方法)まで飛ばしてみてもらった方がよいかも知れません。

## NavMeshをBakeする前の準備
NavMeshをBakeする前にMeshを張る予定のすべてのオブジェクトに『NavigationStatic』のステータスを付与する必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99896/383ee091-e6c1-b27b-ab0d-cab593587349.png)

## デフォルト設定でのBake
とりあえずステージが出来たので、Window -> AI -> NavigationでNavMeshのWindowを開いてBakeを実行。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99896/50b9e8f3-b443-3c2a-5417-adb19fb3eaba.png)
**<font color="Red">！？</font>**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99896/2c5d7702-f653-bd42-06b9-61db1d89b383.png)
どうやら、StepHeightやMaxSlopeの設定で、登れる場所と認識されてしまった様子。

## BakedAgentSizeの設定変更によるBake
平面で動かすようなゲームなら、MaxSlopeを0、StepHeightを0.01のように設定するのがよさそう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99896/54827976-6cc4-2c87-f739-2fcf8300fb12.png)

## 他のオブジェクトを進入禁止にする方法
他の手段として、Objectのタブを開いた状態で、SceneやHierarchyでオブジェクトを選択して『NavigationArea』で『Not Walkable』を選択するとそのオブジェクトはBakeの対象にならないので、キチンとしたものを作るのはこちらの方がよさそう。
『NavigationArea』での選択はAreasタブで追加できて、ルートのコストを設定することも出来る様子。レースゲームの砂漠地帯みたいな、通行可能だけれど極力通りたくない、みたいなエリアを作る時に有用そう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99896/6996c880-f03b-a51a-3d9b-75e213d907c7.png)

## NavigationからのBakeはシーンに対して
さて、Bakeが完了したので次のステージを作ろうといったんステージを非アクティブにしたところ、Navigationでの表示はBakeされたものが残っている。
つまりこのMeshはオブジェクトに対してではなく、シーンに対してBakeされている様子。（まぁ、考えればオブジェクトを指定してBakeしているわけではないし、そりゃそうかという感じ）
RPGとかなら、シーンごとにNavMeshをBakeしても問題なさそうだけれども、今回はステージをPrefabにして１シーンで入れ替えたいのでオブジェクトにBakeする方法を考える。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99896/5899d84b-4b32-2427-7e1a-692d406bc68f.png)

# オブジェクトに対してNavMeshをBakeする方法
どうやら、2021.3の段階ではデフォルトで入っているNavigationシステムではPrefabにBakeは出来ない様子。
Experimentalになるが、PackageManagerのAdd package by nameで`com.unity.ai.navigation`と入力することで、NavMeshの他の機能も使えるようになるとのこと。
**2022.2以上であれば、Pre-Release版が使用できるようなので、NavMeshを使用するならそちらの方がよさそう。**

https://docs.unity3d.com/2021.3/Documentation/Manual/NavMesh-BuildingComponents.html

追加されるComponentは下記の４つ。
```
NavMeshSurface - Use for building and enabling a NavMesh surface for one type of Agent.
NavMeshModifier - Use for affecting the NavMesh generation of NavMesh area types based on the transform hierarchy.
NavMeshModifierVolume - Use for affecting the NavMesh generation of NavMesh area types based on volume.
NavMeshLink - Use for connecting the same or different NavMesh surfaces for one type of Agent.
```

https://docs.unity3d.com/Packages/com.unity.ai.navigation@1.0/manual/index.html

ステージのゲームオブジェクトにNavMeshSurfaceをアタッチすることでBakeをすることが出来る。
これでBakeを行うことで、NavMeshのアセットファイルが生成され、このComponentのenableを切り替えることでNavMeshの有効・無効を切り替えることができるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99896/8df8f9ea-2420-7f55-dee0-5a2aa5107de3.png)

## NavMeshSurfaceを使用する際の注意

### Meshの可視化
Bakeを行う際、Prefabをダブルクリックで開いた状態で行うと、何故かNavMeshが可視化できず、どのようにBakeされたのか分かりません。
Scene上でPrefabを開いてBakeするか、Scene上でBakeをしてApplyするかするのがよさそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99896/423d3474-0117-7c88-b4ac-7a47821a017d.png)

### Bakeの対象
NavigationではGameObjectに『NavigationStatic』の設定をしていたが、NavMeshSurfaceではその設定の必要がありません。
代わりに、存在するMeshRendererすべてがNavMeshの対象になる様子です。
プレハブにするなら、ステージの親にNavMeshSurfaceをアタッチしてCollectObjectsのターゲットを『Children』にするのがよさそうな雰囲気。
Volumeは指定範囲内のでのMeshを作成するので、ブロックを組み合わせてマップを作るようなゲームなら有用そう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99896/45173e64-d9c7-078a-7ff8-a63030b0ba99.png)

## 通れないオブジェクトの設定
NavigationでBakeする際は『Object』のタブを使ってNavigationAreaを変更しても対応できない。
そのため、通れなくするオブジェクトにNavMeshModifierをアタッチしてOverideAreaにチェックしてAreaTypeをNotWalkableに設定することで、Bakeの対象から外すことができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99896/b5a1f1ad-3e62-06fc-3bce-2dcdabc2b581.png)

## Agentの設定
NavMeshSurfaceのBakeはNavigationと違ってAgentのMaxSlopeやStepHeightを制御できないように見えますが、AgentTypeの項目がNavigationのAgentsの項目に紐づいているので、こちらで設定を変更すれば反映されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99896/ffc89d20-f466-e368-1e58-00877797bc0b.png)