Як я можу перехопити предмет круговим рухом


23

Я створюю космічну гру 2d і потрібно, щоб космічний корабель перехопив планету. У мене є робочий код для перехоплення прямих ліній, але не можу зрозуміти, як обчислити розташування планет на круговій орбіті.

Гра не є науково точною, тому мене не турбує інертність, гравітація, еліптичні орбіти тощо.

Я знаю розташування і швидкість космічних кораблів, а також орбіту планет (радіус) і швидкість

введіть тут опис зображення


1
Ні, я намагаюся обчислити кут, який повинен рухати корабель, щоб перехопити планету.
Ауса

4
Це, мабуть, буде краще працювати в math.stackexchange.com ..
Jari Komppa

2
Чи може ваш корабель змінити швидкість і напрямок, або вони постійні? Також може бути корисним це питання про те, щоб не мати ракети по цілі.
thegrinner

4
Для уточнення, чи є ситуація? задані для планети: центр орбіти, радіус орбіти, кутова швидкість, поточне розташування; для корабля : поточне місцезнаходження, поточна швидкість; визначити напрямок руху судна з метою перехоплення планети
AakashM

6
Як цікава історична примітка: планети, як правило, обертаються в тому ж напрямку, що і їх орбіта, і тому також проти годинникової стрілки, як видно зверху північної півкулі. З цього факту можна зробити висновок, що сонячні годинники були винайдені в північній півкулі . Якби сонячні годинники були винайдені в південній півкулі, то тоді за годинниковою стрілкою було б іншим способом.
Ерік Ліпперт

Відповіді:


3

Аналітичне рішення цього важко, але ми можемо використовувати двійковий пошук, щоб знайти рішення в межах необхідної точності.

Корабель може досягти найближчої точки на орбіті за час 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 ітерацій.


1
Тут багато хороших відповідей, а також кілька цікавих альтернативних варіантів, але з того, що у мене вже було ці рішення, найкраще виглядає для мого випадку. Я створив невелику демонстрацію JavaScript своїх результатів. Демо
Ауса

11

Давайте не надто ускладнювати це. Це не "ідеальне" рішення, але воно має працювати для більшості ігор, і будь-яка недосконалість повинна бути невидимою для гравця.

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. Обчисліть час, необхідний для досягнення цільової точки.
  2. Обчисліть, у якому положенні буде планета в обчислений час.
  3. Перемістіться до обчисленої точки.
  4. Повторіть

Це працює, тому що чим ближче космічний апарат досягає нижчої помилки. Тож обчислення з часом стає стабільнішим.

Помилка - різниця між розрахованим необхідним часом для досягнення планети (TimeNeeded) та фактичним часом, необхідним для досягнення планети (після врахування нової TargetPoint).


1
Ви можете запустити 2 ітерації цього при запуску перехоплювального курсу, інакше ви побачите, що корабель миттєво мерехтить між двома напрямками (друга здогадка може бути набагато кращою, ніж перша, і призведе до зовсім іншого напрямку - особливо якщо корабель близько до орбіти планети або в межах неї)
DMGregory

1
@DMGregory О! Ми могли просто взяти поточне положення планети замість центру орбіти як вихідну точку. Коли ми поруч, це набагато ближче, якщо ми далеко, це не має значення.
API-Beast

Варто також зазначити, що це найкраще працює, коли планета рухається повільно порівняно з кораблем. Якщо швидкість планети порівнянна або більша за швидкість корабля, ви можете побачити коливання на шляху корабля. При патологічних співвідношеннях швидкості корабель може вічно переслідувати планету по концентричній орбіті. Якщо ваші планети швидко і ви помітили, що це відбувається, ви, можливо, захочете спланувати весь курс перехоплення вперед, а не ітерацію в середині польоту.
DMGregory

3

Для початку поглянемо на математику, що стоїть перед проблемою.

Крок 1:

Пошук перетину між лінією та формою - це лише питання вставлення рівняння прямої в рівняння фігури, що в цьому випадку є колом.

Лінія, що перетинається з колом

Візьміть коло з центром c і радіусом r . Точка p знаходиться на колі, якщо

|pc|2=r2

