Jak przechwycić obiekt ruchem okrężnym

23

Tworzę grę kosmiczną 2d i muszę sprawić, by statek kosmiczny przechwycił planetę. Mam działający kod do przechwytywania linii prostych, ale nie mogę dowiedzieć się, jak obliczyć położenie planet na orbicie kołowej.

Gra nie jest naukowo dokładna, więc nie martwię się o bezwładność, grawitację, orbitę eliptyczną itp.

Znam lokalizację i prędkość statku kosmicznego, a także orbitę planet (promień) i prędkość

wprowadź opis zdjęcia tutaj

Ausa
źródło
1
Nie. Próbuję obliczyć kąt, jaki statek musi przemieścić, aby przechwycić planetę.
Ausa
4
Prawdopodobnie działałoby to lepiej w math.stackexchange.com ..
Jari Komppa
2
Czy twój statek jest w stanie zmienić prędkość i kierunek, czy są one stałe? Również ta kwestia o unikanie pocisków koło mające cel może być pomocne.
thegrinner
4
Aby wyjaśnić, czy sytuacja jest taka? dane dla planety: środek orbity, promień orbity, prędkość kątowa, aktualna lokalizacja; dla statku : aktualna lokalizacja, aktualna prędkość; określić kierunek ruchu statku w celu przechwycenia planety
AakashM
6
Jako interesująca uwaga historyczna: planety zwykle obracają się w tym samym kierunku, co ich orbita, dlatego też jest ona również przeciwna do ruchu wskazówek zegara, widziana z góry z półkuli północnej. Z tego faktu możemy wywnioskować, że zegary słoneczne zostały wymyślone na półkuli północnej . Miały zegary słoneczne wynaleziono na półkuli południowej, a następnie w prawo byłby inny sposób.
Eric Lippert

Odpowiedzi:

3

Analityczne rozwiązanie tego problemu jest trudne, ale możemy użyć wyszukiwania binarnego, aby znaleźć rozwiązanie z wymaganą dokładnością.

Statek może dotrzeć do najbliższego punktu na orbicie w czasie t_min :

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

Statek może osiągnąć DOWOLNY punkt na orbicie w czasie krótszym lub równym t_max :

(Tutaj, dla uproszczenia, zakładam, że statek może przejechać przez Słońce. Jeśli chcesz tego uniknąć, musisz przełączyć się na ścieżki nieproste przynajmniej w niektórych przypadkach. „Całowanie kół” może wyglądać ładnie i orbitalnie mechanika-y, bez zmiany algorytmu o więcej niż stały współczynnik)

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

Jeśli nasz okres na orbicie jest krótki, możemy być w stanie poprawić tę górną granicę, wybierając t_maxpierwszy raz po t_mintym, jak planeta zbliży się do pozycji początkowej statku. Weź jedną z tych dwóch wartości, która t_maxjest mniejsza. Zobacz późniejszą odpowiedź, aby dowiedzieć się, dlaczego to działa.

Teraz możemy korzystać z wyszukiwania binarnego między tymi skrajnościami, t_min i t_max . Poszukamy wartości t, która zbliża błąd do zera:

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

(Korzystając z tej konstrukcji, błąd @ t_min> = 0 i błąd @ t_max <= 0, więc musi istnieć co najmniej jeden punkt przecięcia z błędem = 0 dla wartości t pomiędzy nimi)

gdzie, dla kompletności, funkcja pozycji jest jak ...

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

Zauważ, że jeśli okres obiegu orbity planety jest bardzo krótki w porównaniu z prędkością statku, ta funkcja błędu może kilkakrotnie zmieniać znaki w czasie od t_min do t_max. Śledź najwcześniejszą napotkaną parę + ve & -ve i kontynuuj wyszukiwanie między nimi, aż błąd będzie wystarczająco bliski zeru („wystarczająco blisko” wrażliwy na twoje jednostki i kontekst gry). Kwadrat połowy czasu trwania klatki może działa dobrze - zapewnia to, że przechwytywanie jest dokładne w ramce)

Kiedy już uzyskasz ładny minimalizujący błędy t, możesz po prostu skierować statek na planet.positionAtTime (t) i przejść na pełną przepustnicę, mając pewność, że planeta dotrze do tego punktu w tym samym czasie, co ty.

Zawsze możesz znaleźć rozwiązanie w iteracjach Log_2 ((2 * orbitRadius / ship.maxSpeed) / errorThreshold). Na przykład, jeśli mój statek może przemieścić orbitę w 60 klatkach, a chcę, aby przechwycenie było dokładne z dokładnością do jednej klatki, potrzebuję około 6 iteracji.

DMGregory
źródło
1
Wiele dobrych odpowiedzi tutaj, również kilka ciekawych alternatywnych opcji, ale z tego, co już miałem, rozwiązania wyglądają najlepiej w moim przypadku. Stworzyłem małe demo JavaScript moich wyników. Demo
Ausa
11

Nie komplikujmy tego zbytnio. Nie jest to „idealne” rozwiązanie, ale powinno działać w przypadku większości gier, a wszelkie niedoskonałości powinny być niewidoczne dla gracza.

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. Oblicz czas potrzebny do osiągnięcia punktu docelowego.
  2. Oblicz, w jakiej pozycji planeta będzie w obliczonym czasie.
  3. Przejdź w kierunku obliczonego punktu.
  4. Powtarzać

Działa to, ponieważ im bliżej statek kosmiczny się zbliża, tym niższy staje się błąd. Dzięki temu obliczenia stają się bardziej stabilne w czasie.

