Wie kann ich ein Objekt mit einer kreisenden Bewegung abfangen?

23

Ich erstelle ein 2D-Weltraumspiel und muss dafür sorgen, dass das Raumschiff einen Planeten abfängt. Ich habe Arbeitscode für geradlinige Abschnitte, kann aber nicht herausfinden, wie die Position der Planeten auf einer kreisförmigen Umlaufbahn berechnet wird.

Das Spiel ist wissenschaftlich nicht korrekt, daher mache ich mir keine Sorgen um Trägheit, Schwerkraft, elliptische Bahnen usw.

Ich kenne den Ort und die Geschwindigkeit der Raumschiffe sowie die Umlaufbahn (Radius) und die Geschwindigkeit der Planeten

Bildbeschreibung hier eingeben

Ausa
quelle
1
Nein, ich versuche den Winkel zu berechnen, den das Schiff benötigt, um den Planeten abzufangen.
Ausa
4
Dies würde wahrscheinlich in math.stackexchange.com besser funktionieren.
Jari Komppa
2
Kann Ihr Schiff Geschwindigkeit und Richtung ändern oder sind diese konstant? Auch diese Frage , wie man vermeiden kann, dass Raketen ein Ziel umkreisen, könnte hilfreich sein.
thegrinner
4
Um zu klären, ist die Situation? gegeben für den Planeten: Umlaufbahnmitte, Umlaufbahnradius, Winkelgeschwindigkeit, aktueller Standort; für das Schiff : aktueller Standort, aktuelle Geschwindigkeit; Bewegungsrichtung für das Schiff bestimmen , um den Planeten abzufangen
AakashM
6
Eine interessante historische Bemerkung: Planeten drehen sich normalerweise in der gleichen Richtung wie ihre Umlaufbahn, also auch gegen den Uhrzeigersinn, von der Nordhalbkugel aus gesehen. Aus dieser Tatsache können wir schließen, dass Sonnenuhren auf der nördlichen Hemisphäre erfunden wurden . Wenn Sonnenuhren in der südlichen Hemisphäre erfunden worden wären, wäre der Uhrzeigersinn der andere Weg.
Eric Lippert

Antworten:

3

Eine analytische Lösung hierfür ist schwierig, aber wir können die binäre Suche verwenden , um eine Lösung mit der erforderlichen Genauigkeit zu finden.

Das Schiff kann zum Zeitpunkt t_min den nächstgelegenen Punkt auf der Umlaufbahn erreichen :

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

Das Schiff kann JEDEN Zeitpunkt auf der Umlaufbahn erreichen, der kürzer oder gleich t_max ist :

(Der Einfachheit halber gehe ich hier davon aus, dass das Schiff durch die Sonne fahren kann. Wenn Sie dies vermeiden möchten, müssen Sie zumindest in einigen Fällen auf nicht geradlinige Pfade umsteigen. "Kusskreise" sehen möglicherweise gut aus und befinden sich in einer Umlaufbahn Mechanik-y, ohne den Algorithmus um mehr als einen konstanten Faktor zu verändern)

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

Wenn unsere Umlaufzeit kurz ist, können wir diese Obergrenze möglicherweise verbessern, indem t_maxwir das erste Mal wählen , wenn sich t_minder Planet der Startposition des Schiffes am nächsten nähert. Nehmen Sie, welcher dieser beiden Werte t_maxkleiner ist. In dieser späteren Antwort erfahren Sie, warum dies funktioniert.

Jetzt können wir die binäre Suche zwischen diesen Extremen t_min und t_max verwenden . Wir werden nach einem t-Wert suchen, der den Fehler nahe Null bringt :

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

(Bei dieser Konstruktion sind error @ t_min> = 0 und error @ t_max <= 0, sodass für einen t-Wert dazwischen mindestens ein Abschnitt mit error = 0 vorhanden sein muss.)

wobei der Vollständigkeit halber die Positionsfunktion so etwas wie ... ist

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

Wenn die Umlaufzeit des Planeten im Vergleich zur Schiffsgeschwindigkeit sehr kurz ist, kann diese Fehlerfunktion über die Zeitspanne von t_min bis t_max das Vorzeichen mehrmals ändern. Behalte einfach das früheste + ve & -ve-Paar im Auge und suche weiter zwischen ihnen, bis der Fehler nahe genug bei Null liegt ("nahe genug", abhängig von deinen Einheiten und dem Gameplay-Kontext). Das Quadrat der halben Frame-Dauer kann gut funktionieren - das stellt sicher, dass das Abfangen innerhalb eines Frames genau ist)

