Come posso intercettare l'oggetto con un movimento circolare


23

Sto creando un gioco spaziale 2D e devo fare in modo che l'astronave intercetti un pianeta. Ho un codice funzionante per le intercettazioni in linea retta ma non riesco a capire come calcolare la posizione dei pianeti in un'orbita circolare.

Il gioco non è scientificamente accurato, quindi non sono preoccupato per inerzia, gravità, orbite ellittiche, ecc.

Conosco la posizione e la velocità delle astronavi e anche l'orbita dei pianeti (raggio) e la velocità

inserisci qui la descrizione dell'immagine


1
No, sto cercando di calcolare l'angolazione che la nave deve muovere per intercettare il pianeta.
Ausa,

4
Questo probabilmente funzionerebbe meglio in math.stackexchange.com ..
Jari Komppa

2
La tua nave è in grado di cambiare velocità e direzione o sono costanti? Inoltre, questa domanda sull'evitare che i missili cerchino un bersaglio potrebbe essere utile.
thegrinner

4
Per chiarire, è la situazione? dato per il pianeta: centro dell'orbita, raggio dell'orbita, velocità angolare, posizione attuale; per la nave : posizione attuale, velocità attuale; determinare la direzione di movimento della nave per intercettare il pianeta
AakashM,

6
Come una nota storica interessante: i pianeti di solito ruotano nella stessa direzione della loro orbita, che è quindi anche in senso antiorario visto dall'alto dell'emisfero settentrionale. Da questo fatto possiamo dedurre che le meridiane sono state inventate nell'emisfero settentrionale . Meridiane era stato inventato nel sud del mondo, allora in senso orario sarebbe il altro modo.
Eric Lippert

Risposte:


3

Una soluzione analitica è difficile, ma possiamo usare la ricerca binaria per trovare una soluzione con l'accuratezza richiesta.

La nave può raggiungere il punto più vicino sull'orbita nel tempo t_min :

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

La nave può raggiungere QUALSIASI punto sull'orbita in un tempo inferiore o uguale a t_max :

