17

长期聆听者,第一次来电者。我正在 XNA 中制作一个小游戏,关于太空中的运输船,类似于海上的集装箱船。我需要能够在受限的 2D 环境中预测船与行星/卫星引力影响范围之间的相遇。船和行星/月球的位置,简称体,由开普勒轨道元素确定。Ship 和 Body 都围绕同一个吸引中心运行。

到目前为止,我设计的方法是首先对远点和近点(距吸引力中心最远和最近的点)进行一些初步检查,看看是否有可能相遇。在这样的检查之间,如果船舶的轨道是开放的(双曲线,我将抛物线情况近似为双曲线),它可以排除许多不可能遇到的情况。

如果这些检查确定可能发生相遇,我将确定船舶有资格发生相遇的距吸引力中心的最小和最大距离。然后我得到船舶轨道与由最小值和最大值定义的两个圆的交点。这会在飞船的轨道上产生零个、两个或四个点,定义零个、一个或两个周期,在这些点上它可能会遇到身体的球体。在这一点上,如果有零个交叉点,则整个船舶轨道可能都在相遇区,这可能是一个不常见的极端情况,但需要被覆盖。

我可以得到船将通过其轨道上的这些点的时间,给一两个时间窗口来检查相遇,但从那里我最好的解决方案是通过将时间跨度划分为步骤来搜索时间跨度,计算身体的位置那些时候,然后测试遇到。

这种方法的问题在于知道有效找到相遇的步骤的大小。及时获取 Body 的位置有点贵,所以我宁愿尽量少做,但步数太大可能会错过遭遇。

共焦圆锥形状是否有任何特性可以帮助减少搜索空间?或者是否有其他方法可以预测沿圆锥路径移动的点和沿共享焦点的椭圆移动的圆之间的相遇/碰撞。

4

3 回答 3

1

您可以尝试使用通常的毕达哥拉斯距离表达式构建将行星与船之间的(平方)距离描述为时间函数的函数。您正在寻找此函数的零点,因此可以应用牛顿法或类似方法来找到它们。

如果行星的运动比船的运动慢得多,这应该可以很好地工作——那么函数将相对平滑,并且牛顿的方法不会有收敛的问题。但是,如果行星的运动速度比船快得多,那么这个距离函数就会上下反弹,就像一个“弹簧”叠加在一些抛物线状的曲线上,并可能与 x 轴相交数次。牛顿法在处理此类函数时可能会遇到问题,因为导数会迅速改变方向。

希望在您构造距离函数时某些项会被抵消,或者表达式可以以其他方式简化或近似,但如果不是,则在垂直和水平方向寻找零可能就足够了。(实际上,您可以选择沿任何轴的距离——例如行星轨道的长轴。)这些函数中的任何一个中的零点都是碰撞的必要条件,但不是充分条件,并且可能更易于计算。如果您有一个按时间排序的 x 方向零的列表,并且对于 y 方向的零也相同,您可以通过使用列表合并(a la mergesort)计算它们的交集来找到任何真正的碰撞。

于 2013-03-15T03:48:06.590 回答
1

使用径向碰撞检测(圆圈),一个圆圈代表行星的重力影响(将大于行星本身),另一个圆圈代表每艘船,并使每个圆圈的中心点以直线相向移动随着距离的缩短,如此轻微。

将每个圆圈的拉力应用于每艘船的移动速度。只需简单的三角函数即可完成运动,x 为 cos(),y 为 sin(),无需任何更复杂的数学运算。当任何两个物体之间的距离小于它们的半径之和时,就会发生碰撞。

但是当只在“重力​​圈”上进行这种形式的碰撞时,可以说,当它们发生碰撞时,您可以在每次迭代时将船的速度增加一点,以模拟重力的拉力。

于 2013-03-14T21:09:10.630 回答
0

由于这还没有得到接受的答案,而且我没有看到下面的计算,我将添加这些以希望它对某人有所帮助。我还没有弄清楚如何获得日期时间,但是我已经弄清楚了如何获得角度。如果您知道角度,这将为您提供轨道体和 soi(或船)之间的距离:

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

更重要的是,如果您知道 semiLatusRectum 和偏心率(这里的半径将是从 body 到 soi 边缘的距离),则翻转该 calc 可以获得到 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);
}

作为参考,可以从 semiMajorAxis 和 eccentricity 中找到 semiLatusRectum:

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

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

于 2019-05-26T23:14:54.703 回答