【Unity】ナビメッシュの目的地を道に沿ってランダムに決定する #2

投稿者: | 2020-06-20

前の記事の方法でナビメッシュエージェントに目的地を設定します。

今回は、バウンドさせるようにナビメッシュを一度に2回ずつ飛ばして、衝突した2つの点の中間の点を目的地にしました。

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

public class NavMeshAgentTest : MonoBehaviour
{
    [SerializeField] GameObject sphere;
    [SerializeField] Material[] materials;

    MeshRenderer meshRenderer;
    Vector3 sourcePos1;
    Vector3 sourcePos2;
    Vector3 targetDir;

    [SerializeField] bool sphere1 = false;
    [SerializeField] bool sphere2 = false;
    [SerializeField] bool sphere3 = false;
    NavMeshAgent agent;

    // Start is called before the first frame update
    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        targetDir = Vector3.Slerp(transform.forward, transform.right, Random.Range(0f, 1f)); 
        sourcePos1 = transform.position;
        sourcePos1.y -= 3f;
        agent.destination = sourcePos1;
    }

    // Update is called once per frame
    void Update()
    {
        if (!agent.pathPending && agent.remainingDistance < 5f)
        {
            NavMeshHit hit;
            GameObject s;         

            // レイキャスト1
            if (NavMesh.Raycast(sourcePos1, targetDir * 50f + sourcePos1, out hit, NavMesh.AllAreas))
            {
                Debug.Log(hit.normal);

                sourcePos1 = hit.position; // 衝突した場所を次の始点にする

                if (sphere1)
                {
                    s = Instantiate(sphere, sourcePos1, sphere.transform.rotation); // 球を作る
                    meshRenderer = s.GetComponent();
                    meshRenderer.material = materials[0]; // 色を変える
                }

                Vector3 tan = Vector3.Cross(hit.normal, Vector3.up); // 接線

                // 接線がレイの来た方を向いていたら
                //if (Vector3.Dot(transform.forward, tan) < 0)
                if (Vector3.Dot(targetDir, tan) < 0)
                {
                    tan *= -1; // 接線の向きを逆にする
                }

                // 次のレイを法線と接線の間の方向にする
                targetDir = Vector3.Slerp(hit.normal, tan, Random.Range(0f, 1f));      

            }
            // どこにもぶつからなければその場所を次の始点にする
            else
            {

                sourcePos1 = targetDir * 50f + sourcePos1;

                // 球を置く
                if (sphere1)
                {
                    s = Instantiate(sphere, sourcePos1, sphere.transform.rotation);
                    meshRenderer = s.GetComponent();
                    meshRenderer.material = materials[0];
                }
            }


            // レイキャスト2
            if (NavMesh.Raycast(sourcePos1, targetDir * 50f + sourcePos1, out hit, NavMesh.AllAreas))
            {
                Debug.Log(hit.normal);

                sourcePos2 = hit.position; // 衝突した場所を次の始点にする

                if (sphere2)
                {
                    s = Instantiate(sphere, sourcePos2, sphere.transform.rotation); // 球を作る
                    meshRenderer = s.GetComponent();
                    meshRenderer.material = materials[1]; // 色を変える
                }

                Vector3 tan = Vector3.Cross(hit.normal, Vector3.up); // 接線

                // 接線がレイの来た方を向いていたら
                //if (Vector3.Dot(transform.forward, tan) < 0)
                if (Vector3.Dot(targetDir, tan) < 0)
                {
                    tan *= -1; // 接線の向きを逆にする
                }

                // 次のレイを法線と接線の間の方向にする
                targetDir = Vector3.Slerp(hit.normal, tan, Random.Range(0f, 1f)); // t       

            }
            // どこにもぶつからなければその場所を次の始点にする
            else
            {

                sourcePos2 = targetDir * 50f + sourcePos1;

                // 球を置く
                if (sphere2)
                {
                    s = Instantiate(sphere, sourcePos2, sphere.transform.rotation);
                    meshRenderer = s.GetComponent();
                    meshRenderer.material = materials[1];
                }
            }


            // 2つの目的地の中間の点
            Vector3 dest = (sourcePos1 + sourcePos2) / 2;
            agent.destination = dest;

            // 球を置く
            if (sphere3)
            {
                s = Instantiate(sphere, dest, sphere.transform.rotation);
                meshRenderer = s.GetComponent();
                meshRenderer.material = materials[2];
            }

            sourcePos1 = sourcePos2;


        }

    }
}

前半は前と同じ方法でナビメッシュの境界へレイを飛ばす処理を2回繰り返しています。最後にそれらの結果によって目的地を設定します。

たまに行ったり来たりしますが、たいていは自然にランダムに移動させられます。

2つの点の中間の点ではなく、ナビメッシュレイキャストが衝突した点をそのまま目的地にすると経路がより険しくなって、エージェントが何度も折り返します。

コメントを残す

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