(Qui, per semplicità, suppongo che la nave possa guidare attraverso il sole. Se vuoi evitarlo, dovrai passare a percorsi non rettilinei per almeno alcuni casi. "I circoli del bacio" possono sembrare belli e orbitali meccanica-y, senza modificare l'algoritmo di più di un fattore costante)

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

Se il nostro periodo orbitale è breve, potremmo essere in grado di migliorare su questo limite superiore scegliendo t_maxdi essere la prima volta dopo t_minche il pianeta si avvicina alla posizione di partenza della nave. Prendi qualunque di questi due valori di t_maxè minore. Vedi questa risposta successiva per una derivazione del perché funziona.

Ora possiamo usare la ricerca binaria tra questi estremi, t_min e t_max . Cercheremo un valore t che porti l' errore vicino a zero:

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

(Usando questa costruzione, errore @ t_min> = 0 ed errore @ t_max <= 0, quindi deve esserci almeno un'intercettazione con errore = 0 per un valore t compreso tra)

dove, per completezza, la funzione di posizione è qualcosa come ...

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

Nota che se il periodo orbitale del pianeta è molto breve rispetto alla velocità della nave, questa funzione di errore può cambiare i segni più volte nell'intervallo da t_min a t_max. Tieni traccia della prima coppia + ve & -ve che incontri e continua a cercare tra loro fino a quando l'errore è abbastanza vicino a zero ("abbastanza vicino" è sensibile alle tue unità e al contesto di gioco. Il quadrato della metà della durata del fotogramma può funziona bene - ciò garantisce che l'intercettazione sia accurata all'interno di un frame)

Una volta che hai una bella t che minimizza gli errori, puoi semplicemente puntare la nave verso planet.positionAtTime (t) e andare a tutto gas, fiducioso che il pianeta raggiungerà quel punto nello stesso momento in cui lo fai.

È sempre possibile trovare una soluzione all'interno delle iterazioni Log_2 ((2 * orbitRadius / ship.maxSpeed) / errorThreshold). Quindi, ad esempio, se la mia nave può attraversare l'orbita in 60 fotogrammi e voglio un'intercettazione accurata entro un fotogramma, avrò bisogno di circa 6 iterazioni.


1
Molte buone risposte qui, anche alcune opzioni alternative interessanti ma da quello che ho già avuto questa soluzione sembra la migliore per la mia istanza. Ho creato una piccola demo JavaScript dei miei risultati. Demo
Ausa,

11

Non compliciamo troppo questo. Questa non è una soluzione "perfetta", ma dovrebbe funzionare per la maggior parte dei giochi e qualsiasi imperfezione dovrebbe essere invisibile al giocatore.

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. Calcola il tempo necessario per raggiungere il punto target.
  2. Calcola in quale posizione sarà il pianeta al momento calcolato.
  3. Spostarsi verso il punto calcolato.
  4. Ripetere

Questo funziona perché più il veicolo spaziale si avvicina e più basso diventa l'errore. Quindi il calcolo diventa più stabile nel tempo.

L'errore è la differenza tra il tempo necessario calcolato per raggiungere il pianeta (TimeNeeded) e il tempo effettivo necessario per raggiungere il pianeta (dopo aver preso in considerazione il nuovo TargetPoint).


1
Potresti voler eseguire 2 iterazioni di questo all'avvio di una rotta di intercettazione, altrimenti potresti vedere lo sfarfallio della nave tra due direzioni momentaneamente (la seconda ipotesi può essere molto migliore della prima e comportare una rotta molto diversa - in particolare se la nave è vicino o all'interno dell'orbita del pianeta)
DMGregory

1
@DMGregory Oh! Potremmo semplicemente prendere l'attuale posizione del pianeta anziché il centro dell'orbita come punto di partenza. Quando siamo vicini è molto più vicino, se siamo lontani non importa.
API-Beast

Vale anche la pena notare che funziona meglio quando il pianeta si muove lentamente rispetto alla nave. Se la velocità del pianeta è paragonabile o superiore a quella della nave, potresti vedere delle oscillazioni sul percorso della nave. A rapporti di velocità patologici, la nave può inseguire il pianeta per sempre su un'orbita concentrica. Se i tuoi pianeti sono veloci e noti che ciò sta accadendo, potresti voler pianificare l'intero percorso di intercettazione in anticipo piuttosto che iterare durante il volo.
DMGregory

3

Cominciamo dando un'occhiata alla matematica dietro il problema.

Passo 1:

Trovare l'intersezione tra una linea e una forma è solo una questione di inserimento dell'equazione della linea nell'equazione della forma, che in questo caso è un cerchio.

Linea che si interseca con il cerchio

Prendi un cerchio con centro c e raggio r . Un punto p è sul cerchio se

|pc|2=r2

p=p0+μv

|p0+μvc|2=r2

La distanza quadrata può essere riscritta come prodotto punto ( 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

che è una semplice equazione quadratica, e arriviamo alla soluzione

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

μ<0

μ=0

μ

Passo 2:

μ

Cosa possiamo fare con questo? Bene, ora sappiamo la distanza che la nave deve percorrere e in che punto finirà!

p=p0+μvμv

Ora, tutto ciò che resta da fare è calcolare dove dovrebbe essere il pianeta quando la nave inizia a dirigersi verso la sua orbita. Questo è facilmente calcolabile con i cosiddetti coodinati polari ( http://mathworld.wolfram.com/PolarCoordinates.html )

x=c+rcos(θ)

y=c+rsin(θ)

tangularVelocity

Sommario

Scegli una linea per la tua nave ed esegui la matematica per vedere se si scontra con l'orbita dei pianeti. In tal caso, calcola il tempo necessario per arrivare a quel punto. Usa questo tempo per tornare in orbita da questo punto con il pianeta per calcolare dove dovrebbe trovarsi il pianeta quando la nave inizia a muoversi.


8
Buona analisi, ma non sembra rispondere alla domanda (chiarita in un commento): "No, sto cercando di calcolare l'angolazione che la nave deve muovere per intercettare il pianeta". Stai prendendo l'angolo della nave come un dato e calcolando la posizione del pianeta, invece il contrario.
Chiuso

4
Non ho intenzione di sottovalutare questo perché è un'analisi utile, ma sono d'accordo con @ Chaosed0 che non risponde alla domanda. Nel tuo riassunto dici "Scegli una linea per la tua nave ..." ma scegliere quella linea è esattamente la parte difficile.
Drake,

1

Ecco due soluzioni leggermente "out of the box".

La domanda è: dato che la nave si muove in linea retta a una data velocità e il pianeta si muove in un cerchio di un determinato raggio a una data velocità angolare, e le posizioni di partenza del pianeta e della nave, determinano quale direzione vettore della nave la linea retta dovrebbe essere dentro per tracciare una rotta di intercettazione.

Soluzione 1: negare la premessa della domanda. La quantità che è "sfuggibile" nella domanda è l'angolo. Invece, risolvilo. Punta la nave dritta al centro dell'orbita.

  • Calcola la posizione in cui la nave incontrerà il pianeta; questo è facile.
  • Calcola la distanza dalla nave alla posizione di intercettazione; anche facile.
  • Calcola il tempo necessario affinché il pianeta successivo raggiunga la posizione di intercettazione. Facile.
  • Dividi la distanza dalla nave all'intercettazione per il tempo fino a quando il pianeta arriva all'intercetta.
  • Se è inferiore o uguale alla velocità massima della nave, il gioco è fatto. Imposta la nave che si muove a quella velocità direttamente verso il sole.
  • Altrimenti, aggiungi il periodo orbitale del pianeta al tempo e riprova. Continua a farlo fino a quando non ottieni una velocità ragionevole per la nave.

Soluzione 2: non farlo affatto con il pilota automatico. Crea un mini-gioco in cui il giocatore deve usare i propulsori per avvicinarsi al pianeta e se lo colpiscono a una velocità relativa troppo elevata, esplodono, ma hanno anche un carburante limitato. Fai imparare al giocatore come risolvere il problema di intercettazione!


1

(x,y,t)

tv=x2+y2

v

La posizione del pianeta nello spazio e nel tempo può essere parametrizzata ad es

X=X0+rcoS(wu+un')y=y0+rSion(wu+un')t=u

u0wun'u

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.