如何防止制导导弹环绕目标飞行?


78

我正在开发一种没有摩擦的2D空间游戏,并且发现将制导导弹绕其目标飞行非常容易。我对反轨道策略感到好奇。

一个简单的例子是寻的导弹,它直接直接向目标加速。如果该目标垂直于导弹的轨迹移动然后停止,则导弹向目标的加速度将不足以克服其自身的速度,并且导弹可能被驱动进入目标周围的轨道,如下所示:

轨道问题

  • 在第1帧中,导弹直奔目标,没有问题。
  • 如图所示,在第2帧中,目标已移动到新位置。导弹继续直接向目标(红色)加速,同时由于其现有速度仍向目标过去(黑色)移动。
  • 在第3帧中,导弹的速度继续将导弹携带在目标侧面(黑色)周围,而加速度矢量拼命地将导弹拉向目标。
  • 在第4帧及以后的帧中,导弹落入目标周围潜在的稳定轨道,并且从未达到目标。黑色箭头表示速度矢量,而红色线表示同一时间的加速度矢量。

考虑到空间中没有摩擦,没有什么可以减慢导弹的速度并使轨道崩溃的。一种可能的解决方案是将目标瞄准在目标“后面”,这将导致轨道闭合,但是从编程的角度来看,这是如何完成的呢?

如何使寻的导弹达到目标?


9
实际上,这是使物体进入轨道的一种非常酷的方法。
Derek 2012年

这使我想起了Euler集成。您所要做的就是使您的时间步长无限小,问题已解决!
杰夫

我想在我的游戏中实现这种效果!:D
Zolomon


6
@Deza这就是轨道的定义。轨道物体以向心力的方式向其他物体的中心加速。
bobobobo

Answers:


49

首先,您应该对要在导弹的参考系中应用的加速度进行所有计算(在该位置,导弹是静止的,其他一切围绕它移动,在游戏引擎中通常也称为“对象坐标”或“局部坐标”,尽管在我们的例子中,我们也希望速度也恰好为零)。

那时的想法不是针对目标,而是针对目标在估计的影响时间所处的地方。因此,通用算法如下所示:

  1. 估计导弹到达目标所需的时间。如果目标直接在目标上飞行(请记住,导弹是静止的),则可以像计算距离 / 速度一样简单,在其他情况下则可以更复杂。如果目标可以逃避,无论如何您将无法做出完美的估计,因此不要太精确也可以。

  2. 假设目标为恒定速度(一级估计)或恒定加速度(第二级估计),请计算上述估计时间的目标位置。

  3. 计算加速度,这将导致导弹同时位于大致相同的位置。

  4. 将加速度从导弹的参照系重新投影到全局参照系,并使用该参照系。

此处的重要部分是在粗糙的球场上获得时间估计,并且在执行过程中不要忘记导弹的加速能力。例如,对“目标正好在我们前方并朝我们的方向飞行”的一个更好的估计将是解方程。

距离 = 速度 x 时间 + 1/2 x 加速度 x 时间2

......对于时间(使用直线飞行物体负速度从导弹),与解决方案,您正在寻找使用标准二次公式是...

时间 =(√(速度2 + 2 x 加速度 x 距离)- 速度)/ 加速度

添加其他参数(例如,拖动)可将其快速转换为无代数解的微分方程。就是为什么火箭科学如此困难。


我认为这正是我所需要的。在此之前,我从未在本地坐标中考虑过。
约翰·麦克唐纳

5
好答案。附带说明一下,许多跟踪导弹的设计都可以在这些条件下自动爆炸:1)到达轨道一定距离内; 2)到轨道的距离正在增加。这可能会以很少的代价增加一些不错的行为。
Patrick Hughes

1
这是一个很好的答案。我最终为武器使用了恒定的加速度(我认为这是最现实的),估计了到达它所花费的时间(重新安排d = v t + 1/2 * a t * t并求解t)。秘诀在于反馈时间估计,以预测目标的当前速度和影响目标的时间。效果很好。
bobobobo

1
我想这是一个类型的航位推算算法
bobobobo

42

@Martin Sojka已经告诉过你该怎么做。除了要改善他的回答,我还想向您提出另一个更简单的方法:DELOCK

正如我在车辆的预计轨迹中所说的那样,操纵能力受限的对象会“投射”几个阴影圈:通过直接操纵无法到达的两个区域(较高尺寸的圆环和hypertorus)。

