如何在2D中预测船舶与物体影响球体之间的相遇?

17
长期听众,第一次来电。我正在使用XNA制作一个小型休闲游戏,它涉及到太空中的运输船,类比于海上的集装箱船。我需要能够在限制的二维环境中预测船和星球/卫星引力势区之间的相遇。船和行星/卫星,简称为物体,的位置是根据开普勒轨道要素确定的。船和物体都绕着同一个引力中心运动。
到目前为止,我想出的方法是首先对近地点和远地点(距离引力中心最远和最近的点)进行一些初步检查,以查看是否可能发生相遇。在这样的检查和如果船的轨道是开放的(双曲线的情况下,我将把抛物线近似为双曲线),可以排除许多不可能有相遇的情况。
如果这些检查确定可能发生相遇,我会确定飞船与引力中心的最小和最大距离,然后获取飞船轨道与由该最小和最大定义的两个圆的交点。这将在飞船轨道上定义零、一个或两个时期,其中它可能会遇到该天体的球体,从而得到零、两个或四个点。此时,如果没有交点,则可能整个飞船轨道都在相遇区域内,这可能是一种不常见的极端情况,但需要进行处理。
我可以获得飞船通过其轨道上的那些点的时间,为相遇检查提供一个或两个时间窗口,但从那里开始,我最好的解决方案是将时间跨度划分为步骤进行搜索,计算那些时间点上的天体位置,然后测试是否相遇。
这种方法的问题在于,知道要采取多大的步骤才能有效地找到相遇。获取时间点上的天体位置有些昂贵,因此我希望尽可能少地执行此操作,但步长过大可能会错过相遇。
有关共焦圆锥形状的任何属性可以帮助减少搜索空间吗?或者是否有其他方法来预测实际上沿着圆锥路径移动的点与沿着共享焦点的椭圆形移动的圆之间的相遇/碰撞?

既然你在谈论重力和旋转,那么你应该看看Osmos。 - ElKamina
集成很好,但能够选择任何时间点(过去或未来),并确定行星/飞船的位置(除了与其他物体的相遇)更好。 Kepler的二体情况是完全确定性和可预测的。它的成本很高,因为你必须解决Kepler's Equation,它可能不会成为最昂贵的函数,但我确实打算让许多实体使用它,即使我不关心成本问题,也有检查间隔的问题。您不希望在跳跃范围很大的情况下进行搜索,以免错过相遇。 - pagnatious
@neontapir 我还没有,但可能应该这么做。我在这里提问是因为这里有更多的人口,而且问题不仅限于游戏领域。他们很可能有一些见解,我应该在那里发帖。 - pagnatious
我在你的个人资料页面上看不到你的电子邮件,但我认为我的电子邮件列在了我的个人资料上。 - pagnatious
那么,你解决问题了吗?你的游戏呢,已经移动到逻辑结尾了吗?有没有机会看到结果? - Victor
显示剩余11条评论
3个回答

1
使用径向碰撞检测(圆形),一个圆表示行星的重力影响(比行星本身更大),每艘船都有另一个圆,当两个圆心逐渐靠近时,导致每个圆心沿直线轻微移动。将每个圆的拉力量应用于每艘船的运动速率上。运动可以通过简单的三角函数完成,x轴使用cos(),y轴使用sin(),不需要任何更复杂的数学计算。当任意两个物体之间的距离小于它们半径之和时,则发生碰撞。
但是,在仅对“引力圆”进行此种形式的碰撞时,当它们碰撞时,您可以在每次迭代中增加船的速度一小部分,以模拟引力的作用。

我不确定我理解你的建议。当然,它们都可以用圆表示,行星的影响在我的二维情况下是一个圆,但我不明白“彼此靠近...随着距离减小而微微移动”的部分?然后,您似乎解释了一种在圆形运动中模拟重力的方法?只使用cos和sin?我目前没有问题模拟重力,这不是问题的关键。 - pagnatious
我试图回答你的问题,“或者还有其他方法来预测实际上沿着圆锥路径移动的点和沿着共享一个焦点的椭圆移动的圆之间的相遇/碰撞吗?”也许不是你想要的方法,但“爱好游戏”这个术语让我相信你可能会考虑一个更直接的建议而不是一个复杂的建议。在二维空间中,圆锥形真的是描述引力拉力的最好词汇吗?它更像是螺旋运动。 - Jon Harbour
不,锥形体可以是二维和三维的。开普勒在展示它方面做得比我好。如果飞船除了来自引力的加速度外还提供了自身的加速度,它也可能是螺旋形的。尽管这可能主要是一种兴趣爱好,但我的目标是尽可能地模拟天体力学。 - pagnatious

