円運動でオブジェクトをインターセプトする方法


23

2D宇宙ゲームを作成していますが、宇宙船が惑星を妨害する必要があります。直線切片の作業コードはありますが、円軌道での惑星の位置の計算方法がわかりません。

ゲームは科学的に正確ではないので、慣性、重力、楕円軌道などについて心配していません。

宇宙船の位置と速度、そして惑星の軌道(半径)と速度も知っています。

ここに画像の説明を入力してください


1
いいえ、惑星をインターセプトするために船が移動する必要がある角度を計算しようとしています。
AUSA

4
これはおそらくmath.stackexchange.com ..に良い仕事でしょう
ヤリKomppa

2
あなたの船は速度と方向を変えることができますか、それとも一定ですか?また、ミサイルがターゲットを一周するのを避けることについてのこの質問は役に立つかもしれません。
thegrinner

4
明確にするために、状況は?惑星に与えられた:軌道中心、軌道半径、角速度、現在の位置。以下のための船舶:現在位置、現在の速度。惑星をインターセプトするための船の動きの方向を決定
AakashM

6
興味深い歴史的注記として、惑星は通常、軌道と同じ方向に回転します。したがって、惑星は北半球の上から見て反時計回りです。この事実から、北半球で日時計が発明されたと推測できます。南半球で日時計が発明された場合、時計回りは逆になります。
エリックリッパー

回答:


3

これに対する分析ソリューションは困難ですが、バイナリ検索を使用して、必要な精度内でソリューションを見つけることができます。

船は時間t_minで軌道上の最も近い点に到達できます。

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

船は、t_max以下の時間で軌道上の任意のポイントに到達できます。

(ここでは、簡単にするために、船は太陽を通り抜けることができると仮定します。これを避けたい場合は、少なくともいくつかの場合、非直線のパスに切り替える必要があります。 mechanics-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。これらの2つの値のうち、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値に対してerror = 0のインターセプトが少なくとも1つ必要です)

ここで、完全性のために、位置関数は次のようなものです...

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フレームで軌道を横断でき、1フレーム以内の正確な切片が必要な場合、約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
インターセプトコースを開始するときに、これを2回繰り返して実行することをお勧めします。そうしないと、船が2つの方向の間で瞬間的にちらつくことがあります(2番目の推測は1番目の推測よりもはるかに優れており、特に船が近くにまたは)地球の軌道内にある
DMGregory

1
@DMGregoryああ!開始点として、オービットセンターの代わりに、現在の惑星の位置を取ることができます。私たちが近くにいるとき、それははるかに近いものであり、私たちが遠くにいる場合、それは重要ではありません。
APIビースト

惑星が船に比べてゆっくりと動いているときにこれが最もうまく機能することも注目に値します。惑星の速度が船の速度と同等以上である場合、船の進路に振動が見られることがあります。病的な速度比で、船は同心円軌道上で永久に惑星を追いかけることができます。惑星が高速で、この現象が発生していることに気づいた場合は、飛行中に繰り返すのではなく、インターセプトコース全体を事前に計画することをお勧めします。
DMGregory

3

問題の背後にある数学を見てみましょう。

ステップ1:

直線と形状の交点を見つけることは、形状の方程式(この場合は円)に直線の方程式を挿入するだけです。

Line intersecting with circle

中心が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)と呼ばれるもので簡単に計算されます

バツ=c+rcosθ

y=c+rsnθ

tangあなたはlarVelocty

概要

船のラインを選択し、数学を実行して、惑星の軌道と衝突するかどうかを確認します。もしそうなら、そのポイントに到達するのにかかる時間を計算します。この時間を使用して、惑星とともにこの地点から軌道に戻り、船が移動し始めたときに惑星がどこにあるべきかを計算します。


8
良好な分析ですが、質問に答えているようには見えません(コメントで明確にされています):「いいえ、惑星を迎撃するために船が移動する必要がある角度を計算しようとしています。」船の角度を与えられたものとして取り、惑星の位置を計算していますが、その逆ではありません。
Chaosed0

4
これは有用な分析であるため、これに反対票を投じることはありませんが、質問に答えていないことは@ Chaosed0に同意します。要約では、「船のラインを選択してください...」と言いますが、そのラインを選択することはまさに難しい部分です。
ドレイク

1

以下に、わずかに「すぐに使える」2つのソリューションを示します。

問題は、船が与えられた速度で直線で動き、惑星が与えられた角速度で与えられた半径の円で動き、惑星と船の開始位置がどの方向ベクトルを決めるかを考えるとインターセプトコースをプロットするには直線が必要です。

解決策1:質問の前提を否定します。問題の「スリップ可能」な量は角度です。代わりに、それを修正してください。軌道の中心に船をまっすぐ向けます。

  • 船が惑星に遭遇する位置を計算します。簡単だ。
  • 船から迎撃位置までの距離を計算します。また簡単。
  • 次に惑星が迎撃位置に到達するまでにかかる時間を計算します。簡単です。
  • 惑星がインターセプトに到達するまでの時間で、船からインターセプトまでの距離を割ります。
  • これが船の最大速度以下であれば、完了です。その速度で太陽に向かって直進する船を設定します。
  • それ以外の場合は、惑星の軌道周期を時間に追加して再試行してください。あなたが船の理由の範囲内にある速度を得るまで、それを続けてください。

解決策2:自動操縦ではまったく行わないでください。プレイヤーがスラスタを使用して惑星に接近しなければならないミニゲームを作成し、相対速度が高すぎる場合は爆破しますが、燃料も限られています。プレイヤーにインターセプト問題の解決方法を学ばせましょう!


1

極座標を使用したくない場合は、船の可能なすべての位置が バツytスペース。この方程式は

tv=バツ2+y2

どこで vは船の速度です。船はゼロから始まると想定されています。

空間と時間における惑星の位置は、例えば

バツ=バツ0+rcoswあなたは+ay=y0+rsnwあなたは+at=あなたは

どこで あなたは から行く 0 上向き。 w は角速度であり、 a時間ゼロでの惑星の開始角度です。次に、船と惑星が時間と空間で出会う場所を解決します。次の方程式が得られますあなたは 解決する:

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.