当您看到目标正在进入这种转向阴影之一时,可以停止将目标归位,并在有限的时间内保持另一个方向。

通过用(双)锥*接近花托,可以轻松计算出解锁触发器:

解锁触发器

您只需简单地计算出(标准化的)方向向量与目标位移向量之间的标量积(Target - Object / | Target - Object |)。

当标量积变为零时,您的目标方向将垂直于您的方向,从而形成圆形轨迹**。当目标落入青色区域时,您可以反转方向,以便将其放置在无法到达的区域之外并重新定位。

*老实说,这不是圆锥体……是另一条直纹曲面,它是由两条不平行的线绕经过相交点并垂直于等分线的轴(半)旋转(生成)生成的;在2D平面上的投影与双圆锥相同,但旋转轴垂直于生成圆锥的那个。

**该轨迹不太可能是圆形,椭圆形甚至封闭的。轨迹可能会像二维(甚至二维)中的其他怪物一样沿着像轨迹描记器(下摆线)那样的呼吸描记器运动。无论如何,您都无法到达这些曲线的中心,它们看起来像是圆形的“圆形”轨迹。


+1对于将导弹的加速度矢量限制为垂直于行进方向的情况,是个不错的主意。我认为这不是事实。
Martin Sojka

@Martin Sojka甚至可以将加速度矢量分解为两个分量,一个是径向的,另一个是与方向相切的。第一个告诉你可以转动多少,第二个告诉你可以加速/减速。
FxIII 2011年

1
是的,如果您可以自由选择彼此的相对强度(即,如果加速度矢量的方向和强度与运动矢量无关),则“排除圆”将消失。
Martin Sojka

@Martin Sojka加速度强度没有限制吗?
FxIII 2011年

1
+1太酷了。我以前从未想过。我可能会尝试将其与@Matin的答案结合使用
John McDonald

8

您的制导系统是基于这样的假设,即直接朝目标加速会最终导致物体碰撞。由于该假设是错误的,因此基于该假设的指导AI也是不成功的。

因此,停止直接朝目标加速。添加一些逻辑以检测目标的位置是否与导弹的运动方向垂直。如果是这样,则导弹需要朝目标加速,但也要减慢其前进速度。因此,它不会直接朝向目标,而是会偏向其加速方向,从而使当前沿其运动方向的速度变慢。

另外,您将需要一个触发器来确保您不会太慢。因此,请增加一些阈值速度,以便在该阈值以下时停止进行偏置。

最后一件事:没有任何指导系统会是完美的。导弹可以拦截现实生活中的目标的原因是,目标的移动速度比导弹本身慢得多,而且目标并不是特别灵活(相对而言)。如果您的导弹不会比追逐的目标快很多倍,那么它们会错过很多。


2
“目标不是特别灵活” .. 不是吗?
bobobobo 2012年

5

在游戏(和现实生活)中,最简单,最先进的方法是比例导航。

在“恒定轴承减小范围(CBDR)”逻辑下,当两个物体(导弹和目标)沿相同方向行进而彼此之间的视线不变时,它们发生碰撞。

视线或视线(LOS)是导弹与目标之间的假想线-导弹位置与目标位置之间的向量。此LOS的角度变化率就是LOS旋转率。

当“ LOS旋转速率”变为零时,视线不再更改-两个对象现在处于碰撞路线上。想想自己就是在踢足球/足球时追逐某人。如果您以某种方式带领他在您的视野中看起来“冻结”(您和他之间的视线不再改变),则您将与他发生碰撞,只要您保持跑步的速度以保持他的身体在冰冻状态下就保持冻结。您的看法。

在比例导航(PN)下,导弹的加速度比LOS旋转速率快“ N”倍。这将迫使导弹引导目标直到LOS旋转速率变为零-也就是说,由于视线不再改变,导弹和目标似乎处于冻结状态,它们现在处于碰撞过程中。变量“ N”称为导航常数(常数乘数)。

导弹的制导命令应如下所示:

加速度=闭合速度* N * LOS速率

通过测量LOS向量(目标位置-导弹位置)并存储其变量,可以轻松得出LOS率。新帧(LOS1)的LOS向量被旧帧(LOS0)的LOS向量减去,生成LOS增量-现在您有了原始LOS旋转速率。

为了简化“闭合速度”,您可以仅使用当前的LOS向量,从而:

加速度=(target_pos-missile_pos)* LOS_delta * N

