好吧,这一切都发生在一个美好而简单的 2D 世界中......:)
假设我有一个位于 Apos 的静态物体 A,一个位于 Bpos 且速度为 bVelocity 的线性移动物体 B,以及一个速度为 Avelocity 的弹药...
考虑到 B 的线速度和 A 弹药的速度,我如何找出 A 必须射击、击中 B 的角度?
现在的目标是物体的当前位置,这意味着当我的射弹到达那里时,单位已经移动到更安全的位置:)
最佳答案
我为 xtank 编写了一个瞄准子程序一会儿回来。我将尝试阐述我是如何做到的。
免责声明:我可能在此处犯了一个或多个愚蠢的错误;我只是想用我生锈的数学技能来重建推理。不过,我先切入正题,因为这是编程问答而不是数学课:-)
如何做
归结为求解以下形式的二次方程:
a * sqr(x) + b * x + c == 0
请注意,sqr
是指平方,而不是平方根。使用以下值:
a := sqr(target.velocityX) + sqr(target.velocityY) - sqr(projectile_speed)
b := 2 * (target.velocityX * (target.startX - cannon.X)
+ target.velocityY * (target.startY - cannon.Y))
c := sqr(target.startX - cannon.X) + sqr(target.startY - cannon.Y)
现在我们可以查看判别式来确定是否有可能的解决方案。
disc := sqr(b) - 4 * a * c
如果判别式小于 0,就别想击中目标了——你的射弹永远无法及时到达目标。否则,请查看两个候选解决方案:
t1 := (-b + sqrt(disc)) / (2 * a)
t2 := (-b - sqrt(disc)) / (2 * a)
请注意,如果 disc == 0
则 t1
和 t2
相等。
如果没有其他考虑因素,例如干扰障碍物,则只需选择较小的正值。 (负t值需要及时向后射击才能使用!)
将所选的 t
值代入目标的位置方程,以获得您应该瞄准的引导点的坐标:
aim.X := t * target.velocityX + target.startX
aim.Y := t * target.velocityY + target.startY
推导
在时间 T 时,弹丸与大炮的(欧几里德)距离必须等于耗时乘以弹丸速度。这给出了一个圆的方程,以耗时为参数。
sqr(projectile.X - cannon.X) + sqr(projectile.Y - cannon.Y)
== sqr(t * projectile_speed)
类似地,在时间 T 处,目标沿其矢量移动时间乘以其速度:
target.X == t * target.velocityX + target.startX
target.Y == t * target.velocityY + target.startY
当炮弹与炮弹的距离与炮弹的距离一致时,炮弹就能击中目标。
sqr(projectile.X - cannon.X) + sqr(projectile.Y - cannon.Y)
== sqr(target.X - cannon.X) + sqr(target.Y - cannon.Y)
太棒了!将表达式替换为 target.X 和 target.Y 得出
sqr(projectile.X - cannon.X) + sqr(projectile.Y - cannon.Y)
== sqr((t * target.velocityX + target.startX) - cannon.X)
+ sqr((t * target.velocityY + target.startY) - cannon.Y)
代入等式另一边可得出:
sqr(t * projectile_speed)
== sqr((t * target.velocityX + target.startX) - cannon.X)
+ sqr((t * target.velocityY + target.startY) - cannon.Y)
...从两边减去sqr(t *projectile_speed)
并翻转它:
sqr((t * target.velocityX) + (target.startX - cannon.X))
+ sqr((t * target.velocityY) + (target.startY - cannon.Y))
- sqr(t * projectile_speed)
== 0
...现在解析子表达式的平方结果...
sqr(target.velocityX) * sqr(t)
+ 2 * t * target.velocityX * (target.startX - cannon.X)
+ sqr(target.startX - cannon.X)
+ sqr(target.velocityY) * sqr(t)
+ 2 * t * target.velocityY * (target.startY - cannon.Y)
+ sqr(target.startY - cannon.Y)
- sqr(projectile_speed) * sqr(t)
== 0
...并将相似术语分组...
sqr(target.velocityX) * sqr(t)
+ sqr(target.velocityY) * sqr(t)
- sqr(projectile_speed) * sqr(t)
+ 2 * t * target.velocityX * (target.startX - cannon.X)
+ 2 * t * target.velocityY * (target.startY - cannon.Y)
+ sqr(target.startX - cannon.X)
+ sqr(target.startY - cannon.Y)
== 0
...然后将它们合并...
(sqr(target.velocityX) + sqr(target.velocityY) - sqr(projectile_speed)) * sqr(t)
+ 2 * (target.velocityX * (target.startX - cannon.X)
+ target.velocityY * (target.startY - cannon.Y)) * t
+ sqr(target.startX - cannon.X) + sqr(target.startY - cannon.Y)
== 0
...给出t中的标准二次方程。找到该方程的正实零点给出(零、一个或两个)可能的命中位置,这可以使用二次公式来完成:
a * sqr(x) + b * x + c == 0
x == (-b ± sqrt(sqr(b) - 4 * a * c)) / (2 * a)
关于2d 游戏 : fire at a moving target by predicting intersection of projectile and unit,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2248876/