实际问题在于找出子弹可以与目标路径相交的空间位置。子弹速度恒定,因此在一定时间内,无论我们以何种方向发射它,它将行驶相同的距离。这意味着它在时间t之后的位置始终位于一个球体上。这是一个丑陋的2D示意图:
![](https://istack.dev59.com/QUvTI.webp)
该球体可以用以下数学公式表示:
(x-x_b0)^2 + (y-y_b0)^2 + (z-z_b0)^2 = (bulletSpeed * t)^2 (eq 1)
x_b0、y_b0和z_b0表示火炮的位置。您可以使用问题中提供的方程式解出时间t,具体方法是解这个方程式:
targetPos+t*targetVelocityVec (eq 2)
(eq 2)
是一个向量方程,可以分解成三个单独的方程:
x = x_t0 + t * v_x
y = y_t0 + t * v_y
z = z_t0 + t * v_z
这三个公式可以插入到(eq 1)
中:
(x_t0 + t * v_x - x_b0)^2 + (y_t0 + t * v_y - y_b0)^2 + (z_t0 + t * v_z - z_b0)^2 = (bulletSpeed * t)^2
这个方程只包含已知变量,可以解出 t。通过将二次子表达式的常数部分赋值给常数,我们可以简化计算:
c_1 = x_t0 - x_b0
c_2 = y_t0 - y_b0
c_3 = z_t0 - z_b0
(v_b = bulletSpeed)
(t * v_x + c_1)^2 + (t * v_y + c_2)^2 + (t * v_z + c_3)^2 = (v_b * t)^2
将其重新排列为标准二次方程:
(v_x^2+v_y^2+v_z^2-v_b^2)t^2 + 2*(v_x*c_1+v_y*c_2+v_z*c_3)t + (c_1^2+c_2^2+c_3^2) = 0
使用标准公式可以轻松解决这个问题。它可能有零、一个或两个解。零解(不计算复数解)意味着没有可能让子弹到达目标。当目标轨迹与球体的边缘相交时,很少会出现一个解的情况。两个解将是最常见的情况。负解意味着你无法击中目标,因为你需要向过去开火。这些都是你需要检查的条件。
当你解出方程后,可以通过将它放回(eq 2)
来找到t的位置。伪代码如下:
c_1 = x_t0 - x_b0
c_2 = y_t0 - y_b0
c_3 = z_t0 - z_b0
v_b = bulletSpeed
a = v_x^2+v_y^2+v_z^2-v_b^2
b = 2*(v_x*c_1+v_y*c_2+v_z*c_3)
c = c_1^2+c_2^2+c_3^2
if b^2 < 4*a*c:
raise error
p = -b/(2*a)
q = sqrt(b^2 - 4*a*c)/(2*a)
t1 = p-q
t2 = p+q
if t1 < 0 and t2 < 0:
raise error
if t1 > t2: t = t2
else: t = t1
x = x_t0 + t * v_x
y = y_t0 + t * v_y
z = z_t0 + t * v_z