Unity制作简单拦截近防炮——如何预测打击目标
突然想嘗試一下在Unity中模擬近防炮(攔截炮),該攔截跑應(yīng)該發(fā)射物理子彈并并命中處在運(yùn)動(dòng)中的物體,所以在代碼中至少應(yīng)考慮:
有以上這些變量后就可以運(yùn)用初高中知識(shí)來(lái)預(yù)判目標(biāo),并得到良好的命中率:以下算法目前只適用于勻速直線運(yùn)動(dòng)和勻變速直線運(yùn)動(dòng)。
首先是制作大炮和發(fā)射部分。這里簡(jiǎn)單地將圓柱體或者立方體拉成炮管,后期再替換成正經(jīng)模型:
然后創(chuàng)建一個(gè)Prefab物體用作炮彈,什么形狀都行,但是要有Rigibody,阻力調(diào)為0;炮管可以不用設(shè)置碰撞體,如果一定要碰撞體,那么就用以下方法來(lái)避免炮彈和炮管發(fā)生碰撞,將炮管和炮彈分別設(shè)置不同Layer:
Physics.IgnoreLayerCollisionhttps://docs.unity3d.com/ScriptReference/Physics.IgnoreLayerCollision.html接下來(lái)就是發(fā)射炮彈,用StartCoroutine()接口來(lái)讓大炮不間斷地連射,發(fā)射頻率可以實(shí)時(shí)更改:
using System.Collections; using UnityEngine;public class Interceptor : MonoBehaviour {public Transform TargetObj, PredictedObj;//assigin target public GameObject bullet;// bullet prefabpublic float FiringRate = .3f, bulletSpeed = 10f, towardSpeed = 1f, gravityLead = 0.5f, accurancy = 0.5f;public float flyingTime, distance, multiplyler, num_bullets_pertime = 5;[SerializeField] Rigidbody TargetRig;[SerializeField] Vector3 lastVelocity, acceleration;void Start(){TargetRig = TargetObj.GetComponent<Rigidbody>();StartCoroutine(Shoot());// start shooting}IEnumerator Shoot(){while (TargetObj)//如果有瞄準(zhǔn)的物體,那么就一直發(fā)射!{// for (int i = 0; i <= num_bullets_pertime; i++) { Instantiate(bullet, transform.position, transform.rotation).GetComponent<Rigidbody>().velocity = transform.forward * bulletSpeed * Random.Range(0.1f, 2f); }Instantiate(bullet, transform.position, transform.rotation).GetComponent<Rigidbody>().velocity = transform.forward * bulletSpeed;yield return new WaitForSeconds(FiringRate);}} }接下來(lái)是核心部分,為了直觀展現(xiàn)大炮預(yù)瞄位置,這里可以創(chuàng)建一個(gè)鮮艷的物體來(lái)表示,如上圖中的紅標(biāo),并將其綁定到?PredictedObj 變量上。只要將PredictedObj 的位置計(jì)算出來(lái),讓大炮直接調(diào)用LookAt 方法 或者?在操作面板中添加LookAt Constrant 鎖定到該物體就可以實(shí)現(xiàn)簡(jiǎn)單的攔截打擊了。
要預(yù)測(cè)PredictedObj 的位置,可以直接運(yùn)用初高中物理知識(shí):但是這里需要注意的是,最終采用的這種方法并不嚴(yán)謹(jǐn),因?yàn)樽訌椩陲w行的過(guò)程中距離?Distance?是會(huì)改變的, 因?yàn)槲矬w在運(yùn)動(dòng),這就涉及到動(dòng)態(tài)預(yù)測(cè)——即在三維坐標(biāo)系中,已知之前的1~5條件,還要加上:
6.? 子彈發(fā)射時(shí)刻位置
7.? 目標(biāo)發(fā)射時(shí)刻位置
然后用兩點(diǎn)距離公式和運(yùn)動(dòng)學(xué)公式(勻速和勻加速)連列來(lái)求解一個(gè)繁雜的二元一次方程,進(jìn)而得出撞擊前需要的未知時(shí)間T。
我直接裂開(kāi)🤯,所以暫時(shí)不考慮方程求解部分,粗略的將未知T 變?yōu)?#xff1a;
這種方法最大的弊端就是炮彈越慢越難命中。Distance 在Unity中可以簡(jiǎn)單的調(diào)用:
distance = Vector3.Distance(transform.position, TargetObj.position);//get the current distance(insufficiently strict)bulletSpeed vb 提前設(shè)定好了;
加速度 a 在 Unity中需要手動(dòng)計(jì)算,只需要在Update()中保存前一幀的目標(biāo)速度,然后用公式
- ??
最后直接明了,一個(gè)簡(jiǎn)單公式解決:
預(yù)測(cè)物體位置
= 預(yù)測(cè)物體初始位置?
??
最后考慮到之前所說(shuō)的不嚴(yán)謹(jǐn),就再加上一個(gè)隨機(jī)的小范圍的散射,來(lái)達(dá)到“碰運(yùn)氣”的目的,畢竟就算是嚴(yán)謹(jǐn)計(jì)算,也無(wú)法應(yīng)對(duì)某些特殊和突發(fā)狀況,同時(shí)盡可能提高子彈速度來(lái)縮小?的誤差,這就是為什么現(xiàn)實(shí)生活中的近放炮往往具有超高的射速,極高的子彈速度,一定的散射比例甚至是高空爆炸。
實(shí)際效果:
攔截炮初步演示
不難看出在低射速,低頻率和低散射時(shí),基本只在勻速直線運(yùn)動(dòng)和部分勻變速直線運(yùn)動(dòng)中起作用,變速和變加速命中率低的可憐。原因很簡(jiǎn)單,因?yàn)榕趶椞?#xff0c;飛行時(shí)間太長(zhǎng),還沒(méi)等到炮彈到達(dá),目標(biāo)早就變到下一個(gè)狀態(tài)了;接著將射速、頻率、散射全部調(diào)高,命中率一下子就上去了,真是非常的amazing啊
完整代碼如下,或許還能優(yōu)化:
using System.Collections; using UnityEngine;public class Interceptor : MonoBehaviour {public Transform TargetObj, PredictedObj;//assigin target public GameObject bullet;// bullet prefabpublic float FiringRate = .3f, bulletSpeed = 10f, followSpeed = 1f, gravityLead = 0.5f, accurancy = 0.5f;public float flyingTime, distance;[SerializeField] Rigidbody TargetRig;[SerializeField] Vector3 lastVelocity, acceleration;void Start(){TargetRig = TargetObj.GetComponent<Rigidbody>();StartCoroutine(Shoot());// start shooting}// Update is called once per framevoid Update(){if (!TargetObj) { return; }acceleration = (TargetRig.velocity - lastVelocity) / Time.deltaTime;//accelerationlastVelocity = TargetRig.velocity;//get the current velocity for next frame acceleration caculationdistance = Vector3.Distance(transform.position, TargetObj.position);//get the current distance(insufficiently strict)flyingTime = distance / bulletSpeed; //dt = Distance / vbPredictedObj.position = Vector3.Lerp(PredictedObj.position,//use Lerp to control cannon's follow speed(TargetObj.position // current position+ TargetRig.velocity * flyingTime // next position with uniform linear motion: dL1 = L + dt * v+ 0.5f * Mathf.Pow(flyingTime, 2f) * acceleration// then add distance with uniformly variable motiond during dt: dL2= dL1 + 1/2 * a * dt^2+ 0.5f * Mathf.Pow(flyingTime, 2f) * -Physics.gravity// next add distance with gravity's uniformly variable motion during dt: dL3= dL2 + 1/2 * a * dt^2+ new Vector3(Random.Range(-accurancy, accurancy), Random.Range(-accurancy, accurancy), Random.Range(-accurancy, accurancy))//finally add alittle random fractors to incrase hit rate chance ),Time.deltaTime * followSpeed);}IEnumerator Shoot(){while (TargetObj){// for (int i = 0; i <= num_bullets_pertime; i++) { Instantiate(bullet, transform.position, transform.rotation).GetComponent<Rigidbody>().velocity = transform.forward * bulletSpeed * Random.Range(0.1f, 2f); }Instantiate(bullet, transform.position, transform.rotation).GetComponent<Rigidbody>().velocity = transform.forward * bulletSpeed;yield return new WaitForSeconds(FiringRate);}} }總結(jié)
以上是生活随笔為你收集整理的Unity制作简单拦截近防炮——如何预测打击目标的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 国货百雀羚化妆品---大数据分析
- 下一篇: 医院计算机管理员自我鉴定,网络管理员个人