如何预测船舶与船体在2D中的影响范围之间的相遇

时间:2013-02-22 17:05:42

标签: c# algorithm math collision-detection orbital-mechanics

长时间听众,第一次来电。我正在XNA做一个小爱好游戏,它关于太空中的运输船,类似于海上的集装箱船。我需要能够在受限制的2D环境中预测船舶与行星/卫星gravitational sphere of influence之间的相遇。船舶和行星/月球身体的位置,简称身体,由keplerian orbital elements确定。船体和船体都在同一个吸引中心运行。

我到目前为止设计的方法是首先对apoapsis和periapsis(距离吸引中心最远和最近的点)做一些初步检查,看看是否有可能遇到。在诸如此类的检查之间以及如果船舶的轨道是开放的(双曲线,我将抛物线情形近似为双曲线),它可以排除许多无法遇到的情况。

如果这些检查确定可能遇到相遇,我会确定该船舶有资格进行相遇的距离中心的最小和最大距离。然后我得到船舶轨道的交点与由该最小值和最大值定义的两个圆圈。这导致船舶轨道上的零点,两点或四点,定义零点,一点或两点,它可能遇到车身的球体。此时如果交叉点为零,则整个船舶轨道可能位于遭遇区域,这可能是一种不常见的极端情况,但需要进行覆盖。

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

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

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

3 个答案:

答案 0 :(得分:1)

使用径向碰撞检测(圆圈),其中一个圆圈代表行星的重力影响(将大于行星本身),另一个圆圈代表每艘船只,并使每个圆圈的中心点相互移动。距离越小,直线越小。

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

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

答案 1 :(得分:1)

您可以尝试使用通常的毕达哥拉斯距离表达式构建描述行星与船舶之间距离(​​方形)作为时间函数的函数。您正在寻找此功能的零,因此可以应用Newton's method或类似功能来查找它们。

如果行星的运动比船的运动慢得多,那么它应该可以正常工作 - 那么函数将相对平滑,牛顿的方法可以毫无困难地收敛。然而,如果行星的运动比船的运动快得多,则该距离函数将上下跳动,就像叠加在某条抛物线状曲线上的“弹簧”,并且可能会与x轴相交几次。牛顿的方法可能会遇到这样的函数问题,其中导数会快速改变方向。

希望在构造距离函数时某些术语将被取消,或者表达式可以以其他方式简化或近似,但如果不是,则在垂直和水平方向上查找零可能就足够了。 (实际上你可以选择沿着任何轴的距离 - 例如行星轨道的主轴。)这些函数中的任何一个零都是必要的但不是碰撞的充分条件,并且计算起来可能更简单。如果你有一个按时间排序的x方向零列表和y方向零相同的列表,你可以通过计算它们与列表合并(la mergesort)的交集来找到任何真正的碰撞。

答案 2 :(得分:0)

由于尚未得到公认的答案,并且我看不到以下计算方式,因此我将其添加,以希望对您有所帮助。 我还没有弄清楚如何获取约会时间,但是我却想出了如何获取角度。 如果您知道角度,这将为您提供轨道运行的物体与soi(或飞船)之间的距离:

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

更重要的是,如果您知道semiLatusRectum和偏心率(此处的半径将是从身体到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和偏心率中找到semiLatusRectum:

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

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