N是导航常数-在现实世界中,通常将其设置为3到5之间,但游戏中的实际可行数字在一定程度上取决于推算LOS率/增量的采样率。尝试一个随机数(从3开始)并增加到1500、2000等,直到在游戏中看到所需的领先效果为止。请注意,导航常数越高,导弹在飞行初期对LOS频率变化的反应越快。如果您的寻的火箭仿真模型有些现实,那么过大的导航常数可能会使导弹的空气动力学能力超负荷,因此您应该根据试验和错误使用均衡的数值。


4

正如Martin和Nicol的其他回答所指出的那样,您可能不希望直接将导弹引导至目标,而是以某种方式使其稍后与目标碰撞。但是,马丁描述的方法很复杂,而尼科尔描述的方法效率低下。

引导导弹的一种更简单但有效的方法是根据导弹与目标之间的角度变化来调整其角度。在每个刻度上,您都会计算出导弹与目标之间的角度,并将其与上一个刻度之间的角度进行比较。区别在于您要对导弹的角度进行精确的区别。因此,如果一个刻度的角度为0.77,而下一刻度的角度为0.75,则您希望将导弹的角度调整为-0.02。这种方法很简单,只要目标在导弹的“前方”,就选择的路线而言,它就非常有效。它也适用于任意数量的尺寸,而不仅仅是二维尺寸。

但是请记住:

  • 如果导弹和目标物以完全相同的速度并平行行进,则此方法会中断。嗯,理论上它仍然为导弹绘制了一个碰撞过程,只需要花费无限的时间:)实际上,导弹应该总是比目标快,但是如果它们具有相同的速度,则需要添加一个角壳来确定它们是否平行。

  • 如果目标和导弹正好在同一条直线上,却在相反的方向飞行,则该方法就会中断。在现实世界中这不可能真的发生,但在离散游戏中并不少见。您需要在上述算法中添加特殊情况检查以进行测试。

  • 如果您的导弹的转弯能力有限,那么只要每次转弯都需要使其超过最大转弯数即可。只要导弹足够远,它仍然可以工作。如果距离太近,请参阅最后一个项目符号。

  • 检查碰撞时,切记要宽大。在现实世界中,许多导弹都依靠弹头产生“杀伤区”,因此它们只需要靠近目标,而不必与目标相撞。

  • 最后,在实践中,导弹可能仍会错过,这使我们回到了您的原始问题。我认为一种好方法是确实禁用归位几秒钟,使其达到一定距离,然后再次使其归位。我认为fxiii提出的识别死区的方法是检测何时需要关闭归位的好方法。


1

对于我过去开发的游戏,发现有两个简单的选项“足够好”:

1)如果您正在查看的场景的分辨率允许它,那么当物体靠近目标时,该物体可能会爆炸(这就是我认为大多数情况下日间归巢导弹在任何情况下都能实际起作用的方式)。如果您的轨道范围大约是物体的两倍大小,那么这对您可能不起作用,因为它最终看起来会很糟糕。

如果您解决方案的最终目标只是确保导弹能够击中目标,那么我全力以赴使其达到目标。同样,这将仅取决于解决方案的外观。

2)如果您发现导弹与目标成直角,则可能是锁“断裂”的地方,除非目标再次回到导弹前方,否则导弹只会直线移动。

我总是尽可能地选择简单的解决方案。如果您正在做的游戏中,归巢导弹只是所使用的武器之一,那么您可能会逃脱这些攻击,因为玩家可能会发射齐射,然后尽快换回其持续接触的武器。但是,如果您要进行导弹仿真,那么显然其他选择是更好的选择。

希望这可以帮助。


0

如前所述,您应该将导弹对准到达目标时预期的目标位置,而不是现在的目标位置。这将阻止MOST导弹进入轨道,但如果目标恰好逃避,仍然可以进入轨道。这是飞机飞行员用来躲避进来导弹的合法策略-因为导弹的飞行速度比您快得多,所以它将具有更大的转弯半径,并且在正确的瞬间出现尖锐的颠簸会使其继续前进。(尽管您仍可能会受到邻近爆炸的威胁。)

由于我们正在处理的导弹仍可跟踪并仍具有推力,因此,如果目标躲避到FxIII哨所谈论的区域之一,您将进入轨道状态。

但是,我不同意他对这个问题的解决方案。相反,我将对导弹进行编程:

