如何以圆周运动拦截对象


23

我正在创建2D太空游戏,需要使飞船拦截一颗行星。我有用于直线截距的工作代码,但无法弄清楚如何计算圆形轨道上的行星位置。

该游戏在科学上不够准确,因此我不必担心惯性,重力,椭圆轨道等。

我知道太空飞船的位置和速度,也知道行星的轨道(半径)和速度

在此处输入图片说明


1
不,我正在尝试计算船舶为了拦截行星而需要移动的角度。
2014年

4
这可能在math.stackexchange.com中会更好地工作。–
Jari Komppa

2
您的船能改变速度和方向吗?还是保持不变?同样,关于避免导弹绕过目标的这个问题可能会有所帮助。
thegrinner

4
澄清一下,情况呢?给定的行星:轨道中心,轨道半径,角速度,当前位置;对于船舶:当前位置,当前速度;确定船的运动方向以拦截行星
AakashM 2014年

6
作为一个有趣的历史注释:行星通常沿与轨道相同的方向旋转,因此从北半球上方看时,行星的旋转方向也是逆时针方向。根据这一事实,我们可以推断出日sun是在北半球发明的。如果在南半球发明了日di,那么顺时针将是一种方式。
埃里克·利珀特

Answers:


3

对此的解析解决方案很困难,但是我们可以使用二进制搜索来找到所需精度范围内的解决方案。

船舶可以在时间t_min到达轨道上的最近点:

shipOrbitRadius = (ship.position - planet.orbitCenter).length;
shortestDistance = abs(shipOrbitRadius - planet.orbitRadius);
t_min = shortestDistance/ship.maxSpeed;

船舶可以在小于或等于t_max的时间内到达轨道上的任何一点:

(在这里,为简单起见,我假设这艘船可以在阳光下行驶。如果要避免这种情况,那么至少在某些情况下,您将需要切换到非直线路径。“接环”可能看起来不错并且在轨道上力学y,而算法的更改不会超过一个常数因子)

if(shipOrbitRadius > planet.orbitRadius)
{
   t_max = planet.orbitRadius * 2/ship.maxSpeed + t_min;
}
else
{
   t_max = planet.orbitRadius * 2/ship.maxSpeed - t_min;
}

如果我们的轨道周期很短,我们也许可以通过选择,使它在行星最接近船的起始位置t_max之后的第一次来提高这个上限t_min。取这两个值中t_max的较小者。请参阅后面的答案,以了解其工作原理。

现在我们可以在这些极端t_mint_max之间使用二进制搜索。我们将搜索误差接近零的t值:

error = (planet.positionAtTime(t) - ship.position).squareMagnitude/(ship.maxSpeed*ship.maxSpeed) - t*t;

(使用这种构造,错误@ t_min> = 0且错误@ t_max <= 0,因此对于中间的t值,必须至少有一个截距,错误= 0)

为了完整起见,位置函数类似于...

Vector2 Planet.positionAtTime(float t)
{
  angle = atan2(startPosition - orbitCenter) + t * orbitalSpeedInRadians;
  return new Vector2(cos(angle), sin(angle)) * orbitRadius + orbitCenter;
}

请注意,如果行星的轨道周期与船舶的速度相比非常短,则此误差函数可能会在从t_min到t_max的跨度内多次改变符号。只需跟踪您遇到的最早的+ ve和-ve对,然后继续在它们之间进行搜索,直到误差足够接近于零(“足够接近”对您的单位和游戏环境敏感)即可。运作良好-确保截取准确到一帧之内)

一旦有了一个使误差最小的t,就可以将飞船指向planet.positionAtTime(t)并全开油门,确信行星会在您同时达到该点。

您始终可以在Log_2((2 * orbitRadius / ship.maxSpeed)/ errorThreshold)迭代中找到解决方案。因此,例如,如果我的飞船可以在60帧内横越轨道,并且我希望截距精确到一帧内,那么我将需要进行大约6次迭代。


1
这里有很多很好的答案,还有一些有趣的替代选项,但是从我已经拥有的解决方案来看,这对于我的实例而言是最好的。我为结果创建了一个JavaScript演示。演示
Ausa

11

让我们不要过于复杂。这不是一个“完美”的解决方案,但适用于大多数游戏,并且任何瑕疵对于玩家来说都是不可见的。

if(!OldTargetPoint)
  TargetPoint = PlanetPosition;
