当前位置:网站首页>Unity制作简单拦截近防炮——如何预测打击目标
Unity制作简单拦截近防炮——如何预测打击目标
2022-07-23 07:02:00 【陈少伯】
突然想尝试一下在Unity中模拟近防炮(拦截炮),该拦截跑应该发射物理子弹并并命中处在运动中的物体,所以在代码中至少应考虑:
- 子弹发射矢量速度vb(暂不考虑风阻)
- 目标距离 L
- 目标当前矢量速度 v
- 目标运动加速度 a
- 重力加速度 g
有以上这些变量后就可以运用初高中知识来预判目标,并得到良好的命中率:以下算法目前只适用于匀速直线运动和匀变速直线运动。
首先是制作大炮和发射部分。这里简单地将圆柱体或者立方体拉成炮管,后期再替换成正经模型:

然后创建一个Prefab物体用作炮弹,什么形状都行,但是要有Rigibody,阻力调为0;炮管可以不用设置碰撞体,如果一定要碰撞体,那么就用以下方法来避免炮弹和炮管发生碰撞,将炮管和炮弹分别设置不同Layer:
Physics.IgnoreLayerCollisionhttps://docs.unity3d.com/ScriptReference/Physics.IgnoreLayerCollision.html
接下来就是发射炮弹,用StartCoroutine()接口来让大炮不间断地连射,发射频率可以实时更改:
using System.Collections;
using UnityEngine;
public class Interceptor : MonoBehaviour
{
public Transform TargetObj, PredictedObj;//assigin target
public GameObject bullet;// bullet prefab
public 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)//如果有瞄准的物体,那么就一直发射!
{
// 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);
}
}
}
接下来是核心部分,为了直观展现大炮预瞄位置,这里可以创建一个鲜艳的物体来表示,如上图中的红标,并将其绑定到 PredictedObj 变量上。只要将PredictedObj 的位置计算出来,让大炮直接调用LookAt 方法 或者 在操作面板中添加LookAt Constrant 锁定到该物体就可以实现简单的拦截打击了。
要预测PredictedObj 的位置,可以直接运用初高中物理知识:但是这里需要注意的是,最终采用的这种方法并不严谨,因为子弹在飞行的过程中距离 Distance 是会改变的, 因为物体在运动,这就涉及到动态预测——即在三维坐标系中,已知之前的1~5条件,还要加上:
6. 子弹发射时刻位置
7. 目标发射时刻位置
然后用两点距离公式和运动学公式(匀速和匀加速)连列来求解一个繁杂的二元一次方程,进而得出撞击前需要的未知时间T。
我直接裂开🤯,所以暂时不考虑方程求解部分,粗略的将未知T 变为:
这种方法最大的弊端就是炮弹越慢越难命中。Distance 在Unity中可以简单的调用:
distance = Vector3.Distance(transform.position, TargetObj.position);//get the current distance(insufficiently strict)bulletSpeed vb 提前设定好了;
加速度 a 在 Unity中需要手动计算,只需要在Update()中保存前一帧的目标速度,然后用公式
acceleration = (TargetRig.velocity - lastVelocity) / Time.deltaTime;//acceleration
lastVelocity = TargetRig.velocity;//get the current velocity for next frame acceleration caculation
最后直接明了,一个简单公式解决:
预测物体位置
= 预测物体初始位置
最后考虑到之前所说的不严谨,就再加上一个随机的小范围的散射,来达到“碰运气”的目的,毕竟就算是严谨计算,也无法应对某些特殊和突发状况,同时尽可能提高子弹速度来缩小
的误差,这就是为什么现实生活中的近放炮往往具有超高的射速,极高的子弹速度,一定的散射比例甚至是高空爆炸。
实际效果:
拦截炮初步演示
不难看出在低射速,低频率和低散射时,基本只在匀速直线运动和部分匀变速直线运动中起作用,变速和变加速命中率低的可怜。原因很简单,因为炮弹太慢,飞行时间太长,还没等到炮弹到达,目标早就变到下一个状态了;接着将射速、频率、散射全部调高,命中率一下子就上去了,真是非常的amazing啊
完整代码如下,或许还能优化:
using System.Collections;
using UnityEngine;
public class Interceptor : MonoBehaviour
{
public Transform TargetObj, PredictedObj;//assigin target
public GameObject bullet;// bullet prefab
public 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 frame
void Update()
{
if (!TargetObj) { return; }
acceleration = (TargetRig.velocity - lastVelocity) / Time.deltaTime;//acceleration
lastVelocity = TargetRig.velocity;//get the current velocity for next frame acceleration caculation
distance = Vector3.Distance(transform.position, TargetObj.position);//get the current distance(insufficiently strict)
flyingTime = distance / bulletSpeed; //dt = Distance / vb
PredictedObj.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);
}
}
}
边栏推荐
猜你喜欢

php连接sql server

Remote editing and debugging with vscode

做测试如何应对新的开发模式?

回溯法解决 八皇后问题

Optimising a 3D convolutional neural network for head and neck computed tomography segmentation with

keepalived双机热备

"Computing beast" Inspur nf5468a5 GPU server open trial free application

Hardware system architecture of 4D millimeter wave radar

Problem solving: script file 'scripts\pip script py‘ is not present.

解决MySQL向表中增加数据插入中文乱码问题
随机推荐
基于BIM+3DGIS的智慧城市基础设施管理
LeetCode_2342_数位和相等数对的最大和
Power BI----综合应用
数据库系统原理与应用教程(050)—— MySQL 查询(十二):SELECT 命令的执行过程分析
欧洲“气荒”对中国有哪些影响?
Wu Enda machine learning series p31~p42
Typora 修改表格宽度
Special topic of MIMO Radar (0) - General Chapter
MySQL index transaction & JDBC programming
[Muduo] poller abstract class
2. Les règles quantitatives
Database view detailed exploration
Smart city infrastructure management based on bim+3dgis
[graphics] ASTC texture compression format
第二章关系数据库课后习题
Introduction to radar part vii 1 radar and resolution
ES6——周考题
2022-07-22 review linked list operation and some problems
数据库-视图详探
QNX modify system time
