Динамическая балансировка двигателя космического корабля

14

Космические корабли в моей игре должны быть построены игроком с произвольным количеством движителей, прикрепленных где угодно с любым вращением. В настоящее время у меня есть грязный код для поворота корабля на заданный угол (ускорение и замедление).

Вот пример симметричного корабля, обращенного туда, куда указывает красная линия, которому говорят повернуть налево.

Судно

Однако, как вы можете себе представить, в зависимости от того, куда игрок поставил двигатели, иногда нежелательные линейные силы влияют на корабль. В этом случае корабль начинает двигаться вперед.

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

До сих пор я придумал формулу для определения «эффективности поворота», например, сколько вращения вызывается относительно линейного движения.

a - вектор положения для двигателя a b - вектор положения для двигателя b v1 - сила от двигателя a v2 - сила от двигателя b

performanceDelta = a.cross (v1) / | v1 | - (a.cross (v1) + b.cross (v2)) / | v1 + v2 |

, в основном "a.cross (v1 * t) / | v1 |" Предполагается, что эффективность поворота. И затем мы вычитаем это из-за эффективности поворота движителей вместе взятых, чтобы посмотреть, стоит ли запуск нового движителя.

Проблема возникает, когда я понимаю, что двигатели не должны быть включены / выключены, но могут изменять их тягу от 0 до 1. И как это сделать, когда игрок хочет, чтобы корабль шел вперед. Конечно, должен быть баланс того, сколько вращаться / двигаться.

Я не специалист в области ракетостроения, поэтому я надеюсь, что найдется кто-нибудь, кто скажет мне, можно ли рассчитать таким образом дроссель каждого двигателя и дать мне толчок в правильном направлении.

Спасибо, что нашли время! / Ким

Ким
источник
3
Я начал по тому же пути, но со многими конфигурациями невозможно вращать и не переводить. Так вы убираете вращение? Или вы разрешаете перевод? В конечном счете, дело за пользователем, проектирующим корабль. Для моей демонстрации этого я подделал это. Связанные: gamedev.stackexchange.com/questions/58216/… , gamedev.stackexchange.com/questions/40615/…
MichaelHouse
Я пошел по тому же пути и закончил тем, что написал демо на этой странице . Когда вы перемещаете двигатели (перетаскиваете их на корабль, чтобы установить положение и мощность), он рисует три фигуры. Интуиция заключается в том, что вы можете думать обо всех возможных движениях как о точке в трехмерном пространстве (x, y, вращение), и ограничение в 0-1 является ограничением в этом пространстве. Таким образом, вы получите трехмерную фигуру, содержащую все возможные движения. Если вам не нужна линейная скорость, вы смотрите на (x = 0, y = 0) линию в этом пространстве (Q, W, E, S все 0 в моей демоверсии)
amitp

Ответы:

7

Я предполагаю, что у вас есть физически правильное движение для вашего корабля, иначе этот анализ не будет проведен. Вам нужно что-то сильнее, чем эффективность, чтобы правильно решить эту проблему.

Каждый движитель будет оказывать два влияния на движение корабля: линейное и угловое. Это можно рассмотреть независимо. Если подруливающее устройство создает силу 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 направлений времени {вращение влево, вращение не влево, вращение вправо}).


источник
Очень хорошо объяснил!
Ким
1
Что Sum_iзначит в этом контексте?
С. Тарык Четин
1

Моей первой мыслью было чисто эмпирическое решение, которое заключается в том, чтобы смоделировать буровую установку в среде песочницы для различной степени тяги, чтобы определить, как она себя ведет. Вместо того, чтобы балансировать сложную математику в поиске детерминированного решения, вы можете достичь ее численно, например, с помощью метода Ньютона. Пример:

Диапазон для тяги составляет от 0 до 1000, где 1000 ALOT.

Шаг 1

Имитация с доверием (0 + 1000) / 2 = 500. Результат: слишком большое доверие

Шаг 2

Диапазон теперь от 0 до 500 Имитация с доверием (0 + 500) / 2 = 250. Результат: слишком большое доверие

Шаг 3

Диапазон теперь от 0 до 250 Имитация с доверием (0 + 250) / 2 = 125 Результат: слишком мало доверия

Шаг № 4

Теперь диапазон от 125 до 250. Имитация с доверием (125 + 250) /2=187.5. Результат - слишком большое доверие.

Шаг # 5 Диапазон теперь от 125 до 187,5. Имитация с доверием (125 + 187,5) /2=156.25 Результат - слишком мало доверия

Шаг № 6 Диапазон теперь 156,25–187,5 Диапазон ниже порогового значения 35, что означает, что это достаточно хорошая оценка

Окончательный результат = (187,5 + 156,25) / 2 = 171,875

Леннарт Роллан
источник