else
  TargetPoint = OldTargetPoint;
Distance = CurPosition - TargetPoint;
TimeNeeded = Distance / Speed;
TargetPoint = PlanetPositionInFuture(TimeNeeded);
SteerTowards(TargetPoint);
[...repeat this every AI update, for example every second...]
  1. 计算到达目标点所需的时间。
  2. 计算在计算的时间行星将位于什么位置。
  3. 向计算点移动。
  4. 重复

之所以起作用,是因为航天器越接近误差越小。因此,随着时间的推移,计算变得更加稳定。

误差是计算出的到达行星所需时间(TimeNeeded)与到达行星所需的实际时间(在考虑了新的TargetPoint之后)之间的差。


1
您可能希望在开始拦截过程时进行两次这样的迭代,否则您可能会看到飞船在两个方向之间短暂闪烁(第二个猜测可能比第一个猜测要好得多,并且导致航向大不相同-特别是如果该船接近或位于行星的轨道内)
DMGregory

1
@DMGregory哦!我们可以仅以当前的行星位置而不是轨道中心作为起点。当我们靠近时,距离就近了,如果我们离得远,那就没关系。
API-Beast

还值得注意的是,与行星相比,当行星缓慢移动时,这效果最好。如果行星的速度等于或大于船舶的速度,则可能会在船舶的路径中看到振荡。以病理速度比,飞船可以在同心轨道上永远追逐行星。如果您的行星运行很快,并且您注意到了这种情况,那么您可能需要预先计划整个拦截过程,而不是在飞行途中进行迭代。
DMGregory

3

让我们从问题背后的数学开始。

步骤1:

找到直线和形状之间的交点,只需将直线的方程式插入形状方程式中即可,在这种情况下为圆形。

线与圆相交

取一个中心为c且半径为r的圆。如果点p在圆上

|pc|2=r2

p=p0+μv

|p0+μvc|2=r2

