Unity 计算导弹抛物线弹道和转向

坚牢地神天
• 阅读 14071

在三维空间中,利用抛物线公式计算弹道,得到一个发射初速度,让导弹打击到指定地点
效果图:
Unity 计算导弹抛物线弹道和转向

测试脚本:
通过Height调整导弹的飞行高度
通过Gravity调整导弹的飞行速度
Unity 计算导弹抛物线弹道和转向

代码实现

关键代码:

// 求导弹初始速度
public void InitVelocity(Vector3 start, Vector3 end, float height = 10, float gravity = -9.8f)
    float topY = Mathf.Max(start.y, end.y) + height;
    float d1 = topY - start.y;
    float d2 = topY - end.y;
    float g2 = 2 / -gravity;
    float t1 = Mathf.Sqrt(g2 * d1);
    float t2 = Mathf.Sqrt(g2 * d2);
    float t = t1 + t2;
    float vX = (end.x - start.x) / t;
    float vZ = (end.z - start.z) / t;
    float vY = -gravity * t1;
    Vector3 v0 = new Vector3(vX, vY, vZ);
    return v0;
}


// 求下一帧导弹的位置:
public static Vector3 NextPosition(Vector3 position, Vector3 velocity, float gravity, float time) {
    float dY = 0.5f * gravity * time * time;
    return position + velocity * time + new Vector3(0, dY, 0);
}

代码封装:

using UnityEngine;

/// <summary>
/// 抛物线运动轨迹
/// ZhangYu 2019-04-28
/// <param>blog:https://segmentfault.com/a/1190000018336439</param>
/// </summary>
public class ParabolaPath {

    /// <summary> 是否夹紧起点和终点 </summary>
    public bool isClampStartEnd;
    private Vector3 m_start;
    private Vector3 m_end;
    private float m_height;
    private float m_gravity;
    private float m_upTime;
    private float m_downTime;
    private float m_totalTime;
    private Vector3 m_velocityStart;
    private Vector3 m_position;
    private float m_time;

    /// <summary> 初始化抛物线运动轨迹 </summary>
    /// <param name="start">起点</param>
    /// <param name="end">终点</param>
    /// <param name="height">高度(相对于两个点的最高位置 高出多少)</param>
    /// <param name="gravity">重力加速度(负数)</param>
    /// <returns></returns>
    public ParabolaPath(Vector3 start, Vector3 end, float height = 10, float gravity = -9.8f) {
        Init(start, end, height, gravity);
    }

    /// <summary> 初始化抛物线运动轨迹 </summary>
    /// <param name="start">起点</param>
    /// <param name="end">终点</param>
    /// <param name="height">高度(相对于两个点的最高位置 高出多少)</param>
    /// <param name="gravity">重力加速度(负数)</param>
    /// <returns></returns>
    public void Init(Vector3 start, Vector3 end, float height = 10, float gravity = -9.8f) {
        float topY = Mathf.Max(start.y, end.y) + height;
        float d1 = topY - start.y;
        float d2 = topY - end.y;
        float g2 = 2 / -gravity;
        float t1 = Mathf.Sqrt(g2 * d1);
        float t2 = Mathf.Sqrt(g2 * d2);
        float t = t1 + t2;
        float vX = (end.x - start.x) / t;
        float vZ = (end.z - start.z) / t;
        float vY = -gravity * t1;
        m_start = start;
        m_end = end;
        m_height = height;
        m_gravity = gravity;
        m_upTime = t1;
        m_downTime = t2;
        m_totalTime = t;
        m_velocityStart = new Vector3(vX, vY, vZ);
        m_position = m_start;
        m_time = 0;
    }