1
你可以尝试构建一个函数来描述行星和飞船之间距离(的平方)随时间变化的情况,使用通常的毕达哥拉斯距离公式。寻找这个函数的零点,所以可以使用牛顿法或类似方法来找到它们。
只要行星的运动比飞船慢得多,这种方法应该能很好地工作——然后函数将相对平滑,牛顿法将没有问题地收敛。但是如果行星的运动比飞船快得多,则此距离函数将像“弹簧”一样上下弹动,叠加在某些抛物线状的曲线上,并可能与x轴相交多次。牛顿法在这种导数方向迅速变化的函数上可能会出现问题。
希望在构建距离函数时,一些术语可以抵消,或者表达式可以被简化或近似,但如果不能,可能足以在垂直和水平方向上寻找零点。(事实上,您可以选择沿任何轴线的距离-例如行星轨道的主轴。)这些函数中的任何一个零点都是碰撞的必要条件,但不足以保证碰撞,并且可能更容易计算。如果您有按时间排序的x方向零点列表,并且同样适用于y方向零点,则可以通过计算它们与列表合并(类似于归并排序)的交点来找到任何真实碰撞。

那个函数中的零点将是飞船拦截行星中心的点吗?我将寻找距离(平方)等于影响半径(平方)的函数上的点。对于在系统中旅行的飞船(例如从月球(或更高)到低地球轨道站),目标可能会绕行数次,从而产生这种弹簧效应。此外,牛顿法已经用于获取每个物体在时间上的位置,这意味着您不能制作一个表示两者之间随时间变化的距离的函数? - pagnatious
我在建模距离时过于简化了,将其视为两点之间的距离;如果“引力影响范围”是一个球体(即2D中的圆),那么我们实际想要计算的距离是一个点(飞船)与一个圆(GSI)之间的最短距离。幸运的是,这只是一个非常简单的调整:只需从行星中心到飞船的距离中减去GSI的半径!:)(当飞船位于GSI内部时,这将给出一个“有符号”的距离,但我们不关心,因为我们只寻找零点。)很抱歉,我不明白你的最后一句话。 - j_random_hacker
要得到行星和飞船之间随时间变化的距离函数,你需要类似于f(t) = s(t) - p(t)这样的公式,而且正如你所说,希望项会相互抵消。在获取位置时,你需要真近点角,为了在某个时间获得它,你需要从平近点角中获取偏心近点角(这是轨道唯一随时间一致变化的方面)。偏心近点角的方程是M = E - e*sin(E),它没有一个封闭形式的解。因此,对于每个s(t)和p(t),你需要数值求解该方程,因此我不知道你如何定义f(t)。 - pagnatious

0

由于此问题尚未得到采纳的答案,并且我没有看到以下的计算,因此我希望添加这些内容,以帮助某些人。 我还没有弄清楚如何获得日期时间,但我已经知道了如何获取角度。 如果您知道角度,这将使您获得轨道体与SOI(或船只)之间的距离:

public static double RadiusAtAngle(double angle, double semiLatusRectum, double eccentricity)
{
    return semiLatusRectum / (1 + eccentricity * Math.Cos(angle)); 
}

更重要的是,如果您知道半准线和离心率(这里的半径将是从物体到soi边缘的距离),翻转该计算可以得到您到达soi边缘的角度:
public static double AngleAtRadus(double radius, double semiLatusRectum, double eccentricity)
{
    //r = p / (1 + e * cos(θ))
    //1 + e * cos(θ) = p/r
    //((p / r) -1) / e = cos(θ)
    return Math.Acos((semiLatusRectum / radius - 1) / eccentricity);
}

作为参考,半通径可以从半长轴和离心率中找到:

public static double SemiLatusRectum(double SemiMajorAxis, double eccentricity)
{
    if (eccentricity == 0)//ie a circle 
        return SemiMajorAxis;
    return SemiMajorAxis * (1 - eccentricity * eccentricity);
}

请注意,这些计算也适用于双曲线轨迹。

我曾经就同一个问题提出了不同的问题,并在这里得到了答案:https://stackoverflow.com/questions/16501182/find-first-root-of-a-black-box-function-or-any-negative-value-of-same-function我从未真正将其制作成游戏,但是遭遇预测逻辑在我的所有测试中都表现良好。可能无法在游戏帧期间廉价运行,从未走得太远以确定这一点。我仍计划整理它并在线发布,但生活一直在阻碍我。 - pagnatious
有趣,如果您还有C#的转换代码,我很乐意看一看,pastbin链接已经失效了。 - se5a
上次有人询问时,我发布的 pastebin 已经过期了。我应该在适当的地方重新发布它。 - pagnatious

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接