【Unity】ナビメッシュエージェントをランダムな方向に移動させる

投稿者: | 2023-08-20

ナビメッシュエージェントを360度ランダムな方向に移動させてみます。

ゲームオブジェクトを追加

シーンにカプセルと、地面や障害物を配置してナビメッシュをベイクしました。

カプセルにナビメッシュエージェントコンポーネントとスクリプトを追加します。

スクリプト

using UnityEngine;
using UnityEngine.AI;

public class NavMeshRandomWalker : MonoBehaviour
{
    // 目的地を設定する間隔
    [SerializeField] float interval = 0.5f;

    // レイの長さ
    [SerializeField] float maxMoveDistance = 10f;

    // 経過時間
    float elapsedTime = 0f;

    // 歩く方向
    Vector3 walkDirection;

    NavMeshAgent agent;

    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        ResetWalkParameters();
    }

    void Update()
    {
        UpdateAgentMovement();
    }

    void ResetWalkParameters()
    {
        // パラメータを初期化
        elapsedTime = 0f;

        // ランダムの方向を作成
        var x = (Random.value * 2f) - 1f;
        var z = (Random.value * 2f) - 1f;

        walkDirection = new Vector3(x, 0f, z).normalized;
    }


    void UpdateAgentMovement()
    {
        elapsedTime += Time.deltaTime;

        // 一定期間ごとに目的地を設定して値を初期化
        if (elapsedTime >= interval)
        {
            MoveTowardsTarget();
            ResetWalkParameters();
        }
    }


    void MoveTowardsTarget()
    {
        // レイの始点
        var sourcePos = transform.position;
        //sourcePos.y -= 1f;

        // レイの終点
        var targetPos = sourcePos + walkDirection * maxMoveDistance;

        // レイを投げる
        var blocked = NavMesh.Raycast(sourcePos, targetPos, out NavMeshHit hitInfo, NavMesh.AllAreas);

        if (blocked)
        {
            // ヒット地点を目的地にする
            agent.SetDestination(hitInfo.position);
        }
        else
        {
            // ターゲット位置を目的地にする。
            agent.SetDestination(targetPos);
        }

        // ラインを描画
        Debug.DrawLine(sourcePos, targetPos, blocked ? Color.red : Color.green, interval);
    }
}

一定時間ごとにランダムな方向にレイを飛ばして目的地を設定することで移動します。レイを飛ばす間隔とレイの長さをインスペクタで設定できます。

using UnityEngine;
using UnityEngine.AI;

public class NavMeshRandomWalker : MonoBehaviour
{
    // 目的地を設定する間隔
    [SerializeField] float interval = 0.5f;

    // レイの長さ
    [SerializeField] float maxMoveDistance = 10f;

    // 経過時間
    float elapsedTime = 0f;

    // 歩く方向
    Vector3 walkDirection;

    NavMeshAgent agent;

スタートで値をリセットして、毎フレーム秒読みします。

    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        ResetWalkParameters();
    }

    void Update()
    {
        UpdateAgentMovement();
    }

リセットでは、経過時間を0にし、ランダムに方向ベクトルを作って正規化しています。

    void ResetWalkParameters()
    {
        // パラメータを初期化
        elapsedTime = 0f;

        // ランダムの方向を作成
        var x = (Random.value * 2f) - 1f;
        var z = (Random.value * 2f) - 1f;

        walkDirection = new Vector3(x, 0f, z).normalized;
    }

経過時間が間隔を超えたら目的地を設定して、値をリセットします。

    void UpdateAgentMovement()
    {
        elapsedTime += Time.deltaTime;

        // 一定期間ごとに目的地を設定して値を初期化
        if (elapsedTime >= interval)
        {
            MoveTowardsTarget();
            ResetWalkParameters();
        }
    }

NavMesh.Raycastメソッドで、カプセルからランダムな方向へレイを投げます。ナビメッシュの境界にがあればその地点を、なければレイの終点を目的地にします。

    void MoveTowardsTarget()
    {
        // レイの始点
        var sourcePos = transform.position;
        //sourcePos.y -= 1f;

        // レイの終点
        var targetPos = sourcePos + walkDirection * maxMoveDistance;

        // レイを投げる
        var blocked = NavMesh.Raycast(sourcePos, targetPos, out NavMeshHit hitInfo, NavMesh.AllAreas);

        if (blocked)
        {
            // ヒット地点を目的地にする
            agent.SetDestination(hitInfo.position);
        }
        else
        {
            // ターゲット位置を目的地にする。
            agent.SetDestination(targetPos);
        }

        // ラインを描画
        Debug.DrawLine(sourcePos, targetPos, blocked ? Color.red : Color.green, interval);
    }
}

最後にDebug.DrawLineでシーンビューにレイを表示します。第4引数に表示する時間を秒単位で指定できます。

実行する

レイがナビメッシュの境界に当たるとNavMesh.Raycastがtrueを返します。

パラメータで動き方が変わります。

コメントを残す

メールアドレスが公開されることはありません。