Я припускаю, що у вас фізично правильний рух для вашого корабля, оскільки в іншому випадку цей аналіз не проведе. Вам потрібно щось сильніше, ніж ефективність, щоб правильно вирішити цю проблему.
Кожен тяги буде виробляти два впливи на рух корабля: лінійний та кутовий. Їх можна розглядати самостійно. Якщо тяга виробляє силу f
в напрямку dir
і зміщується з центру маси вектором r
(а не геометричним центром або центром спрайта!), То вплив на лінійну складову:
t = f * dir // f is a scalar, dir is unit length
Вплив на кутову швидкість надає крутний момент:
tau = f * <dir.x, dir.y, 0> CROSS <r.x, r.y, 0> // cross product
t
- вектор сили (тобто лінійна тяга). tau
являє собою підписаний скаляр, який при поділі на момент інерції маси дасть кутове прискорення. Важливо, що dir
іr
обидва в тому ж просторі координат, тобто як в локальних координатах або як в світових координатах.
Загальне лінійне прискорення корабля задається сумою t
's для кожного тяги, поділеної на масу корабля. Аналогічно, кутове прискорення - це лише сума крутних моментів, поділена на масовий момент інерції (що є ще одним скаляром). Якщо сумарний крутний момент дорівнює нулю, корабель не повернеться. Так само воно не рухатиметься, якщо загальна тяга дорівнює нулю. Нагадаємо, крутний момент є скалярним, але тяга (сума t
's) - двовимірний вектор.
Суть цієї експозиції полягає в тому, що тепер ми можемо записати свою проблему як лінійну програму . Скажіть спочатку, що ми хочемо, щоб наш корабель повернувся без руху . У нас є змінна для кожного тяги, $ x_1, x_2, ... $, яка є величиною тяги, яку забезпечить тяга. Один набір обмежень:
0 <= x_i < fmax_i //for each i
де fmax
максимальна сила для цього тяги (це дозволяє нам мати сильніші або слабкіші). Далі ми говоримо, що обидві рівності:
0 = Sum_i x_i * dir_i.x
0 = Sum_i x_i * dir_i.y
Це кодує обмеження, що ми не будемо застосовувати лінійне прискорення, кажучи, що загальна тяга дорівнює нулю (тяга - вектор, тому ми просто скажемо, що кожна частина дорівнює нулю).
Тепер ми хочемо, щоб наш корабель повернувся. Імовірно, ми хочемо зробити це якомога швидше, тому ми хочемо:
max (Sum_i x_i * c_i)
where c_i = <dir_i.x, dir_i.y, 0> CROSS <r_i.x, r_i.y, 0>
Рішення для x_i
's, задовольняючи вищезгадані нерівності та рівності, при цьому максимізуючи підсумок вище, дасть нам бажану тягу. Більшість мов програмування мають бібліотеку LP для них. Просто покладіть на нього вищевказану проблему, і вона дасть вашу відповідь.
Подібна проблема дозволить нам рухатися, не повертаючись. Скажімо, ми переписуємо свою проблему в систему координат, в якій ми хочемо рухатись у позитивному напрямку x. Тоді обмеженнями є:
0 <= x_i < fmax_i //for each i
max Sum_i x_i * dir_i.x
0 = Sum_i x_i * dir_i.y
0 = (Sum_i x_i * c_i)
where c_i = <dir_i.x, dir_i.y, 0> CROSS <r_i.x, r_i.y, 0> // as before
З обмеженням того, що тяги можуть створювати тягу тільки в одному напрямку, існують обмеження щодо виду обертання та лінійних швидкостей, яких ви зможете досягти. Це виявиться як рішення 0 = x_1 = x_2 = ... = x_n
, яке є , а це означає, що ви нікуди не потрапите. Щоб пом'якшити це, я пропоную додати пару маленьких, слабких (скажімо, 5% або 10%) штовхачів для кожного гравця, розміщеного тяга під 45 градусами з обох боків. Це дасть рішенню більшу гнучкість, оскільки вони можуть бути використані для протидії слабким вторинним ефектам основних рушіїв.
Нарешті, для наближення, можливо, 100 поштовхів, рішення LP дуже швидко, щоб зробити це на кадр. Однак, оскільки рішення не залежить від місця розташування або поточного стану, ви можете попередньо обчислити рішення для кожної розумної вхідної комбінації контролера щоразу, коли форма змінюється (це включає додавання не-тяжів, які змінюють момент інерції або масу корабля, бо тоді штовхачі знаходяться в іншому місці відносно центру маси!). Це 24 можливості (тобто 8 разів вказівки (лівий віджим, відсутність обертання, правий віджим)).