Sobald Sie ein nettes Fehler minimierendes t haben, können Sie das Schiff einfach auf planet.positionAtTime (t) richten und Vollgas geben, in der Gewissheit, dass der Planet diesen Punkt zur gleichen Zeit erreicht, zu der Sie dies tun.

Sie finden immer eine Lösung in den Iterationen Log_2 ((2 * orbitRadius / ship.maxSpeed) / errorThreshold). Wenn mein Schiff zum Beispiel die Umlaufbahn in 60 Bildern überqueren kann und ich einen Schnitt mit einer Genauigkeit von bis zu einem Bild will, benötige ich ungefähr 6 Iterationen.

DMGregory
quelle
1
Viele gute Antworten hier, auch einige interessante alternative Optionen, aber von dem, was ich bereits hatte, sieht diese Lösung für meine Instanz am besten aus. Ich habe eine kleine JavaScript-Demo meiner Ergebnisse erstellt. Demo
Ausa
11

Lassen Sie uns dies nicht überkomplizieren. Dies ist keine "perfekte" Lösung, sollte aber für die meisten Spiele funktionieren und jegliche Unvollkommenheit sollte für den Spieler unsichtbar sein.

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. Berechnen Sie die Zeit, die benötigt wird, um den Zielpunkt zu erreichen.
  2. Berechnen Sie, an welcher Position sich der Planet zur berechneten Zeit befindet.
  3. Bewegen Sie sich zum berechneten Punkt.
  4. Wiederholen

Dies funktioniert, weil der Fehler umso geringer wird, je näher das Raumschiff kommt. So wird die Berechnung mit der Zeit stabiler.

Der Fehler ist die Differenz zwischen der berechneten Zeit, die benötigt wird, um den Planeten zu erreichen (TimeNeeded) und der tatsächlichen Zeit, die benötigt wird, um den Planeten zu erreichen (nach Berücksichtigung des neuen Zielpunkts).

API-Biest
quelle
1
Möglicherweise möchten Sie 2 Iterationen davon ausführen, wenn Sie einen Abfangkurs starten. Andernfalls kann das Schiff vorübergehend zwischen zwei Richtungen flimmern (die zweite Vermutung ist möglicherweise viel besser als die erste und führt zu einer ganz anderen Kursrichtung - insbesondere, wenn das Schiff fährt ist in der Nähe oder innerhalb der Umlaufbahn des Planeten)
DMGregory
1
@DMGregory Oh! Wir könnten einfach die aktuelle Position des Planeten anstelle des Orbit Centers als Ausgangspunkt nehmen. Wenn wir nah sind, ist das viel näher, wenn wir weit weg sind, spielt es keine Rolle.
API-Beast
Es ist auch erwähnenswert, dass dies am besten funktioniert, wenn sich der Planet im Vergleich zum Schiff langsam bewegt. Wenn die Geschwindigkeit des Planeten mit der des Schiffes vergleichbar oder größer ist, können Schwankungen im Schiffspfad auftreten. Bei pathologischen Geschwindigkeitsverhältnissen kann das Schiff den Planeten auf einer konzentrischen Umlaufbahn für immer verfolgen. Wenn Ihre Planeten schnell sind und Sie dies bemerken, möchten Sie möglicherweise Ihren gesamten Abfangkurs im Voraus planen, anstatt mitten im Flug zu iterieren.
DMGregory
3

Beginnen wir mit einem Blick auf die Mathematik hinter dem Problem.

Schritt 1:

Um den Schnittpunkt zwischen einer Linie und einer Form zu finden, müssen Sie lediglich die Gleichung der Linie in die Gleichung der Form einfügen, die in diesem Fall ein Kreis ist.

Linie, die sich mit dem Kreis schneidet

Nehmen Sie einen Kreis mit Mittelpunkt c und Radius r . Ein Punkt p liegt auf dem Kreis, wenn

|pc|2=r2

p=p0+μv

|p0+μvc|2=r2

