【Unityで2DRPG】NPCをNavMeshAgentで動かしてみる (猫の冒険)

NPC同士の重なり合いや、通り抜けできない部分をNPCがすり抜けちゃう問題を解消するために「NavMesh Agent」というものを使ってNPCの移動部分を作成してみました。

プレイ動画

動作検証してた時のプレイ動画です。
www.youtube.com

NavMeshをベイク

以下のシーンのTilemapに通れる場所と通れない場所を設定します。
f:id:a1026302:20201121003109j:plain
設定後にNavMeshをベイクすると移動可能部分が青色になります。
(通れない場所の設定が荒い。。。)
f:id:a1026302:20201121003116j:plain

設定メモ

NavMeshPlus

今回は「NavMeshPlus」というものを利用してNavMeshAgentの設定を行いました。
github.com
とりあえずマスターブランチのものを持ってきてマニュアルらしきものを読みます。
f:id:a1026302:20201121005500j:plain

NavMeshModifierの設定

「Tilemap」を設定しているところに、「NavMeshModifier」というものを追加して、通れる場所と通れない場所を教えてあげます。

通れる場所

以下が通れる場所の「Tilemap」です。
f:id:a1026302:20201121010644j:plain
「NavMeshModifier」を追加後に「Walkable」を選択します。
f:id:a1026302:20201121011240j:plain

通れる場所

以下が通れない場所の「Tilemap」です。
f:id:a1026302:20201121010858j:plain
「NavMeshModifier」を追加後に「Not Walkable」を選択します。
f:id:a1026302:20201121011728j:plain

NavMeshSurface2dの設定

適当なGameObjectを作成後「NavMeshSurface2d」を追加します。
「Bake」ボタンをクリックすると、移動可能部分が青色になります。
(ならないときは、「Rotate Surface to XY」ボタンを押してみるといいかもです)
f:id:a1026302:20201121012021j:plain

NPCの設定

Nav Mesh Agentの設定

NPCに「Nav Mesh Agent」の設定を追加します。
f:id:a1026302:20201121012549j:plain

ごっこ用のスクリプト作成

ごっこ用のスクリプトを作成します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class Chase2 : MonoBehaviour
{
    public GameObject target;
    private NavMeshAgent agent;
    public Animator animator;
    GameObject playerObj;
    public float distance;
    float time;

    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        agent.updateRotation = false;
        agent.updateUpAxis = false;
    }
    void FixedUpdate()
    {
        playerObj = GameObject.Find("Player(Clone)");
        float now = Vector2.Distance(transform.position, playerObj.transform.position);
        if (distance < now)
        {
            agent.destination = playerObj.transform.position;
            Vector2? vector = new Vector2( 
                agent.destination.x - transform.position.x, 
                agent.destination.y - transform.position.y 
            );
            setStateToAnimator(vector: vector != Vector2.zero ? vector : (Vector2?)null);
        }
    }
    private void setStateToAnimator(Vector2? vector)
    {
        if (!vector.HasValue)
        {
            this.animator.speed = 0.0f;
            return;
        }
        this.animator.speed = 1.0f;
        this.animator.SetFloat("x", vector.Value.x);
        this.animator.SetFloat("y", vector.Value.y);
    }
}