NavMeshを使った巡回するNPCのつくりかた

こんにちは、ZeniZeniです。
毎度ゲームを作ってると、巡回するNPCとか、一定範囲をウロチョロする敵とかを作りたいなーと思うときがあります。
そんな気持ちで巡回するNPCのつくり方を調べたりすると、基本的なやり方はわかっても、じゃあどう実装するのが楽で汎用的なのかがいまいちわからなかったので、自分で考えてみました。

個人的にNavMechを使った実装が最適解だと思うので、NavMeshを使っていきます。
NavMeshの基本的な使い方は[こちら](http://nn-hokuson.hatenablog.com/entry/2016/08/05/235156)のおもちゃラボさんのサイトがとても分かりやすかったです。

#作製するコード
```C#:DestinationController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DestinationController : MonoBehaviour
{
    //初期位置
    private Vector3 startPosition;
    //目的地
    [SerializeField] private Vector3 destination;

    [SerializeField] private Transform[] targets;

    [SerializeField] private int order = 0;

    public enum Route {inOrder, random}
    public Route route;


    void Start()
    {
        //　初期位置を設定
        startPosition = transform.position;
        SetDestination(transform.position);
    }

    public void CreateDestination()
    {
        if(route == Route.inOrder)
        {
            CreateInOrderDestination();
        }else if(route == Route.random)
        {
            CreateRandomDestination();
        }
    }

    //targetsに設定した順番に作成
    private void CreateInOrderDestination()
    {
        if(order < targets.Length-1)
        {
            order++;
            SetDestination(new Vector3(targets[order].transform.position.x, 0, targets[order].transform.position.z));
        }
        else
        {
            order = 0;
            SetDestination(new Vector3(targets[order].transform.position.x, 0, targets[order].transform.position.z));
        }
    }

    //　targetsからランダムに作成
    private void CreateRandomDestination()
    {
        int num = Random.Range(0, targets.Length);
        SetDestination(new Vector3(targets[num].transform.position.x, 0, targets[num].transform.position.z));
    }

    //　目的地の設定
    public void SetDestination(Vector3 position)
    {
        destination = position;
    }

    //　目的地の取得
    public Vector3 GetDestination()
    {
        return destination;
    }
}
```

```C#:NpcMovement
using UnityEngine;
using UnityEngine.AI;

[RequireComponent(typeof(NavMeshAgent))]
[RequireComponent(typeof(DestinationController))]
public class NpcMovement : MonoBehaviour
{

    private NavMeshAgent navAgent = null;
    [SerializeField] private DestinationController destinationController;


    void Start()
    {
        navAgent = GetComponent<NavMeshAgent>();
        destinationController = GetComponent<DestinationController>();
        navAgent.SetDestination(destinationController.GetDestination());
    }

    void Update()
    {
        if(Vector3.Distance(transform.position, destinationController.GetDestination()) < 1.5f)
        {
            destinationController.CreateDestination();
            navAgent.SetDestination(destinationController.GetDestination());
        }
    }

}
```

#使い方
巡回させたいフィールドのNavMeshの設定をします。
そして、巡回させたい3DモデルにNpcMovement.csをアタッチします。すると自動でDestinationControllerとNavMeshAgentもアタッチされます。
![bandicam 2019-05-24 23-31-07-466.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281560/c6525a46-df98-37d4-a4d1-746262f4b010.jpeg)
巡回させたい地点に何かしらGameObjectを設置して、それをDestinationControllerのTargetsに入れます。
それらの巡回地点をElement0から順番に巡回させたい場合はRouteをInOrderに、ランダムに巡回させたい場合はRandomにしてください。

後はNavMeshAgentで移動速度とかを調整すれば完了です。

#開発、執筆にあたり、下記のサイト様を参考、引用させていただきました。
[【Unity】NavMeshで経路に沿って動かす - おもちゃラボ](http://nn-hokuson.hatenablog.com/entry/2016/08/05/235156)