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_max
pierwszy raz po t_min
tym, jak planeta zbliży się do pozycji początkowej statku. Weź jedną z tych dwóch wartości, która t_max
jest 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.