unity导弹算法 预计目标点

关于导弹的飞行算法,网上有很多教程。简单算法无非是获取目标点的当前位置,然后导弹朝目标方向移动。高深点的,就是通过计算获取碰撞点然后朝着目标移动。如果你能看懂这个高深算法的话,可以去看原帖:http://game.ceeger.com/forum/read.php?tid=3919

需要注意的是,原帖存在错误。而且一些方法使用的不合理。下面是我整合后的代码,欢迎大家提出不同见解。

想要实现导弹的“拦截”功能,首先需要根据目标物体的速度,位置,导弹的速度,位置,计算出两者相交的预计点。然后导弹朝碰撞点移动。

因为目标可能做不规则运动,所以需要公式计算物体的平均速度。即速度=距离/时间。物体的方向,则是当前位置-上一位置。下面是计算物体的速度和方向的具体代码:

 

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

 

接下来是写一个雷达,通过一系列“复杂”的运算获取碰撞点位置。

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

 

原博客中的解是获取较小的那个。但是据我测试,只有正解时目标点才正确。大家也可以进行测试。值得注意的是,导弹的速度必须要大于目标的速度,不然导弹无法靠近目标。

好,获取目标点的代码已经完成了。接着是导弹的飞行代码。关于这部分,一般的做法是通过移动+转向实现导弹的轨迹。代码很简单。距离和角度的过滤我就省略了,基本上新手都能写出来。

 

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

 

好,上面就是导弹的所有代码了。谢谢观看。

 

考虑到可能有小白拿到代码可能完全不知道怎么弄,故增加以下注释。

将Radar.cs脚本和Missile.cs脚本托给你做好的导弹。然后将目标Transform赋值给Radar的target即可完成拦截导弹的演示。

关于目标怎样的移动,你可以自己定义,像直线移动或者圆周移动,不规则平滑移动等等都可以进行拦截。具体的效果由参数控制,但是一定要注意导弹的速度一定要大于目标的

速度,拦截导弹才能发挥作用!

本文的链接是:http://www.cnblogs.com/jqg-aliang/p/4768101.html 转载请申明出处谢谢!

转载于:https://www.cnblogs.com/jqg-aliang/p/4768101.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值