Der quadratische Abstand kann als Punktprodukt ( http://en.wikipedia.org/wiki/Dot_product ) umgeschrieben werden .

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

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

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

|v|=1 und wir haben

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

Das ist eine einfache quadratische Gleichung, und wir kommen zur Lösung

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

μ<0 , schneidet die Schiffslinie in Ihrem Fall nicht die Planetenbahn.

μ=0 , berührt die Schiffslinie einfach den Kreis an einem Punkt.

μ Werte, die zwei Punkten auf der Umlaufbahn entsprechen!

Schritt 2:

μ Werte erhalten. Wenn wir 1 Wert erhalten, verwenden Sie diesen. Wenn wir 2 bekommen, wählen Sie einfach eine davon.

Was können wir damit machen? Nun, wir wissen jetzt, wie weit das Schiff zurücklegen muss und wo es landen wird!

p=p0+μvμv -Komponente gibt uns an, wie weit wir reisen müssen. Teilen Sie einfach diese letzte Komponente durch die Geschwindigkeit Ihres Schiffes, um festzustellen, wie lange es dauern wird, bis es dort ankommt!

Jetzt müssen Sie nur noch berechnen, wo sich der Planet befinden soll, wenn das Schiff in Richtung seiner Umlaufbahn fährt. Dies lässt sich leicht mit sogenannten Polar Coodinates ( http://mathworld.wolfram.com/PolarCoordinates.html ) berechnen.

x=c+rcos(θ)

y=c+rsin(θ)

tangularVelocity Grad in seiner Umlaufbahn, und wir sind fertig!

Zusammenfassung

Wählen Sie eine Linie für Ihr Schiff und führen Sie die Berechnung aus, um festzustellen, ob sie mit der Planetenbahn kollidiert. Wenn ja, berechnen Sie die Zeit, die benötigt wird, um zu diesem Punkt zu gelangen. Verwenden Sie diese Zeit, um von diesem Punkt aus mit dem Planeten in die Umlaufbahn zurückzukehren und zu berechnen, wo sich der Planet befinden soll, wenn das Schiff in Bewegung gerät.

Tholle
quelle
8
Gute Analyse, aber es scheint nicht die Frage zu beantworten (in einem Kommentar geklärt): "Nein, ich versuche den Winkel zu berechnen, den das Schiff braucht, um den Planeten abzufangen." Sie nehmen den Schiffswinkel als gegeben und berechnen die Position des Planeten, anstatt umgekehrt.
Chaosed0
4
Ich werde das nicht ablehnen, weil es eine nützliche Analyse ist, aber ich stimme @ Chaosed0 zu, dass es die Frage nicht beantwortet. In Ihrer Zusammenfassung sagen Sie "Wählen Sie eine Linie für Ihr Schiff ...", aber die Auswahl dieser Linie ist genau der schwierige Teil.
Drake
1

Hier sind zwei "out of the box" -Lösungen.

Die Frage ist: Wenn sich das Schiff mit einer bestimmten Geschwindigkeit auf einer geraden Linie bewegt und sich der Planet mit einer bestimmten Winkelgeschwindigkeit in einem Kreis mit einem bestimmten Radius bewegt, bestimmen die Startpositionen von Planet und Schiff, welchen Richtungsvektor das Schiff hat Es sollte eine gerade Linie sein, um einen Abfangkurs zu zeichnen.

Lösung eins: Leugnen Sie die Prämisse der Frage. Die Größe, die in der Frage "rutschbar" ist, ist der Winkel. Korrigieren Sie das stattdessen. Richten Sie das Schiff direkt in die Mitte der Umlaufbahn.

  • Berechnen Sie die Position an der das Schiff auf den Planeten trifft. das ist einfach.
  • Berechnen Sie die Entfernung vom Schiff zur Abfangposition. auch einfach.
  • Berechnen Sie die Zeit, die benötigt wird, bis der Planet die Abfangposition erreicht. Einfach.
  • Teilen Sie die Entfernung vom Schiff zum Achsenabschnitt durch die Zeit, bis der Planet zum Achsenabschnitt gelangt.
  • Wenn das kleiner oder gleich der Höchstgeschwindigkeit des Schiffes ist, sind Sie fertig. Stellen Sie das Schiff mit dieser Geschwindigkeit direkt auf die Sonne zu.
  • Fügen Sie andernfalls die Umlaufzeit des Planeten zur Zeit hinzu und versuchen Sie es erneut. Machen Sie so lange weiter, bis Sie eine Geschwindigkeit erreicht haben, die für das Schiff in Ordnung ist.

Lösung 2: Machen Sie das überhaupt nicht mit dem Autopiloten. Erstelle ein Minispiel, in dem der Spieler mit Triebwerken auf den Planeten zukommen muss. Wenn sie ihn mit zu hoher Relativgeschwindigkeit treffen, explodieren sie, aber der Treibstoff ist begrenzt. Lassen Sie den Spieler lernen, das Abfangproblem zu lösen!

Eric Lippert
quelle
1

(x,y,t)

tv=x2+y2

v

Die Position des Planeten in Raum und Zeit kann z

x=x0+rcOs(wu+ein)y=y0+rsichn(wu+ein)t=u

u0weinu

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)

Diese Gleichung muss numerisch gelöst werden. Es kann viele Lösungen geben. Wenn man es betrachtet, scheint es immer eine Lösung zu geben

Toni Makkonen
quelle
1

Hier ist ein Teil einer Lösung. Ich habe es nicht rechtzeitig geschafft. Ich werde es später noch einmal versuchen.

Wenn ich das richtig verstehe, haben Sie die Position und Geschwindigkeit eines Planeten sowie die Position und Geschwindigkeit eines Schiffes. Sie möchten die Bewegungsrichtung des Schiffes ermitteln. Ich gehe davon aus, dass die Geschwindigkeit von Schiff und Planet konstant ist. Ich gehe auch ohne Einschränkung der Allgemeinheit davon aus, dass sich das Schiff bei (0,0) befindet; Dazu subtrahieren Sie die Schiffsposition vom Planeten und addieren die Schiffsposition wieder zum Ergebnis der unten beschriebenen Operation.

Leider kann ich diese Antwort ohne Latex nicht sehr gut formatieren, aber wir werden versuchen, dies zu erreichen. Lassen:

  • s_s = die Schiffsgeschwindigkeit (s_s.x, s_s.y, ebenfalls)
  • s_a= die Schiffspeilung (Bewegungswinkel, was wir berechnen wollen )
  • p_p = die ursprüngliche Position des Planeten, globale Koordinaten
  • p_r = Entfernung (Radius) des Planeten vom Mittelpunkt der Umlaufbahn, ableitbar von p_p
  • p_a = der Anfangswinkel des Planeten im Bogenmaß relativ zum Mittelpunkt der Umlaufbahn
  • p_s = Winkelgeschwindigkeit des Planeten (rad / sec)
  • t = die Zeit bis zur Kollision (dies ist etwas, das wir ebenfalls berechnen müssen)

Hier sind die Gleichungen für die Position der beiden Körper, unterteilt in Komponenten:

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

Da wir wollen ship.x = planet.xund ship.y = planet.yirgendwann terhalten wir diese Gleichung (der yFall ist fast symmetrisch):

   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

Lösen der Top-Gleichung für 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))

