unity導彈算法 預計目標點

關於導彈的飛行算法,網上有不少教程。簡單算法無非是獲取目標點的當前位置,而後導彈朝目標方向移動。高深點的,就是經過計算獲取碰撞點而後朝着目標移動。若是你能看懂這個高深算法的話,能夠去看原帖:http://game.ceeger.com/forum/read.php?tid=3919php

須要注意的是,原帖存在錯誤。並且一些方法使用的不合理。下面是我整合後的代碼,歡迎你們提出不一樣看法。html

想要實現導彈的「攔截」功能,首先須要根據目標物體的速度,位置,導彈的速度,位置,計算出二者相交的預計點。而後導彈朝碰撞點移動。算法

由於目標可能作不規則運動,因此須要公式計算物體的平均速度。即速度=距離/時間。物體的方向,則是當前位置-上一位置。下面是計算物體的速度和方向的具體代碼:ide

 

using UnityEngine;
using System.Collections; public class SpeedTest : MonoBehaviour { private float lastTime; private Vector3 lastPos; private float dtime; [HideInInspector] public Vector3 CurrentVector; [HideInInspector] public float Speed; // Update is called once per frame void OnEnable() { lastTime = Time.time; lastPos = transform.position; } void Update () { dtime = Time.time - lastTime; if (dtime > 0) { lastTime = Time.time; Speed = PhycisMath.GetSpeed(lastPos, transform.position, dtime); CurrentVector = PhycisMath.GetDir(lastPos, transform.position); if (Mathf.Abs(Speed)<0.001f) { CurrentVector = transform.TransformDirection(Vector3.forward); } lastPos = transform.position; } } }

 

上面是經過位移來算的速度和方向,與物理效果無關,因此擁有更好的適用性,能夠用來不規則的平滑運動計算。爲了代碼的直觀,將一些經常使用的方法封裝於一個靜態方法類中。測試

using UnityEngine;
using System.Collections; public class PhycisMath { public static float GetSpeed(Vector3 lastPos,Vector3 newPs,float time) { if (time == 0) return 0; return Vector3.Distance(lastPos, newPs) / time; } public static Vector3 GetDir(Vector3 lastPos, Vector3 newPs) { return (newPs - lastPos).normalized; } public static float GetDelta(float a,float b,float c) { return b * b - 4 * a * c; } public static float GetRad(float dis, float angle) { return -(2 * dis * Mathf.Cos(angle * Mathf.Deg2Rad)); } public static float GetPom(float a, float b) { return 1-Mathf.Pow(a,b); } public static float GetSqrtOfMath(float a,float b, float d) { float a1 = (-b + Mathf.Sqrt(d)) / (2 * a); float a2 = (-b - Mathf.Sqrt(d)) / (2 * a); return a1>a2?a1:a2; } public Vector3 GetHitPoint() { return Vector3.zero; } }

 

接下來是寫一個雷達,經過一系列「複雜」的運算獲取碰撞點位置。ui

using UnityEngine;
using System.Collections; public class RadarOfRocket : MonoBehaviour { //咱們的導彈的軌道計算是基於Transform的, //純數學的計算,這樣更精確,適用性更好 public Transform target;//目標 private SpeedTest rocketSpeed;// private SpeedTest targetSpeed; private Vector3 targetDir; private float angle; private float distence; private bool isAim = false; public bool IsAim { get { return isAim; } set { isAim = value; } } private Vector3 aimPos; public Vector3 AimPos { get { return aimPos; } set { aimPos = value; } } void checkTarget() { if (!(rocketSpeed=GetComponent<SpeedTest>())) { gameObject.AddComponent<SpeedTest>(); rocketSpeed = GetComponent<SpeedTest>(); } if (target&&!(targetSpeed = target.GetComponent<SpeedTest>())) { target.gameObject.AddComponent<SpeedTest>(); targetSpeed = target.GetComponent<SpeedTest>(); } } void OnEnable() { checkTarget(); } void Update() { if (target) TestAim(); } public void TestAim() { if (Mathf.Abs(targetSpeed.Speed) < 0.01f) { //物體的速度太小,則默認物體是靜止的。  isAim = true; aimPos = target.position; } else { targetDir = transform.position - target.position; angle = Vector3.Angle(targetDir, targetSpeed.CurrentVector); distence = targetDir.magnitude; float a = PhycisMath.GetPom((rocketSpeed.Speed / targetSpeed.Speed), 2); float b = PhycisMath.GetRad(distence, angle); float c = distence * distence; float d = PhycisMath.GetDelta(a, b, c); isAim = d >= 0 && !float.IsNaN(d) && !float.IsInfinity(d); if (isAim) { float r = PhycisMath.GetSqrtOfMath(a, b, d); if (r < 0) isAim = false;//若是得出的是負值,則表明交點有誤 aimPos = target.transform.position + targetSpeed.CurrentVector * r; } } } }

 

原博客中的解是獲取較小的那個。可是據我測試,只有正解時目標點才正確。你們也能夠進行測試。值得注意的是,導彈的速度必需要大於目標的速度,否則導彈沒法靠近目標。spa

好,獲取目標點的代碼已經完成了。接着是導彈的飛行代碼。關於這部分,通常的作法是經過移動+轉向實現導彈的軌跡。代碼很簡單。距離和角度的過濾我就省略了,基本上新手都能寫出來。code

 

using UnityEngine;
using System.Collections; [RequireComponent(typeof(RadarOfRocket))] public class Missile : MonoBehaviour { private RadarOfRocket radar; public float Speed = 100; public float RoteSpeed = 3; public float Noise = 0; void OnEnable() { radar = GetComponent<RadarOfRocket>(); } void Update() { Fly(); if (radar.IsAim) { FlyToTarget(radar.AimPos-transform.position); } } private void FlyToTarget(Vector3 point) { if (point != Vector3.zero) { Quaternion missileRotation = Quaternion.LookRotation(point, Vector3.up); transform.rotation = Quaternion.Slerp(transform.rotation, missileRotation, Time.deltaTime * RoteSpeed); } } private void Fly() { Move(transform.forward.normalized+transform.right*Mathf.PingPong(Time.time,0.5f)*Noise, Speed*Time.deltaTime); } public void Move(Vector3 dir,float speed){ transform.Translate(dir*speed,Space.World); } void OnTriggerEnter(Collider other) { print("hit"); } }

 

好,上面就是導彈的全部代碼了。謝謝觀看。orm

 

考慮到可能有小白拿到代碼可能徹底不知道怎麼弄,故增長如下注釋。htm

將Radar.cs腳本和Missile.cs腳本託給你作好的導彈。而後將目標Transform賦值給Radar的target便可完成攔截導彈的演示。

關於目標怎樣的移動,你能夠本身定義,像直線移動或者圓周移動,不規則平滑移動等等均可以進行攔截。具體的效果由參數控制,可是必定要注意導彈的速度必定要大於目標的

速度,攔截導彈才能發揮做用!

本文的連接是:http://www.cnblogs.com/jqg-aliang/p/4768101.html 轉載請申明出處謝謝!

相關文章
相關標籤/搜索