Błąd jest różnicą między obliczonym potrzebnym czasem na dotarcie do planety (TimeNeeded) a rzeczywistym czasem potrzebnym na dotarcie do planety (po uwzględnieniu nowego TargetPoint).

API-Beast
źródło
1
Możesz uruchomić 2 iteracje tego, rozpoczynając kurs przechwytywania, w przeciwnym razie możesz chwilowo migotać statek między dwoma kierunkami (drugie przypuszczenie może być znacznie lepsze niż pierwsze i spowodować zupełnie inny kurs - szczególnie jeśli statek znajduje się w pobliżu orbity planety)
DMGregory
1
@DMGregory Oh! Moglibyśmy po prostu przyjąć aktualną pozycję planety zamiast centrum orbity jako punkt wyjścia. Kiedy jesteśmy blisko, to jest znacznie bliżej, jeśli jesteśmy daleko, to nie ma znaczenia.
API-Beast
Warto również zauważyć, że działa to najlepiej, gdy planeta porusza się powoli w porównaniu do statku. Jeśli prędkość planety jest porównywalna lub większa niż prędkość statku, możesz zobaczyć oscylacje na drodze statku. Przy patologicznych stosunkach prędkości statek może ścigać planetę na zawsze na koncentrycznej orbicie. Jeśli twoje planety są szybkie i zauważysz, że tak się dzieje, możesz zaplanować cały kurs przechwytywania z góry, a nie iterować w trakcie lotu.
DMGregory
3

Zacznijmy od przyjrzenia się matematyce stojącej za tym problemem.

Krok 1:

Znalezienie przecięcia linii z kształtem polega jedynie na wstawieniu równania linii do równania kształtu, którym w tym przypadku jest okrąg.

Line intersecting with circle

Weź okrąg o środku c i promieniu r . Punkt p znajduje się na okręgu, jeśli

|pc|2=r2

p=p0+μv

|p0+μv-do|2)=r2)

Kwadratowa odległość może być przepisana jako iloczyn kropkowy ( http://en.wikipedia.org/wiki/Dot_product ).

(p0+μv-do)(p0+μv-do)=r2)

za=do-p0(μv-za)(μv-za)=r2)

Wykonaj produkt kropkowy, a my dostaniemy μ2)(vv)-2)μ(zav)+zaza=r2)

Zakładać, że |v|=1 i mamy

μ2)-2)μ(zav)+|za|2)-r2)=0

który jest prostym równaniem kwadratowym, i dochodzimy do rozwiązania

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

If μ<0, the line of the ship in your case does not intersect with the planets orbit.

If μ=0, the line of the ship will simply touch the circle in one point.

Otherwise, this gives us two μ-values that corresponds to two points on the orbit!

Step 2:

So we can define a line for the ship, and out of that we get either 0, 1 or 2 μ-values. If we get 1 value, use that one. If we get 2, simply choose one of them.

What can we do with this? Well, we now know the distance the ship has to travel and what point it will end up in!

p=p0+μv gives us the coordinate, and the μv-component gives us how far is will have to travel. Simply divide this last component with the speed of your ship to get how much time it will take for it to get there!

Now, all that is left to do is to calculate where the planet should be when the ship begins coming towards it's orbit. This is easily calculated with so called Polar coodinates (http://mathworld.wolfram.com/PolarCoordinates.html)

x=c+rcos(θ)

y=c+rsin(θ)

And since you had the speed of you ship, and we have the time it will take for the ship to reach the orbit, and where it will collide, we simply move the planet back tangularVelocity degrees in it's orbit, and we are done!

Summary

Choose a line for your ship, and run the math to see if it collides with the planets orbit. If it does, calculate the time it will take to get to that point. Use this time to go back in orbit from this point with the planet to calculate where the planet should be when the ship starts moving.

Tholle
źródło
8
Good analysis, but it doesn't appear to answer the question (clarified in a comment): "No I am trying to calculate the angle the ship needs to move in order to intercept the planet." You are taking the ship's angle as a given and calculating the position of the planet, instead of the other way around.
Chaosed0
4
Not going to downvote this because it's useful analysis, but I agree with @Chaosed0 that it does not answer the question. In your summary you say "Choose a line for your ship..." but choosing that line is exactly the hard part.
Drake
1

Here are two slightly "out of the box" solutions.

The question is: given that the ship moves in a straight line at a given velocity, and the planet moves in a circle of given radius at a given angular velocity, and the starting positions of the planet and ship, determine what direction vector the ship's straight line should be in to plot an intercept course.

Solution one: Deny the premise of the question. The quantity that is "slippable" in the question is the angle. Instead, fix that. Point the ship straight at the center of the orbit.

  • Calculate the position at which the ship will encounter the planet; that's easy.
  • Calculate the distance from the ship to the intercept position ; also easy.
  • Calculate the time it will take until the planet next reaches the intercept position. Easy.
  • Divide the distance from the ship to the intercept by the time until the planet gets to the intercept.
  • If that is smaller than or equal to the maximum speed of the ship, you're done. Set the ship moving at that speed straight towards the sun.
  • Otherwise, add the orbital period of the planet to the time and try again. Keep doing that until you get a speed that is within reason for the ship.

Solution two: Don't do it on autopilot at all. Make a mini-game where the player has to use thrusters to approach the planet, and if they hit it at too high a relative speed, they blow up, but they have limited fuel as well. Make the player learn how to solve the intercept problem!

Eric Lippert
źródło
1

If you dont' want to use polar coordinates, consider that the all the possible positions of the ship form a cone in (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

Toni Makkonen
źródło
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.

Chaosed0
źródło
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.

Bram
źródło
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