如果导弹一直以90度向其运动线推进360度运动,那么您就在轨道上。将推力从运动线调整到120度。导弹的轨道将变宽,因为它的旋转不那么困难,但导弹也将变慢,从而使其机动性更好。当目标范围打开到死区直径的1.25倍时(请注意,该直径仅基于导弹的速度,在运行时无需复杂的计算即可),导弹恢复其正常的跟踪行为。

或者,使用笨拙的搜索头-当目标范围不再使您引爆时倒数。


0

我知道这是一个古老的问题,但是我认为到目前为止给出的答案中缺少一些东西。在最初的问题中,导弹(或任何其他物体)被告知要加速向目标位置前进。有几个答案指出这是错误的,您应该在以后的某个时间加快目标速度。这更好,但仍然是错误的。

您真正想做的不是加速朝目标前进,而是朝着目标前进。考虑这一点的方法是将所需的速度指向目标(或目标位置的投影),然后找出最适合的加速度(给定任何限制,即导弹可能无法加速)直接相反)以达到您想要的速度(记住速度是一个向量)。

这是我今天早上实施的一个有效示例,以我在体育模拟游戏中针对玩家AI的情况为例,该玩家试图追赶对手。该运动由标准的“踢球漂移”模型控制,该模型在时间步的开始处应用加速度以更新速度,然后对象在该时间步的持续时间内以该速度漂移。

我会发布它的派生词,但我发现此网站上不支持数学标记。!您只需要相信这是最佳解决方案,因为我对加速度方向没有限制,而对于导弹类型的对象则不是这样,因此需要一些额外的约束。

代码在python中,但是在任何语言背景下均应可读。为简单起见,我假设每个时间步长为1,并以适当的单位表示速度和加速度以反映这一点。

self.x = # current x co-ordinate
self.y = # current y co-ordinate
self.angle = # current angle of motion
self.current_speed = # current magnitude of the velocity
self.acc # Maximum acceleration player can exert on themselves
target_x = # x co-ordinate of target position or projection of it
target_y = # y co-ordinate of target position or projection of it
vx = self.current_speed * math.cos(self.angle) # current velocity x component
vy = self.current_speed * math.sin(self.angle) # current velocity y component
# Find best direction to accelerate
acc_angle = math.atan2(self.x + vx - target_x,self.y + vy - target_y)

请注意,atan2(a,b)函数计算a / b的反正切值,但要确保角度位于圆的正确象限中,这需要知道a和b的符号。

就我而言,一旦获得加速度,便应用该加速度来更新速度

vx_new = vx + self.acc * math.cos(acc_angle)
vy_new = vy + self.acc * math.sin(acc_angle)
self.current_speed = math.sqrt( vx_new**2 + vy_new**2)
self.angle = math.atan2(vy_new,vx_new)

我还会根据玩家的最大速度检查新速度,并以此为上限。如果是导弹,汽车或具有最大转弯速度(单位为每跳的度数)的物体,您可以简单地查看当前运动角度与计算得出的理想值之间的关系,如果此变化幅度大于允许值,只需将角度更改为尽可能地走向理想。

对于任何对此推导感兴趣的人,我都会在进行了最后一步之后写下玩家与目标之间的距离,包括初始位置,速度,加速速率和加速角,然后针对加速角取导数。将该值设置为零可找到时间步后玩家目标距离的最小值,该最小值是加速度角的函数,这正是我们想要知道的。有趣的是,即使加速度最初是方程式中的,它也抵消了使最佳方向独立于您实际能够加速的速度。


在某些情况下,我几乎建议直接设置速度-尽管很难与主要依赖于力的物理系统集成。如果这是一个定期发射导弹的游戏,而“躲避”不是一个著名的游戏机制,那么您可能要避免物理干扰的小风险,并确保该机制能够按照玩家的预期运行每次。例如,在RTS中,这可能比太空动作游戏更有意义。
Katana314 2013年

0

您正在使用恒定的转弯速率。这正是造成完美的完美圆形轨道的原因。

对于制导系统,更现实的方法是改变转弯速率,使其与目标距离成反比(距离越短,转弯速率越大)。这将产生螺旋而不是轨道,并确保与较慢的目标发生碰撞。

它还提供了更为现实的飞行路径。恒定的转弯速度自然是完美的。您还可以将随机变化添加到转弯速率中以模拟湍流。再次,更加现实,并且实际上可以避免稳态轨道运行情况。

无需偏方程。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.