3D dynamic roadblock generation

introduce

The previous article introduced the underlying implementation principle of Mathf.Lerp. Here we will introduce how to implement dynamic roadblock generation in parkour games.
Dynamic roadblocks are actually easier to generate, but what is the difficulty? If they are all flat or have no turns, it is easier to implement. If the implementation of dynamic roadblocks encounters uphill, downhill or turning places, how do we deal with these? What about the rotation and position of corner points and uphill and downhill slopes?

Design implementation

Let’s briefly talk about the design idea.
The end point of the road is the origin of the coordinates (0,0,0), and our road faces the direction of the Z axis. That is to say, when we generate roadblocks, we only need to use the depth of the Z axis.
We create multiple empty objects between the end point and the starting point. This empty object is used to determine which two empty objects the created roadblock is between. Then we use Lerp to perform interpolation operations so that we can generate the roadblocks at corners and slopes. Correct rotation and position of barricades.
When generating a roadblock, the roadblock is randomly generated within the custom parameter distance range, and its rotation angle and height can be calculated using the difference between the two empty objects mentioned above.

1. Pavement creation

The following is a road surface that I simply spliced ​​using Plane. The end position of the road is Unity's (0, 0, 0).
Here, my full length is 300, which means that the starting position in the picture is (x, x, -300).
Insert image description here

2. Creation of empty objects

Create an empty object of waypoints in the Road, and put all the empty objects we create later in it.
We can create countless empty objects on the entire road, but the Z-axis rotation and Y-axis height of the empty object must be followed. The road surface remains consistent, because we will later use the position and rotation of this empty object to perform interpolation operations to obtain the position and rotation angle of the roadblock. The more empty objects are created here, the more accurate the slope and rotation of the roadblock will be to fit the road surface. Finally, create a Waypoints script and mount it on waypoints to obtain all the empty objects we created. We can use OnDrawGizmos() to draw them for our convenience.

The created position is as follows.
Insert image description here
Here you can see that I fit the Z-axis rotation angle of each point to the road surface.

The script is as follows:

[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 script creation

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));
    }
    }

The creation completion result is as follows:
Insert image description here

Summarize

This article mainly explains the usage of Mathf.Lerp(). If you don’t understand anything, you can read my previous article.

Guess you like

Origin blog.csdn.net/qq_42194657/article/details/135438295