平方距离可以重写为点积(http://en.wikipedia.org/wiki/Dot_product)。

(p0+μvc)(p0+μvc)=r2

a=cp0(μva)(μva)=r2

μ2(vv)2μ(av)+aa=r2

|v|=1

μ22μ(av)+|a|2r2=0

这是一个简单的二次方程,我们得出解

μ=av+sqrt((av)2a2r2)

μ<0

μ=0

μ

第2步:

μ

我们该怎么办?好了,我们现在知道了船的航行距离以及它将到达的终点!

p=p0+μvμv

现在,剩下要做的就是计算当船开始驶向轨道时行星应该在哪里。这可以通过所谓的Polar coodinateshttp://mathworld.wolfram.com/PolarCoordinates.html)轻松计算。

x=c+rcos(θ)

y=c+rsin(θ)

tangularVelocity

摘要

为您的飞船选择一条直线,然后运行数学运算以查看其是否与行星轨道发生碰撞。如果是这样,请计算到达该点所需的时间。利用这段时间从该点开始从行星返回轨道,以计算飞船开始移动时行星应位于的位置。


8
很好的分析,但似乎并不能回答问题(在评论中得到澄清):“不,我正在尝试计算船舶为了拦截行星而需要移动的角度。” 您将船的角度作为给定并计算行星的位置,而不是相反。
Chaosed0 2014年

4
因为它是有用的分析,所以不会拒绝它,但是我同意@ Chaosed0,它不能回答问题。在您的摘要中,您说“为您的船选择一条线...”,但是选择那条线恰恰是​​困难的部分。
德雷克

1

这里有两个“开箱即用”的解决方案。

问题是:给定船舶以给定速度沿直线运动,行星以给定角速度沿给定半径的圆运动,并且行星和船舶的起始位置确定了船舶的方向矢量直线应位于绘制拦截路线。

解决方案一:否认问题的前提。问题中“可滑动”的数量是角度。相反,请解决该问题。将飞船直指轨道中心。

  • 计算船与行星相遇的位置;这很简单。
  • 计算从船到拦截位置的距离; 也容易。
  • 计算直到下一个行星到达拦截位置所需的时间。简单。
  • 用从飞船到拦截器的距离除以直到行星到达拦截器的时间。
  • 如果该速度小于或等于船的最大速度,那么您就完成了。使船以该速度直行向太阳。
  • 否则,将行星的轨道周期添加到该时间,然后重试。继续这样做,直到您的船速达到合理范围为止。

解决方案二:完全不使用自动驾驶仪。制作一个微型游戏,玩家必须使用推进器来接近该行星,如果以相对较高的速度撞击该行星,它们会炸毁,但燃料也有限。让玩家学习如何解决拦截问题!


1

如果您不想使用极坐标,请考虑船舶的所有可能位置在形成圆锥(x,y,t) space. The equation for this is

tv=x2+y2

where v is the the ship velocity. It is assumed the ship starts at zero.

The position of the planet in space and time can be parametrized by e.g.

x=x0+rcos(wu+a)y=y0+rsin(wu+a)t=u

where u goes from 0 upwards. w is the angular speed and a is the starting angle of the planet at time zero. Then solve where the ship and planet could meet in time and space. You get an equation for u to solve:

uv=(x0+rcos(wu+a))2+(y0+rsin(wu+a))2u2v2=(x0+rcos(wu+a))2+(y0+rsin(wu+a))2u2v2=x02+y02+r2+2x0rcos(wu+a)+2y0rsin(wu+a)

This equation needs to be solved numerically. It may have many solutions. By eyeballing it, it seems it always has a solution


1

Here's part of a solution. I didn't get to finish it in time. I'll try again later.

If I understand correctly, you have a planet's position & velocity, as well as a ship's position and speed. You want to get the ship's movement direction. I'm assuming the ship's and planet's speeds are constant. I also assume, without loss of generality, that the ship is at (0,0); to do this, subtract the ship's position from the planet's, and add the ship's position back onto the result of the operation described below.

Unfortunately, without latex, I can't format this answer very well, but we'll attempt to make do. Let:

  • s_s = the ship's speed (s_s.x, s_s.y, likewise)
  • s_a = the ship's bearing (angle of movement, what we want to calculate)
  • p_p = the planet's initial position, global coords
  • p_r = the planet's distance (radius) from the center of orbit, derivable from p_p
  • p_a = the planet's initial angle in radians, relative to the center of orbit
  • p_s = the planet's angular velocity (rad/sec)
  • t = the time to collision (this turns out to be something we must calculate as well)

Here's the equations for the position of the two bodies, broken down into components:

ship.x = s_s.x * t * cos(s_a)
ship.y = s_s.y * t * sin(s_a)

planet.x = p_r * cos(p_a + p_s * t) + p_p.x
planet.y = p_r * sin(p_a + p_s * t) + p_p.y

Since we want ship.x = planet.x and ship.y = planet.y at some instant t, we obtain this equation (the y case is nearly symmetrical):

   s_s.x * t * cos(s_a) = p_r * cos(p_a + p_s * t) + p_p.x
   s_s.y * t * sin(s_a) = p_r * sin(p_a + p_s * t) + p_p.y

Solving the top equation for s_a:

   s_s.x * t * cos(s_a) = p_r * cos(p_a + p_s * t) + p_p.x
=> s_a = arccos((p_r * cos(p_a + p_s * t) + p_p.x) / (s_s.x * t))

Substituting this into the second equation results in a fairly terrifying equation that Wolfram alpha won't solve for me. There may be a better way to do this not involving polar coordinates. If anyone wants to give this method a shot, you're welcome to it; I've made this a wiki. Otherwise, you may want to take this to the Math StackExchange.


2
I would love to have TeX enabled for this site. It would make some graphics related stuff (e.g. vector, matrices, quaternions..) easier to represent.
mvw

0

I would fix the location at which to intercept (graze the circle, at the "outgoing" side of the orbit.)

Now you just have to adjust the spaceship's speed so that planet and ship reach that point at the same time.

Note that the rendez-vous could be after N more orbits, depending how far away the ship is, and how fast the planet is orbiting the star.

Pick the N that in time, comes nearest to the ship's journey duration at current speed.

Then speed up or slow down ship to match the timestamp for those N orbits exactly.

In all this, the actual course is already known! Just not the speed.


This could give unnecessarily long trips. Let's say we're positioned so that the planet is coming toward us and we can actually reach the "incoming" grazing point at the same time the planet does. If we're only looking at the "outgoing" grazing point, then we could end up spending half an extra half a year in transit!
DMGregory

True... depends on orbital speeds. But it also minimizes the delta-speed if you always graze at outgoing. At "incoming" you could burn up in the atmosphere, whereas in "outgoing" you are more likely to be matched. @DMGregory
Bram
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.