Quantcast
Viewing all articles
Browse latest Browse all 8895

急カーブにも強いNavMeshAgentを作る

NavMeshAgentは簡単にオブジェクトを自動で移動させることができる便利な機能ですが、使っていてある問題が発生したので、その解決策を載せます。

githubに全ソースコードを載せています。
https://github.com/AtshshiMori/NavMeshMovement

問題

以下のようにスピードがある程度遅ければ良いが、早くすると急に曲がるときに通り過ぎてしまう。

Speed=3のときは問題なく曲がれる。
Image may be NSFW.
Clik here to view.
speed3.gif

Speed=5 のときは行き過ぎてしまい上手く曲がれない。
Image may be NSFW.
Clik here to view.
speed5.gif

ソースコード

サンプルシーンのソースコードです。
Unityちゃんに以下のスクリプトを追加します。
targetにはインスペクターからUnityちゃんが向かう先であるカプセル型のオブジェクトを指定しておきます。

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

public class Player : MonoBehaviour
{
    [SerializeField] GameObject target; // ゴールとなるターゲットオブジェクト
    UnityEngine.AI.NavMeshAgent agent;
    Animator animator;

    void Start()
    {
        agent = GetComponent<UnityEngine.AI.NavMeshAgent>();
        animator = GetComponentInChildren<Animator>();
    }

    void Update()
    {
        agent.destination = target.transform.position; // ターゲットの設定
        animator.SetFloat("Speed", agent.velocity.sqrMagnitude); // Unityちゃんをアニメーションさせるためのパラメータ
    }
}

解決策1 等速で動かす

とりあえず等速で動くようにすることで解決ができます。
Update関数内に以下を追加します。

agent.velocity = (agent.steeringTarget - transform.position).normalized * agent.speed;
transform.forward = agent.steeringTarget - transform.position;

agent.velocityでNavMeshAgentのスピードを指定できます。

NavMeshAgentは常にゴールまでのパスを保持しており、
agent.steeringTargetはパスの中継地点のうち、現在向かっている地点となります。

Image may be NSFW.
Clik here to view.
steeringTarget.png

したがって、
(agent.steeringTarget - transform.position)
により方向を取得し、agent.speedをかけることで常にインスペクターでNavMeshAgentに設定したスピードで動くことになります。

結果がこちら
Image may be NSFW.
Clik here to view.
fixedSpeed.gif

上手く曲がれるようになりましたが、動きに滑らかさはなくなってしまいます。表現したいものによっては使えると思います。

解決策2 曲がり角でスピードを落とす

曲がり角が近くなったらスピードを落とすようにします。
以下のようにスクリプトに追加します。

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

public class Player : MonoBehaviour
{
    [SerializeField] GameObject target; // ゴールとなるターゲットオブジェクト

    UnityEngine.AI.NavMeshAgent agent;
    Animator animator;

    private float speed = 0.0f; // 追加:NavMeshAgentのspeedを保持するための変数

    void Start()
    {
        agent = GetComponent<UnityEngine.AI.NavMeshAgent>();
        animator = GetComponentInChildren<Animator>();
        speed = agent.speed;            // 追加:初期値の保持
    }

    void Update()
    {
        agent.destination = target.transform.position; // ターゲットの設定
        animator.SetFloat("Speed", agent.velocity.sqrMagnitude); // Unityちゃんをアニメーションさせるためのパラメータ

        // 以下を追加
        if (Vector3.Distance(agent.steeringTarget, transform.position) < 1.0f)
        {
            agent.speed = 1.0f;
        }
        else
        {
            agent.speed = speed;
        }
    }
}

先ほどの steeringTarget で曲がり角の位置を取得し、距離が近くなったときに speed を 1.0f に変更しています。

その結果がこちら
Image may be NSFW.
Clik here to view.
slowSpeed.gif

スムーズに曲がれるようになりました。


Viewing all articles
Browse latest Browse all 8895

Trending Articles