    /// <summary> 起点 </summary>
    public Vector3 start { get { return m_start; } }
    /// <summary> 终点 </summary>
    public Vector3 end { get { return m_end; } }
    /// <summary> 目标高度 </summary>
    public float height { get { return m_height; } }
    /// <summary> 重力加速度 </summary>
    public float gravity { get { return m_gravity; } }
    /// <summary> 上升时间 </summary>
    public float upTime { get { return m_upTime; } }
    /// <summary> 下降时间 </summary>
    public float downTime { get { return m_downTime; } }
    /// <summary> 总运动时间 </summary>
    public float totalTime { get { return m_totalTime; } }
    /// <summary> 顶点 </summary>
    public Vector3 top { get { return GetPosition(m_upTime); } }
    /// <summary> 初始速度 </summary>
    public Vector3 velocityStart { get { return m_velocityStart; } }
    /// <summary> 当前位置 </summary>
    public Vector3 position { get { return m_position; } }
    /// <summary> 当前速度 </summary>
    public Vector3 velocity { get { return GetVelocity(m_time); } }

    /// <summary> 当前时间 </summary>
    public float time {
        get { return m_time; }
        set {
            if (isClampStartEnd) value = Mathf.Clamp(value, 0, m_totalTime);
            m_time = value;
            m_position = GetPosition(value);
        }
    }

    /// <summary> 获取某个时间点的位置 </summary>
    public Vector3 GetPosition(float time) {
        if (time == 0) return m_start;
        if (time == m_totalTime) return m_end;
        float dY = 0.5f * m_gravity * time * time;
        return m_start + m_velocityStart * time + new Vector3(0, dY, 0);
    }

    /// <summary> 获取某个时间点的速度 </summary>
    public Vector3 GetVelocity(float time) {
        if (time == 0) return m_velocityStart;
        return m_velocityStart + new Vector3(0, m_velocityStart.y + m_gravity * time, 0);
    }

}

测试代码:

using UnityEngine;

/// <summary>
/// 抛物线导弹
/// <para>计算弹道和转向</para>
/// <para>ZhangYu 2019-02-27</para>
/// </summary>
public class Missile : MonoBehaviour {

    public Transform target;        // 目标
    public float height = 16f;      // 高度
    public float gravity = -9.8f;   // 重力加速度
    private ParabolaPath path;      // 抛物线运动轨迹

    private void Start() {
        path = new ParabolaPath(transform.position, target.position, height, gravity);
        path.isClampStartEnd = true;
        transform.LookAt(path.GetPosition(path.time + Time.deltaTime));
    }

    private void Update() {
        // 计算位移
        float t = Time.deltaTime;
        path.time += t;
        transform.position = path.position;

        // 计算转向
        transform.LookAt(path.GetPosition(path.time + t));

        // 简单模拟一下碰撞检测
        if (path.time >= path.totalTime) enabled = false;
    }

}
点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Karen110 Karen110
4年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
1年前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Stella981 Stella981
3年前
Rancher开源Harvester:基于K8s的超融合基础架构软件
2020年12月17日,业界应用最为广泛的Kubernetes管理平台创建者RancherLabs(以下简称Rancher)宣布推出全新开源软件Harvester,一个通过Kubernetes构建的超融合基础架构(HCI)软件。!图片(https://img.rwimg.top/7592_5649bc00e54d4b30a1419db9c4
Easter79 Easter79
3年前
Taro小程序自定义顶部导航栏
微信自带的顶部导航栏是无法支持自定义icon和增加元素的,在开发小程序的时候自带的根本满足不了需求,分享一个封装好的组件,支持自定义icon、扩展dom,适配安卓、ios、h5,全面屏。我用的是京东的Taro多端编译框架写的小程序,原生的也可以适用,用到的微信/taro的api做调整就行,实现效果如下。!在这里插入图片描述(https://i
Stella981 Stella981
3年前
Python之time模块的时间戳、时间字符串格式化与转换
Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y
光纤陀螺仪应用情况
是目前惯性技术研究领域的主流陀螺仪。早在2005年就已经在中近程导弹、中程导弹、卫星等国外武器装备领域占据了一半以上的使用量。一般来说,根据应用场景的性能要求,不同的precision光纤陀螺仪对应不同的应用范围,涵盖了从战略武器装备到商用民用产品的所有领
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
坚牢地神天
坚牢地神天
Lv1
千淘万漉虽辛苦,吹尽狂沙始到金。
文章
2
粉丝
0
获赞
0