LoginSignup
2
1

More than 3 years have passed since last update.

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

Posted at

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

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

問題

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

Speed=3のときは問題なく曲がれる。
speed3.gif

Speed=5 のときは行き過ぎてしまい上手く曲がれない。
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はパスの中継地点のうち、現在向かっている地点となります。

steeringTarget.png

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

結果がこちら
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 に変更しています。

その結果がこちら
slowSpeed.gif

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

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1