3D 動的ロードブロッキングの生成

導入

前回の記事では Mathf.Lerp の基本的な実装原理を紹介しましたが、ここではパルクール ゲームで動的ロードブロッキング生成を実装する方法を紹介します。
動的ロードブロッキングは実際には生成するのが簡単ですが、何が難しいのでしょうか? それらがすべて平坦であるか、曲がり角がない場合、実装は簡単です。動的ロードブロッキングの実装で上り坂、下り坂、または曲がり角に遭遇した場合、これらにどのように対処しますか? ?コーナーポイントや上り坂、下り坂の回転や位置はどうなりますか?

設計の実装

設計上の考え方を簡単に説明しますと、
道路の終点が座標の原点 (0,0,0) で、道路は Z 軸の方向を向いています。 Z 軸の深さを使用するだけで済みます。
終点と始点の間に複数の空のオブジェクトを作成します。この空のオブジェクトは、作成された障害物がどの 2 つの空のオブジェクトの間にあるかを決定するために使用されます。その後、Lerp を使用して補間演算を実行し、コーナーや斜面に障害物を生成できるようにしますバリケードの正しい回転と位置。
道路障害物を生成するとき、障害物はカスタム パラメーターの距離範囲内でランダムに生成され、その回転角度と高さは、前述の 2 つの空のオブジェクトの差を使用して計算できます。

1. 舗装の作成

以下は、Plane を使用して単純に接続した路面です。道路の終了位置は Unity の (0, 0, 0) です。
ここで、全長は 300 です。つまり、写真の開始位置は ( x、x、-300)。
ここに画像の説明を挿入します

2. 空のオブジェクトの作成

道路にウェイポイントの空のオブジェクトを作成し、後で作成するすべての空のオブジェクトをその中に配置します。
道路全体に無数の空のオブジェクトを作成できますが、空のオブジェクトの Z 軸の回転と Y 軸の高さは後でこの空のオブジェクトの位置と回転を使用して補間操作を実行し、障害物の位置と回転角度を取得するため、路面は一貫したままになります。ここでより多くの空のオブジェクトを作成するほど、傾斜と角度がより正確になります。ロードブロッキングは路面に合わせて回転します。最後に、Waypoints スクリプトを作成し、それをウェイポイントにマウントして、作成した空のオブジェクトをすべて取得します。便宜上、OnDrawGizmos() を使用してそれらを描画できます。

作成した位置は以下の通りで、
ここに画像の説明を挿入します
各点のZ軸回転角度を路面にフィットさせていることがわかります。

スクリプトは次のとおりです。

[ExecuteInEditMode]
	public class waypoints : MonoBehaviour {
    
    

    	public Transform[] points;
    	void OnDrawGizmos()
    	{
    
    
        	for (int i = 0; i < points.Length; i++)
        	{
    
    
            	Gizmos.color = Color.red;
            	Gizmos.DrawWireSphere(points[i].transform.position, 5);
        	}
    	}
	}

3.Create.csスクリプト作成

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

	public class Create : MonoBehaviour {
    
    

    /// <summary>
    /// 路障物体数组
    /// </summary>
    public GameObject[] obstacles;

    /// <summary>
    /// 路障在道路上出现的开始位置
    /// </summary>
    public float startLength = 10;

    /// <summary>
    /// 路障距上一个路障的最小距离  
    /// </summary>
    public float minLength = 10;

    /// <summary>
    /// 路障距上一个路障的最大距离  
    /// </summary>
    public float maxLength = 20;

    /// <summary>
    /// 与路面相贴合的路线上的脚本组件  
    /// </summary>
    private waypoints wayPoints;

    void Awake()
    {
    
    
        wayPoints = GameObject.Find("waypoints").GetComponent<waypoints>(); 
    }

    // Use this for initialization  
    void Start()
    {
    
    
        //创建路障
        GenerateObstacle(); 
    }

    /// <summary>
    /// 创建路障
    /// </summary>
    void GenerateObstacle()
    {
    
    
        //当前道路在场景中的起始Z坐标  
        float startZ = transform.position.z - 300;

        //当前道路在场景中的结束Z坐标  
        float endZ = transform.position.z;
        
        //将要产生路障的Z坐标
        float z = startZ + startLength;
        
        while (true)
        {
    
    
            //每隔多少米的距离产生一个路障  
            z += Random.Range(minLength, maxLength);

            //如果将要产生路障的位置超出了这条道路则退出路障产生循环,否则产生路障 
            if (z > endZ)                            
            {
    
    
                break;
            }
            else
            {
    
    
                //方法计算路障位置坐标
                Vector3 position = GetWayPos(z);
                //方法计算路障旋转坐标
                Vector3 rotation = GetWayRotate(z);
                //产生一个从路障数组里取路障的随机序数  
                int obsIndex = Random.Range(0, obstacles.Length);
                //实例化路障 
                Instantiate(obstacles[obsIndex], position, Quaternion.Euler(rotation.x, rotation.y, rotation.z)); 
            }
        }
    }

    /// <summary>
    /// 获取转折点的集合索引值
    /// </summary>
    /// <param name="z"></param>
    /// <returns></returns>
    int GetPointIndex(float z)
    {
    
    
        //在道路上设置的转折点的集合  
        Transform[] points = wayPoints.points;
        //转折点在集合中的序数号  
        int index = 0;

        for (int i = 0; i < points.Length - 1; i++)
        {
    
    
            //根据要插入路障的Z值在集合中寻找在哪两个点之间,找到后记下序数号  
            if (z >= points[i].position.z && z <= points[i + 1].position.z)
            {
    
    
                index = i;
                break;
            }
        }
        return index;
    }

    Vector3 GetWayPos(float z)
    {
    
    
        int index = GetPointIndex(z);
        //使用Lerp函数计算出插入路障处的空间坐标值  
        return Vector3.Lerp(wayPoints.points[index + 1].position, wayPoints.points[index].position, (z - wayPoints.points[index + 1].position.z) / (wayPoints.points[index].position.z - wayPoints.points[index + 1].position.z));
    }

    Vector3 GetWayRotate(float z)
    {
    
    
        int index = GetPointIndex(z);
        return Vector3.Lerp(wayPoints.points[index + 1].eulerAngles, wayPoints.points[index].eulerAngles, (z - wayPoints.points[index + 1].position.z) / (wayPoints.points[index].position.z - wayPoints.points[index + 1].position.z));
    }
    }

作成完了結果は以下の通りです。
ここに画像の説明を挿入します

要約する

この記事では Mathf.Lerp() の使い方を中心に説明しますので、分からないことがあれば前回の記事を読んでください。

おすすめ

転載: blog.csdn.net/qq_42194657/article/details/135438295