Аналитическое решение этого является сложным, но мы можем использовать бинарный поиск, чтобы найти решение с необходимой точностью.
Корабль может достичь ближайшей точки на орбите за время 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;
(Используя эту конструкцию, error @ t_min> = 0 и error @ t_max <= 0, поэтому должен быть хотя бы один перехват с ошибкой = 0 для промежуточного значения t)
где для полноты функция положения что-то вроде ...
Vector2 Planet.positionAtTime(float t)
{
angle = atan2(startPosition - orbitCenter) + t * orbitalSpeedInRadians;
return new Vector2(cos(angle), sin(angle)) * orbitRadius + orbitCenter;
}
Обратите внимание, что если орбитальный период планеты очень короткий по сравнению со скоростью корабля, эта функция ошибок может несколько раз менять знаки на протяжении промежутка от t_min до t_max. Просто следите за самой ранней парой + ve & -ve, с которой вы столкнулись, и продолжайте поиск между ними, пока ошибка не станет достаточно близкой к нулю («достаточно близко», чувствительная к вашим юнитам и контексту игрового процесса. Квадрат половины длительности кадра может работать хорошо - это гарантирует, что перехват с точностью до кадра)
Как только вы добьетесь приятного минимизации ошибок t, вы можете просто указать кораблю на planet.positionAtTime (t) и сделать полный газ, будучи уверенным, что планета достигнет этой точки в то же время, что и вы.
Вы всегда можете найти решение в итерациях Log_2 ((2 * orbitRadius / ship.maxSpeed) / errorThreshold). Так, например, если мой корабль может пересечь орбиту за 60 кадров, и мне нужен точный перехват с точностью до одного кадра, мне потребуется около 6 итераций.