ものづくりのブログ

うちのネコを題材にしたものづくりができたらいいなと思っていろいろ奮闘してます。

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

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

NavMesh Agent は「キャラクターを自動的に移動させられる機能」です。
これを使えば自動で動くキャラクターが作ることができます。

プレイ動画

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

事前作業

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

設定メモ

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

「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

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

NPCの設定

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);
    }
}