敵が自分を追跡する処理が必要な際に重宝する、NavMeshを学習しよう。
ステージの作成
1.CreateEmptyからStageを原点に作成する
2.Stageの中にCubeからFloorを作成するtransformは以下
![](http://joytas.net/wp-content/uploads/2017/10/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88-2017-10-11-20.46.07.png)
3.新規にマテリアルを作成し、Floorにアタッチする。色は茶色っぽくする。
![](https://joytas.net/wp-content/uploads/2024/05/SampleScene_-_NavMesh_-_Windows__Mac__Linux_-_Unity_2022_3_20f1__Metal_-1024x947.png)
4.カメラを調整しておこう。transformは以下
![](https://joytas.net/wp-content/uploads/2024/05/SampleScene_-_NavTest_-_Windows__Mac__Linux_-_Unity_2022_3_20f1__Metal__と_投稿を編集_‹_ジョイタスネット_—_WordPress.png)
![](https://joytas.net/wp-content/uploads/2024/05/SampleScene_-_NavMesh_-_Windows__Mac__Linux_-_Unity_2022_3_20f1__Metal_-1-1024x945.png)
5.Stageの子要素としてCylinderを作成する。transformは以下
![](http://joytas.net/wp-content/uploads/2017/10/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88-2017-10-11-20.48.52.png)
6.CylinderをCtr+Dで複製しながら以下のように並べる(大雑把で良い)
![](https://joytas.net/wp-content/uploads/2024/05/SampleScene_-_NavMesh_-_Windows__Mac__Linux_-_Unity_2022_3_20f1__Metal_-2-1024x797.png)
NavMeshのインポート
navMesh以前はUnityに同梱されていたが、今は分離されている。
インポートして使えるようにする。Windowメニューからpackage managerを開く
![](https://joytas.net/wp-content/uploads/2024/05/スクリーンショット_2024-05-23_15_13_27-534x1024.png)
上部三角を押して、Unity Registryを選択
![](https://joytas.net/wp-content/uploads/2024/05/スクリーンショット_2024-05-23_15_15_25.png)
検索窓にnavといれると表示されるAI NavigationをInstallする。
![](https://joytas.net/wp-content/uploads/2024/05/Package_Manager-1024x328.png)
これでNavMeshが使えるようになった。
まずは、Floorを選択して、Add Componentから NavMeshSurfaceを追加する
![](https://joytas.net/wp-content/uploads/2024/05/スクリーンショット_2024-05-23_15_21_06-851x1024.png)
追加されたコンポーネントみると、初期設定として以下のように設定されている。これは今回NavMeshに従って動く物体の設定をしている。
身長が2m
半径が0.5m
登れる段差が75cm
登れる角度が45度
という値が初期値となっている。
![](https://joytas.net/wp-content/uploads/2024/05/SampleScene_-_NavMesh_-_Windows__Mac__Linux_-_Unity_2022_3_20f1__Metal_-3.png)
想定しているキャラの大きさが違う場合はAgent Typeの右にあるプルダウンから再設定できる。(今回は初期設定のまま行う)
![](https://joytas.net/wp-content/uploads/2024/05/スクリーンショット_2024-05-23_15_30_18.png)
下部にあるBakeボタンを押す
![](https://joytas.net/wp-content/uploads/2024/05/SampleScene_-_NavMesh_-_Windows__Mac__Linux_-_Unity_2022_3_20f1__Metal_-4.png)
シーンビューを開いてみよう。敵が通れる部分が設定され、その部分が青く表示されている。これでNavMeshの設定が完了だ。
![](https://joytas.net/wp-content/uploads/2024/05/SampleScene_-_NavMesh_-_Windows__Mac__Linux_-_Unity_2022_3_20f1__Metal__と_投稿を編集_‹_ジョイタスネット_—_WordPress-1024x782.png)
Playerの作成
敵に追いかけられることとなるPlayerを作成しよう。
最初にCreateEmptyからPlayerを作成し、transformを以下のように設定。
![](https://joytas.net/wp-content/uploads/2024/05/SampleScene_-_NavMesh_-_Windows__Mac__Linux_-_Unity_2022_3_20f1__Metal_-8-1024x278.png)
その後、Playerの子要素としてCubeを2つ作成し、HeadとBodyという名にする。それぞれのTransformは以下
![](https://joytas.net/wp-content/uploads/2024/05/SampleScene_-_NavMesh_-_Windows__Mac__Linux_-_Unity_2022_3_20f1__Metal_-6-1024x345.png)
![](https://joytas.net/wp-content/uploads/2024/05/SampleScene_-_NavMesh_-_Windows__Mac__Linux_-_Unity_2022_3_20f1__Metal_-7-1024x350.png)
Player用のマテリアルを作成してアタッチする。何色でもよいが今回は青にした。
![](https://joytas.net/wp-content/uploads/2024/05/SampleScene_-_NavMesh_-_Windows__Mac__Linux_-_Unity_2022_3_20f1__Metal_-9.png)
まずはもっとも単純な移動スクリプトを作る。PlayerController1.csとして以下のように作成する。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController1 : MonoBehaviour {
void Update () {
transform.Rotate (0, Input.GetAxis ("Horizontal")*100f*Time.deltaTime, 0);
transform.Translate (0,0,Input.GetAxis ("Vertical") * 5.0f*Time.deltaTime);
}
}
Playerに付与して実行してみよう。Translateでの移動は最強といっていい。あらゆるものを無視して移動する。当然Cylinderをすり抜ける。
Enemyの作成
それでは追跡してくる敵を作成しよう。新規3D object->CapsuleからEnemyを作成し表面材質(赤)を設定する。Transformは以下。
![](https://joytas.net/wp-content/uploads/2017/10/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88-2017-10-11-21.16.55.png)
![](https://joytas.net/wp-content/uploads/2024/05/SampleScene_-_NavMesh_-_Windows__Mac__Linux_-_Unity_2022_3_20f1__Metal_-10-1024x716.png)
Enemyを選択し、AddComponentからNavMeshAgentをアタッチする。
![](https://joytas.net/wp-content/uploads/2024/05/スクリーンショット_2024-05-23_16_06_13-888x1024.png)
EnemyController.csを以下のように作成して、Enemyに付与する。(using UnityEngin.AIを忘れないこと)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class EnemyController : MonoBehaviour
{
public Transform player;
//索敵範囲
public float traceDist = 10.0f;
NavMeshAgent nav;
void Start()
{
nav = GetComponent<NavMeshAgent>();
//毎フレーム距離の計測をする必要はないのでコルーチンで行う。
StartCoroutine(CheckDist());
}
IEnumerator CheckDist()
{
while (true)
{
//1秒間に5回距離を計測する。
yield return new WaitForSeconds(0.2f);
//プレイヤーとの距離を計測
float dist = Vector3.Distance(player.position, transform.position);
//索敵範囲に入ったか?
if (dist < traceDist)
{
//プレイヤーの位置を目的地に設定
nav.SetDestination(player.position);
//追跡再開
nav.isStopped=false;
}
else
{
//探索範囲から出たら追跡終了
nav.isStopped=true;
}
}
}
}
インスペクターからplayerを登録し、実行してみよう。プレイヤーの距離に応じて追跡を開始すれば成功だ。
Playerの動き変更1
今のままではPlayerはステージ外にいっても落ちないし、Cylinderもすり抜ける。修正しよう。PlayerにCharacterControllerコンポーネントを付与する。
コライダーの設定を以下のようにする。
![](https://joytas.net/wp-content/uploads/2024/05/SampleScene_-_NavMesh_-_Windows__Mac__Linux_-_Unity_2022_3_20f1__Metal_-11.png)
PlayerController1を無効にして、PlayerController2を以下のように作成し付与する。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController2 : MonoBehaviour {
CharacterController cc;
void Start () {
cc = GetComponent<CharacterController> ();
}
void Update () {
transform.Rotate(Vector3.up*Input.GetAxis("Horizontal")*100f*Time.deltaTime);
cc.Move (transform.forward*Input.GetAxis("Vertical")*5.0f*Time.deltaTime);
}
}
Move関数で動かすことにより、Sylinderをすり抜けられなくなった。その他にも坂があれば45度以下は登るし、30cmの段差なら無視して進むことができる。ただ、Move関数は自分で重力を実装しないと下方向の重力はない。(ステージ外に行っても落ちない)
SimpleMoveでの移動
さらに変更してみよう。以下のようにMoveからSimpleMoveでの移動に変更してみる。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController2 : MonoBehaviour {
private CharacterController cc;
void Start () {
cc = GetComponent<CharacterController> ();
}
void Update () {
transform.Rotate(Vector3.up*Input.GetAxis("Horizontal")*100f*Time.deltaTime);
//cc.Move (transform.forward*Input.GetAxis("Vertical")*5.0f*Time.deltaTime);
cc.SimpleMove (transform.forward*Input.GetAxis("Vertical")*700.0f*Time.deltaTime);
}
}
SimpleMoveでは重力が与えらる。なので画面外に行った時に落下する。しかもEnemyと衝突したときに押し出されることも確認できる。ただし、スクリプトによって上方にジャンプパワーなどを与えることはできない。MoveとSimpleMoveはどちらも癖がある、どちらを使うかは吟味のしどころだ。
コメント