[Unity]一定距離になったら追ってくる機能の実装(Navmeshを使用)

今回はあるオブジェクトの一定範囲にPlayerが入ったときに、そのオブジェクトが追いかけてくるという機能を作っていきます！

:::note info
使用PC： MacBook Pro (13-inch, M1, 2020)
OSバージョン: 11.5.2
Unityバージョン：2021.3.2f1
:::

今回使用したアセットは以下になります！参考にどうぞ😊
>・[プレイヤー](https://assetstore.unity.com/packages/3d/animations/haon-sd-series-bundle-84992)
・[エネミー](https://assetstore.unity.com/packages/3d/characters/creatures/party-monster-duo-polyart-pbr-195698)
・[ステージ](https://assetstore.unity.com/packages/3d/environments/historic/polylised-medieval-desert-city-94557)

# 実際にプレイすると
（動画ちょっとわかりづらくてごめんなさい）
基本は徘徊してて,,,
![徘徊_1_AdobeExpress.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/c15b8d8b-e249-4ca9-22ea-a49833040b3b.gif)

一定距離に近づくとプレイヤーに近づいてきて衝突したらゲームオーバーシーンに遷移する！
![tuiseki.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/53be8cba-512d-4637-a842-67f35e7fc69f.gif)


# 目次
[1.オブジェクトの準備](#1-オブジェクトの準備)
[2.追跡・徘徊機能の構成](#2-追跡・徘徊機能の構成)
[3.エネミーの設定](#3-エネミーの設定)
[4.スクリプトの作成](#4-スクリプトの作成)
[5.徘徊用の目的地をランダムに生成する](#5-徘徊用の目的地をランダムに生成する)
[6.最後の仕上げ！](#6-最後の仕上げ！)

# オブジェクトの準備
今回は画像のようにオブジェクトを配置しました。
![スクリーンショット 2022-07-12 11.27.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/e0c7bf20-219e-e992-3dcc-ffbc91b45678.png)

プレイヤーはJoyStickで動くように事前に実装しました。
→やり方は[こちら](https://qiita.com/1230/items/ac91173b704d05aa9f8e)

エネミー本体とプレイヤーに`Collider（種類はなんでも）`と`Rigidbody`をComponentとして付け加えておいてください！

# 追跡・徘徊機能の構成
今回は「一定距離に近づいたら」という処理を、当たり判定を使用してセンサーのように動かしていきたいと思います。
当たり判定が起動した場合に対象物を追跡し、起動していない場合はフィールドを自由徘徊する仕様にします。

## 追跡
センサー内にPlayerがいる場合、その範囲内でEnemyの方向をプレイヤーに向けさせ、そっちに進む感じです！

⏬イメージ図
![スクリーンショット 2022-07-12 19.44.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/4441e65a-8d56-388e-6486-465dab094a6f.png)

## 徘徊
逆にセンサー外にPlayerがいる時は、向かう目的地を一定時間おきにランダムでフィールド上に生成することによって自由徘徊をしているように見える実装をします。

⏬イメージ図
![スクリーンショット 2022-07-12 17.11.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/0d98fa62-12fd-cfdf-2fff-1b874d206de4.png)

# エネミーの設定
## センサーの設置
①Hierarchyビューから`Create`→`Create Empty`で作成
![スクリーンショット 2022-07-12 16.53.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/7631e8b3-bcb8-7923-c9f7-56f37b2a9d98.png)

②Emptyオブジェクトの名前を`sensor`などに変更し、Enemyの子オブジェクトにする。InspectorビューのAdd Componentから`Box Collider`を選択する。
![スクリーンショット 2022-07-12 16.54.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/2dfa7068-cfc1-b632-ab83-f6aa4e7e2a2c.png)

③Box Colliderの`Edit Collider`のボタンをクリックして、Sceneビューの方でちょうど良い形にColliderの大きさを変更する。
![スクリーンショット 2022-07-12 20.03.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/f86faedc-81c5-abe0-8cb2-6c3b9fca1113.png)

画像だとわかりづらいのですが、私はこんな感じの大きさにしました！薄ーい緑の線がColliderの大きさです。
![スクリーンショット 2022-07-12 16.56.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/f6f42edf-c2a7-6293-5b25-1057e1fc7439.png)

④Box Colliderの`is Trigger`にチェックを入れる。
![スクリーンショット 2022-07-13 18.28.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/4cecdf63-b748-e16a-829a-0868735faec4.png)


## NavMeshの設定
①Enemy本体にInspectorビューのAdd　Componentから`Nav Mesh Agent`を加える。
![スクリーンショット 2022-07-12 20.12.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/8dd4d7b5-f94b-755c-564c-b870d8a0c283.png)

②地面に当たるGameObjectのStaticを`Navigation Static`にする
![スクリーンショット 2022-07-13 17.59.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/b1cfc2e7-847a-31c7-fe35-46158eb94ab9.png)

（なければWindow→AI→Navigationを選択し、ウィンドウを表示する）
![スクリーンショット 2022-07-13 18.02.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/e1d89955-8b5e-71a6-3318-dc9ebd5baaf8.png)


③NavigationウィンドウのBakeタブの底のBakeボタンをクリックする。
![スクリーンショット 2022-07-13 18.05.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/9ca69dbe-0802-af0b-2a59-deb7fee31850.png)
（右下のBake NavMeshが消えたら完了！少し時間がかかるかも,,,）

Bakeが終わったら青い移動できる範囲が示されます！
![スクリーンショット 2022-07-13 18.20.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/96df2851-eb85-2cca-dcf3-43a661a66cf5.png)


# エネミーのスクリプトの作成
Projectビューから`Create`→`C# Script`で`EnemyScript`と`sensorScript`の二つを作成する。

## エネミー本体のスクリプト
`EnemyScript`に以下全文コピペ！
```cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.SceneManagement;

public class EnemyScript : MonoBehaviour
{
    public Transform Target;
    public Transform random;
    NavMeshAgent agent;
    bool sensor;
    public float speed;

    // Start is called before the first frame update
    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
    }

    // Update is called once per frame
    void Update()
    {
        if(sensor == false)
        {
            agent.destination = random.transform.position;
        }
        else
        {
            agent.destination = Target.transform.position;
        }
    }

    public void tuiseki()
    {
        sensor = true;
    }

    public void haikai()
    {
        sensor = false;
    }

    private void OnCollisionEnter(Collision col)
    {
        if (col.gameObject.tag == "Player" )
        {
            SceneManager.LoadScene("GameOver");
        }
    }
}
```

## センサー用のスクリプト
`sensorScript`に以下全文コピペ！
```cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class sensorScript : MonoBehaviour
{
    public GameObject enemy;
    EnemyScript encs;

    // Start is called before the first frame update
    void Start()
    {
        encs = enemy.GetComponent<EnemyScript>();
    }

    void OnTriggerStay(Collider other)
    {
        if (other.gameObject.tag == "Player")
        {
            encs.tuiseki();
        }
    }

    void OnTriggerExit(Collider other)
    {
        if (other.gameObject.tag == "Player")
        {
            encs.haikai();
        }
    }
}
```
①それぞれにスクリプトをアタッチする
![スクリーンショット 2022-07-13 18.10.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/f2667dac-5298-c9be-ab24-79a4d4773e4e.png)

②Enemyに必要なオブジェクトをアタッチして、Speedを好きな数字を入れる。
![スクリーンショット 2022-07-13 18.23.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/88daa479-d596-7669-6a51-df968c70224e.png)

③sensorにEnemyをアタッチする。
![スクリーンショット 2022-07-13 18.24.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/5240ece8-da1f-8687-877c-5d1cb101c06f.png)


# 徘徊用の目的地をランダムに生成する
①ランダムオブジェクトをHierarchyビューから`Create`→`Create Empty`で作成し、名前を`random`とかにする。
![スクリーンショット 2022-07-13 12.32.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/b4b84848-5da9-0fec-99c8-a5f4fabb1051.png)

②Projectビューから、ランダムオブジェクト用のスクリプトを作成する。
今回はコルーチンという機能を使って、ワープ処理を繰り返し行うように実装しました。

`⏬スクリプト全文`
```cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class randomScript : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(Warp());
    }

    private IEnumerator Warp()
    {
        while (true)
        {
            // 10秒後ごとにワープ移動する。
            yield return new WaitForSeconds(10f);

            // ランダムな値を取得する。
            float posX = Random.Range(- 120, 120);
            float posZ = Random.Range(-200, 200);

            transform.position = new Vector3(posX, 0, posZ);
        }
    }
}
```
③スクリプトをHierarchtビューのRandomにアタッチする
![スクリーンショット 2022-07-13 17.42.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/0a943696-a3a4-75ec-2fcc-145ece35a29e.png)

# 最後の仕上げ！
①Playerに`Player`タグを追加する
![スクリーンショット 2022-07-14 12.27.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/2a143530-577a-6d4f-7cd9-d8add5408bef.png)

②Projectビューから`Create`→`Scene`でGameOverのシーンを作成

③`File`→`Build Settings`を開き、`Scenes in Build`に遷移で使うシーンを入れる。
![スクリーンショット 2022-07-14 11.24.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890419/7b167e64-1fc1-f2d0-4e6c-7819620c0c46.png)

# 以上！