プレイヤーを追いかけてくるキャラクターの実装

UnityのNavMeshAgentを使うと、オブジェクトを目的地に向かって自動で移動させることが出来ます。これを使ってプレイヤーを追いかけてくるキャラクターを実装します。操作用のキャラクターとそれを追いかけてくるキャラクターの2つのオブジェクトが必要になります。動作環境はUnity 2022.3.10fです。本環境の例ではLevel 1 Monster PackのRabbit_Yellowを操作用キャラクターに、Slime_Greenを追いかけてくるキャラクターに使用しました。

# 準備
最初にキャラクターが移動するためのステージを用意します。Hierarchyビューで右クリックし、3D Object→Cubeを選択します。InspectorビューでScaleのX、Y、Zの値を調整してキャラクターが動き回れる広さの床を作ります。InspectorビューでTagの名前をFloorに設定します。作成した床のオブジェクトの上に2つのキャラクターのオブジェクトを置きます。Add Componentをクリックして両方のキャラクターにBox Colliderをアタッチします。
![image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3644510/8ce38cf6-725e-6622-97ca-446f91055e67.png)


# プレイヤーキャラクターの実装
以下のスクリプトを作って操作する方のキャラクターにアタッチします。

```C#:PlayerController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(Rigidbody))]
public class PlayerController : MonoBehaviour
{
    public float speed; //移動速度
    public float jumpPower; //ジャンプ力
    private bool isJumping = false; //ジャンプ判定
    Rigidbody rigidbody;

    void Start()
    {
        rigidbody = GetComponent<Rigidbody>(); //Rigidbodyを取得
        rigidbody.constraints = RigidbodyConstraints.FreezeRotation; //オブジェクトの回転を防ぐ
    }

    void Update()
    {
        if (Input.GetKey(KeyCode.UpArrow)) //上矢印を押すと奥へ移動
        {
            transform.position += speed * transform.forward * Time.deltaTime;
        }

        if (Input.GetKey(KeyCode.DownArrow)) //下矢印を押すと手前へ移動
        {
            transform.position -= speed * transform.forward * Time.deltaTime;
        }

        if (Input.GetKey(KeyCode.RightArrow)) //右矢印を押すと右へ移動
        {
            transform.position += speed * transform.right * Time.deltaTime;
        }

        if (Input.GetKey(KeyCode.LeftArrow)) //左矢印を押すと左へ移動
        {
            transform.position -= speed * transform.right * Time.deltaTime;
        }

        if (Input.GetKeyDown(KeyCode.Space) && isJumping == false)
        {
            rigidbody.AddForce(Vector3.up * jumpPower); //ジャンプしていない時にスペースキー入力でジャンプする
            isJumping = true;
        }
    }

    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.CompareTag("Floor"))
        {
            isJumping = false; //床に着地したらジャンプ判定をfalseにする
        }
    }

}
```

ジャンプした時にisJumpにtrueを代入することによって空中でジャンプできないようにします。

# 追跡機能の実装
自動で追いかける機能を実装するためにNavmesh Agentを使用します。AI Navigationパッケージをインストールしていない人は、Window→Package Managerを選択してPackage Managerを開きます。AI Navigationを選択してInstallをクリックします。
インストール出来たらWindowにAIという項目が追加されています。AIのNavigation(Obsolete)を選択します。以下の図のようなNavigation(Obsolete)ビューが出てくるので、4種類あるタブの中からBakeというタブを選びます。Bakeを選ぶと色々パラメーターを調整できますが、本環境ではデフォルトのまま使用しました。ここで、先程作ったステージ用のCubeオブジェクトのInspectorビューでStaticにチェックが入っているか確認します。チェックが入っていなかったらクリックしてチェックを入れておきます。確認出来たらNavigation(Obsolete)ビューの下部にあるBakeボタンをクリックします。
![image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3644510/02d4b9ea-69e8-7c75-d153-b34ad24280b2.png)

Bakeが完了すると移動可能な範囲が青色で示されます。
以下のスクリプトをもう一つのキャラクターオブジェクトにアタッチします。

```C#:EnemyMove.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(NavMeshAgent))]
public class EnemyMove : MonoBehaviour
{
    private Transform target;
    private NavMeshAgent agent;
    Rigidbody rigidbody;

    void Start()
    {
        target = GameObject.Find("Rabbit_Yellow").transform; //追いかける対象のオブジェクトのtransformを取得
        rigidbody = GetComponent<Rigidbody>(); //Rigidbodyを取得
        rigidbody.constraints = RigidbodyConstraints.FreezeRotation; //オブジェクトの回転を防ぐ
        agent = GetComponent<NavMeshAgent>(); //NavMeshAgentを取得
    }

    void Update()
    {
        agent.SetDestination(target.position); //追いかける対象を目的地に設定する
    }
}
```

コードの説明を簡単にしておきます。上から4行目に「using UnityEngine.AI;」と書いていますが、Projectビューで右クリックしてC#スクリプトを生成した時には書かれていないので、追加しておくことを忘れないようにしてください。
classの前にRequireComponentを書いておくと、InspectorビューでRigidbodyやNavMeshAgentをアタッチするのを忘れても自動でアタッチされるようになります。
Start関数の中では、GameObject.Findによって追いかけるターゲットにするオブジェクトの名前を指定しています。本環境ではFind()の中は"Rabbit_Yellow"になっていますが、必要に応じて追いかけたい対象のオブジェクト名を入れてください。
Update関数の中では、SetDestinationメソッドによって常にターゲットのオブジェクトが目的地に指定されています。これによってターゲットが移動しても、目的地が更新されてずっとついてくるようになります。
以上で実行すると自分が操作するキャラクターの後を、もう一つのキャラクターが自動で追跡します。
次回はこの状態から発展させて、向かってくる敵を踏んで倒せるようにしたいと思います。

# 参考
https://unity-guide.moon-bear.com/navmeshagent/
https://zenn.dev/k1togami/articles/71519622146168