Я предполагаю, что у вас есть физически правильное движение для вашего корабля, иначе этот анализ не будет проведен. Вам нужно что-то сильнее, чем эффективность, чтобы правильно решить эту проблему.
Каждый движитель будет оказывать два влияния на движение корабля: линейное и угловое. Это можно рассмотреть независимо. Если подруливающее устройство создает силу 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) является 2D вектором.
Смысл этой экспозиции в том, что теперь мы можем написать нашу задачу в виде линейной программы . Скажем сначала, мы хотим, чтобы наш корабль вращался без движения . У нас есть переменная для каждого двигателя, $ 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
задачи при соблюдении указанных выше неравенств и равенств при максимальном суммировании, приведенном выше, даст нам желаемую тягу. Большинство языков программирования имеют для них доступную библиотеку LP. Просто поместите вышеупомянутую проблему в нее, и она даст ваш ответ.
Подобная проблема позволит нам двигаться без поворота. Скажем, мы переписываем нашу задачу в систему координат, в которой мы хотим двигаться в положительном направлении х. Тогда ограничения:
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 направлений времени {вращение влево, вращение не влево, вращение вправо}).