在三维空间中,利用抛物线公式计算弹道,得到一个发射初速度,让导弹打击到指定地点效果:
脚本使用:只需指定目标点即可可以通过 Hight 调整导弹的飞行高度可以通过 Gravity 调整导弹的飞行速度
通过以下两个脚本实现。工具脚本计算弹道,Missile 脚本每帧更新导弹位置
PhysicsUtil.cs
using UnityEngine;
/// <summary> 物理计算工具
/// <para>ZhangYu 2018-05-10</para>
/// </summary>
public static class PhysicsUtil {
/**findInitialVelocity
* Finds the initial velocity of a projectile given the initial positions and some offsets
* @param Vector3 startPosition – the starting position of the projectile
* @param Vector3 finalPosition – the position that we want to hit
* @param float maxHeightOffset (default=0.6f) – the amount we want to add to the height for short range shots. We need enough clearance so the
* ball will be able to get over the rim before dropping into the target position
* @param float rangeOffset (default=0.11f) – the amount to add to the range to increase the chances that the ball will go through the rim
* @return Vector3 – the initial velocity of the ball to make it hit the target under the current gravity force.
*
* Vector3 tt = findInitialVelocity (gameObject.transform.position, target.transform.position);
Rigidbody rigidbody = gameObject.GetComponent<Rigidbody> ();
Debug.Log (tt);
rigidbody.AddForce(tt*rigidbody.mass,ForceMode.Impulse);
*/
public static Vector3 GetParabolaInitVelocity(Vector3 from, Vector3 to, float gravity = 9.8f, float heightOff = 0.0f, float rangeOff = 0.11f) {
// get our return value ready. Default to (0f, 0f, 0f)
Vector3 newVel = new Vector3();
// Find the direction vector without the y-component
/// / 找到未经 y 分量的方向矢量 //
Vector3 direction = new Vector3(to.x, 0f, to.z) – new Vector3(from.x, 0f, from.z);
// Find the distance between the two points (without the y-component)
// 发现这两个点之间的距离(不 y 分量)//
float range = direction.magnitude;
// Add a little bit to the range so that the ball is aiming at hitting the back of the rim.
// Back of the rim shots have a better chance of going in.
// This accounts for any rounding errors that might make a shot miss (when we don’t want it to).
range += rangeOff;
// Find unit direction of motion without the y component
Vector3 unitDirection = direction.normalized;
// Find the max height
// Start at a reasonable height above the hoop, so short range shots will have enough clearance to go in the basket
// without hitting the front of the rim on the way up or down.
float maxYPos = to.y + heightOff;
// check if the range is far enough away where the shot may have flattened out enough to hit the front of the rim
// if it has, switch the height to match a 45 degree launch angle
//if (range / 2f > maxYPos)
// maxYPos = range / 2f;
if (maxYPos < from.y)
maxYPos = from.y;
// find the initial velocity in y direction
/// / 发现在 y 方向上的初始速度 //
float ft;
ft = -2.0f * gravity * (maxYPos – from.y);
if (ft < 0) ft = 0f;
newVel.y = Mathf.Sqrt(ft);
// find the total time by adding up the parts of the trajectory
// time to reach the max
// 发现的总时间加起来的轨迹的各部分 //
// 时间达到最大 //
ft = -2.0f * (maxYPos – from.y) / gravity;
if (ft < 0)
ft = 0f;
float timeToMax = Mathf.Sqrt(ft);
// time to return to y-target
// 时间返回到 y 轴的目标 //
ft = -2.0f * (maxYPos – to.y) / gravity;
if (ft < 0)
ft = 0f;
float timeToTargetY = Mathf.Sqrt(ft);
// add them up to find the total flight time
// 把它们加起来找到的总飞行时间 //
float totalFlightTime;
totalFlightTime = timeToMax + timeToTargetY;
// find the magnitude of the initial velocity in the xz direction
/// / 查找的初始速度的大小在 xz 方向 //
float horizontalVelocityMagnitude = range / totalFlightTime;
// use the unit direction to find the x and z components of initial velocity
// 使用该单元的方向寻找初始速度的 x 和 z 分量 //
newVel.x = horizontalVelocityMagnitude * unitDirection.x;
newVel.z = horizontalVelocityMagnitude * unitDirection.z;
return newVel;
}
/// <summary> 计算抛物线物体在下一帧的位置 </summary>
/// <param name=”position”> 初始位置 </param>
/// <param name=”velocity”> 移动速度 </param>
/// <param name=”gravity”> 重力加速度 </param>
/// <param name=”time”> 飞行时间 </param>
/// <returns></returns>
public static Vector3 GetParabolaNextPosition(Vector3 position, Vector3 velocity, float gravity, float time) {
velocity.y += gravity * time;
return position + velocity * time;
}
}
Missile.cs
using UnityEngine;
/// <summary>
/// 抛物线导弹
/// <para> 计算弹道和转向 </para>
/// <para>ZhangYu 2019-02-27</para>
/// </summary>
public class Missile : MonoBehaviour {
public Transform target; // 目标
public float hight = 16f; // 抛物线高度
public float gravity = -9.8f; // 重力加速度
private Vector3 position; // 我的位置
private Vector3 dest; // 目标位置
private Vector3 velocity; // 运动速度
private float time = 0; // 运动时间
private void Start() {
dest = target.position;
position = transform.position;
velocity = PhysicsUtil.GetParabolaInitVelocity(position, dest, gravity, hight, 0);
transform.LookAt(PhysicsUtil.GetParabolaNextPosition(position, velocity, gravity, Time.deltaTime));
}
private void Update() {
// 计算位移
float deltaTime = Time.deltaTime;
position = PhysicsUtil.GetParabolaNextPosition(position, velocity, gravity, deltaTime);
transform.position = position;
time += deltaTime;
velocity.y += gravity * deltaTime;
// 计算转向
transform.LookAt(PhysicsUtil.GetParabolaNextPosition(position, velocity, gravity, deltaTime));
// 简单模拟一下碰撞检测
if (position.y <= dest.y) enabled = false;
}
}