Das Einsetzen in die zweite Gleichung führt zu einer ziemlich erschreckenden Gleichung, die Wolfram Alpha für mich nicht lösen wird . Möglicherweise gibt es einen besseren Weg, dies ohne Polarkoordinaten zu tun. Wenn jemand diese Methode ausprobieren möchte, ist er herzlich eingeladen. Ich habe dies zu einem Wiki gemacht. Andernfalls möchten Sie dies möglicherweise zum Math StackExchange übertragen .

Chaosed0
quelle
2
Ich würde gerne TeX für diese Site aktivieren. Einige grafische Elemente (z. B. Vektoren, Matrizen, Quaternionen usw.) könnten einfacher dargestellt werden.
mvw
0

Ich würde die Stelle festlegen, an der abgefangen werden soll (streife den Kreis auf der "ausgehenden" Seite der Umlaufbahn).

Jetzt müssen Sie nur noch die Geschwindigkeit des Raumschiffs anpassen, damit Planet und Schiff gleichzeitig diesen Punkt erreichen.

Beachten Sie, dass das Rendezvous nach N weiteren Umlaufbahnen stattfinden kann, je nachdem, wie weit das Schiff entfernt ist und wie schnell der Planet den Stern umkreist.

Wählen Sie das N, das der Reisedauer des Schiffes bei der aktuellen Geschwindigkeit am nächsten kommt.

Beschleunigen oder verlangsamen Sie dann das Schiff, um den Zeitstempel für diese N Umlaufbahnen exakt abzugleichen.

Dabei ist der aktuelle Verlauf bereits bekannt! Nur nicht die Geschwindigkeit.

Bram
quelle
Dies kann zu unnötig langen Fahrten führen. Nehmen wir an, wir sind so positioniert, dass der Planet auf uns zukommt, und wir können tatsächlich den "ankommenden" Weidepunkt erreichen, während der Planet dies tut. Wenn wir nur den "ausgehenden" Weidepunkt betrachten, könnten wir am Ende ein halbes zusätzliches halbes Jahr auf der Durchreise verbringen!
DMGregory
Richtig ... hängt von der Umlaufgeschwindigkeit ab. Es minimiert aber auch die Delta-Geschwindigkeit, wenn Sie immer abgehend grasen. Bei "Incoming" können Sie sich in der Atmosphäre verbrennen, während bei "Outgoing" die Wahrscheinlichkeit größer ist, dass Sie sich angleichen. @DMGregory
Bram