Unity開發中導彈路徑散射的原理與實現
- 前言
- 邏輯原理
- 代碼實現
- 導彈自身腳本
- 外部控制腳本
- 應用效果
- 結語
前言
前面我們學習了導彈的追蹤的效果,但是在動畫或游戲中,我們經常可以看到導彈發射后的彈道是不規則的,扭扭曲曲的飛行,然后擊中目標。
這期我們就講一下不規則路徑飛行的邏輯,在游戲中是如何實現的。
邏輯原理
首先迎面走來的是初級的散射效果原理圖,在發射點和目標點之間有一個散射經過點,重點來了:**利用三維空間中球形公式,給定球心,隨機返回球面上一點。**然后讓導彈經過隨機點再擊打目標,就會形成隨機散射的效果。
多點也是一樣的道理,把路徑點經過換算之后再賦值導彈路徑點,然后形成不規則散射的效果。
這里可以發現,導彈的路徑是折線效果,按標準應該是曲線效果。兩者的區別就在于導彈在兩點之間的過渡函數,折線是平滑過渡,曲線是貝塞爾曲線過渡,選的過渡函數不同實現的效果也不一樣。由于貝塞爾曲線過渡較為復雜,這里就用平滑過渡演示原理
代碼實現
導彈自身腳本
這里將散射的范圍用變量表示,實現可控的效果,想大范圍就大范圍、想小范圍就小范圍。將腳本掛載到導彈的預制體上之后給相應的變量賦值,例如:散射半徑、爆炸特效、子彈移動速度,其他變量通過外部腳本賦值。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SpherePoint : MonoBehaviour
{[Header("散射半徑")]public float radius;public GameObject FX;//爆炸特效public Transform endPoint; // 目標點 public List<Transform> wayPoints; // 中間點列表 public float speed = 10f; // 子彈移動速度 public int currentWaypointIndex = 0; // 當前處理的中間點索引 public Vector3 currentTargetPosition; // 當前目標位置 // Start is called before the first frame updatevoid Start(){if (wayPoints.Count > 0){currentTargetPosition = GetRandomPointOnSphere(wayPoints[0].position, radius);}else{currentTargetPosition = endPoint.position;}}// Update is called once per framevoid Update(){BulletMovement(transform);}/// <summary>/// 隨機獲取中間點周圍的散射經過點/// </summary>/// <param name="center">中間點坐標</param>/// <param name="r">散射半徑</param>/// <returns></returns>public static Vector3 GetRandomPointOnSphere(Vector3 center, float r){// 生成隨機的經度和緯度 float u = UnityEngine.Random.value * 2 * Mathf.PI; // 經度 [0, 2*PI] float v = UnityEngine.Random.value * Mathf.PI; // 緯度 [0, PI] // 將球坐標轉換為笛卡爾坐標 float x = center.x + r * Mathf.Sin(v) * Mathf.Cos(u);float y = center.y + r * Mathf.Sin(v) * Mathf.Sin(u);float z = center.z + r * Mathf.Cos(v);//返回指定球心的球面上隨機一點return new Vector3(x, y, z);}private void BulletMovement(Transform bulletTran){// 子彈朝向當前目標位置 bulletTran.LookAt(currentTargetPosition);bulletTran.position += bulletTran.forward * speed * Time.deltaTime; //向前移動// 檢查子彈是否到達當前目標位置 if (Vector3.Distance(bulletTran.position, currentTargetPosition) < 0.1f){// 如果當前點不是最后一個中間點,則更新下一個目標位置為下一個中間點 if (currentWaypointIndex < wayPoints.Count){currentWaypointIndex++;if (currentWaypointIndex < wayPoints.Count){currentTargetPosition = GetRandomPointOnSphere(wayPoints[currentWaypointIndex].position, radius);}else{currentTargetPosition = endPoint.position; // 最后一個中間點后,目標位置是終點 }}// 如果已經到達終點,可以選擇銷毀子彈或其他操作 else if (currentTargetPosition == endPoint.position){GameObject tempFX = Instantiate(FX, bulletTran.position, bulletTran.rotation); //生成一個爆炸特效 并給予位置和旋轉信息Destroy(gameObject);//銷毀自己Destroy(tempFX, 0.3f);//銷毀爆炸效果currentWaypointIndex = 0;//重置路徑索引}}}}
外部控制腳本
將導彈的擊打目標和散射路徑點通過腳本告訴導彈。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class InstantiateBullet : MonoBehaviour
{public GameObject bullet;//導彈預制體public Vector3 startPoint; // 導彈出生發射點 public Quaternion missileRotation;//導彈出生時方向public Transform endPoint; // 目標點 public List<Transform> wayPoints; // 中間點列表 // Start is called before the first frame updatevoid Start(){}// Update is called once per framevoid Update(){//鼠標點擊左鍵發射導彈if (Input.GetMouseButtonDown(0)){GameObject bu = Instantiate(bullet, startPoint, missileRotation);bu.GetComponent<SpherePoint>().endPoint = endPoint;bu.GetComponent<SpherePoint>().wayPoints = wayPoints;}}
}
外部腳本我掛載到了Main Camera
相機上。
應用效果
先看個正面的:
再來個側面的:
好了,結束。
結語
學會后要多嘗試,變成自己的東西,為己所用,趕快自己嘗試下吧。有什么問題可以評論區或私信留言,下期見,拜拜。