З прямою, вираженою як p=p0+μv (де v - вектор, http://en.wikipedia.org/wiki/Euclidean_vector ), ви вставляєте рядок у формулу кола і отримуєте

|p0+μvc|2=r2

Відстань у квадраті може бути переписана як крапковий продукт ( 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

що є простим квадратичним рівнянням, і ми приходимо до рішення

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

μ<0

μ=0

Інакше це дає нам два μ

Крок 2:

Таким чином, ми можемо визначити лінію для корабля, і з цього отримаємо або 0, 1 або 2 μ

Що ми можемо з цим зробити? Ну, ми тепер знаємо, яку відстань повинен пройти корабель, і в який момент він опиниться!

p=p0+μvμv -компонент дає нам, наскільки далеко доведеться проїхати. Просто розділіть цей останній компонент зі швидкістю вашого корабля, щоб отримати скільки часу знадобиться йому, щоб дістатися туди!

Тепер все, що залишилося зробити, - це порахувати, де повинна бути планета, коли корабель починає наближатися до своєї орбіти. Це легко обчислити за допомогою так званих полярних кодинатів ( http://mathworld.wolfram.com/PolarCoordinate.html )

x=c+rcos(θ)

y=c+rsin(θ)

tangularVelocity

Підсумок

Виберіть лінію для свого корабля та запустіть математику, щоб побачити, чи стикається він з орбітою планет. Якщо це так, порахуйте час, який знадобиться, щоб дістатися до цієї точки. Використовуйте цей час, щоб повернутися на орбіту з цієї точки з планетою, щоб обчислити, де повинна бути планета, коли судно починає рухатися.


8
Хороший аналіз, але, схоже, це не дає відповіді на запитання (уточнене в коментарі): "Ні, я намагаюся обчислити кут, який судно потрібно рухати, щоб перехопити планету". Ви приймаєте кут корабля як заданий і обчислюєте положення планети, а не навпаки.
Chaosed0

4
Не збираюся спростовувати це, оскільки це корисний аналіз, але я погоджуюся з @ Chaosed0, що він не відповідає на питання. У своєму резюме ви говорите "Виберіть лінію для свого корабля ...", але вибір цієї лінії - це саме важка частина.
Дрейк

1

Ось два злегка "поза коробкою" рішення.

Питання полягає в тому, що: враховуючи, що корабель рухається по прямій із заданою швидкістю, а планета рухається по колу заданого радіуса з заданою кутовою швидкістю, а вихідні положення планети і корабля визначають, у якому напрямку руху корабель пряма лінія повинна бути в змозі побудувати перехоплюючий хід.

Рішення перше: заперечте передумови питання. Кількість, яка "ковзає" у питанні, - це кут. Натомість виправте це. Направте корабель прямо на центр орбіти.

  • Обчисліть позицію в якому корабель зустріне планету; це просто.
  • Обчисліть відстань від корабля до положення перехоплення; також легко.
  • Обчисліть час, який знадобиться, поки наступна планета не досягне місця перехоплення. Легко.
  • Розділіть відстань від корабля до перехоплення на час, поки планета потрапить на перехоплення.
  • Якщо це менше або дорівнює максимальній швидкості корабля, ви закінчите. Встановіть корабель, що рухається такою швидкістю, прямо до сонця.
  • В іншому випадку додайте орбітальний період планети до часу і спробуйте ще раз. Продовжуйте це робити, поки не отримаєте швидкість, яка не є причиною для корабля.

Рішення друге: взагалі не робіть цього на автопілоті. Створіть міні-гру, де гравцеві доводиться використовувати штовхачі, щоб наблизитися до планети, і якщо вони вдарять його з занадто високою відносною швидкістю, вони вибухають, але паливо також має обмежене значення. Змусьте гравця навчитися вирішувати проблему перехоплення!


1

(х,у,т)

тv=х2+у2

v

Положення планети в просторі і в часі можна параметризувати, наприклад

х=х0+rcос(шу+а)у=у0+rсiн(шу+а)т=у

де у йде від 0 вгору ш - кутова швидкість і а- початковий кут планети в нульовий час. Потім вирішіть, де корабель і планета могли зустрітися у часі та просторі. Ви отримуєте рівняння дляу вирішувати:

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.