Аналітичне рішення цього важко, але ми можемо використовувати двійковий пошук, щоб знайти рішення в межах необхідної точності.
Корабель може досягти найближчої точки на орбіті за час t_min :
shipOrbitRadius = (ship.position - planet.orbitCenter).length;
shortestDistance = abs(shipOrbitRadius - planet.orbitRadius);
t_min = shortestDistance/ship.maxSpeed;
Корабель може досягти будь-якої точки на орбіті за час, менший або рівний t_max :
(Тут, для простоти, я припускаю, що корабель може проїхати через сонце. Якщо ви хочете цього уникнути, вам потрібно буде хоч хоча б у деяких випадках перейти на прямолінійні шляхи. "Цілувальні кола" можуть виглядати приємно та орбітально механіка-у, не змінюючи алгоритм більш ніж постійним фактором)
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
того, як планета здійснить найближчий підхід до початкового положення корабля. Візьміть, що б із цих двох значень t_max
менше. Дивіться цю пізню відповідь для отримання висновку, чому це працює.
Тепер ми можемо використовувати двійковий пошук між цими крайнощами, t_min та t_max . Ми будемо шукати t-значення, яке отримує помилку, близьку до нуля:
error = (planet.positionAtTime(t) - ship.position).squareMagnitude/(ship.maxSpeed*ship.maxSpeed) - t*t;
(Використовуючи цю конструкцію, помилка @ t_min> = 0 і помилка @ t_max <= 0, тому для t-значення між ними має бути принаймні один перехоплення з помилкою = 0)
де для повноти функція позиції - це щось на зразок ...
Vector2 Planet.positionAtTime(float t)
{
angle = atan2(startPosition - orbitCenter) + t * orbitalSpeedInRadians;
return new Vector2(cos(angle), sin(angle)) * orbitRadius + orbitCenter;
}
Зауважте, що якщо орбітальний період планети дуже короткий порівняно зі швидкістю корабля, ця функція помилок може кілька разів змінювати знаки за проміжок від t_min до t_max. Просто слідкуйте за найдавнішою парою, що зустрічається, і продовжуйте шукати між ними, поки помилка не наблизиться до нуля ("достатньо близько" буде чутливим до ваших одиниць та ігрового контексту. Площа половини тривалості кадру може бути добре працюйте - це забезпечує точне перехоплення всередині кадру)
Після того, як у вас з’явиться приємне зменшення помилок t, ви можете просто вказати корабель на planet.positionAtTime (t) і піти повним дроселем, впевнений, що планета досягне цієї точки в той самий час, коли і ви.
Ви завжди можете знайти рішення в ітераціях Log_2 ((2 * orbitRadius / ship.maxSpeed) / errorThreshold). Так, наприклад, якщо мій корабель може пройти орбіту в 60 кадрів, і я хочу перехопити точно в одному кадрі, мені знадобиться близько 6 ітерацій.