2D Космический корабль движения математика - PullRequest
25 голосов
/ 23 мая 2010

Я пытаюсь сделать игру с космическим кораблем сверху вниз и хочу, чтобы движение было несколько реалистичным. 360 градусов с инерцией, гравитацией и т. Д.

Моя проблема в том, что я могу без проблем заставить корабль двигаться по инерции на 360 °, но мне нужно установить ограничение на скорость работы двигателей, не ограничивая при этом другие силы, толкающие / толкающие корабль. *

Таким образом, если частота вращения двигателя не превышает 500, а корабль движется с гравитационной скважиной на 1000, корабль не будет двигаться на 1500, когда его двигатели включены, но если он направлен в сторону от угла, то это может замедлиться.

Для чего я стою, я использую Конструкция , и все, что мне нужно, это математика.

Спасибо за любую помощь, я облысел от попыток выяснить это.

Ответы [ 5 ]

25 голосов
/ 23 мая 2010

Возьмите страницу из относительной физики , где объекты не могут превышать скорость света :

(см. Ниже длямой рабочий фрагмент кода C ++ и запущенная демонстрация [только для Windows].)

  1. Установите постоянную c на максимальную скорость, которую может достичь объект («скорость света»)"в вашей игре).
  2. Если применение силы увеличит скорость объекта, разделите ускорение (изменение скорости) на коэффициент Лоренца. Условие if нереально с точки зрения специальной теории относительности, но оно делает корабль более «управляемым» на высоких скоростях.
  3. Обновление: Обычно при движении корабль будет трудно маневрироватьна скоростях, близких к c, потому что изменение направления требует ускорения, которое толкает скорость выше c (Фактор Лоренца в конечном итоге приведет к тому, что ускорение в новом направлении будет практически нулевым). Чтобы восстановить маневренность, используйте направление, в котором вектор скорости был бы без масштабирования Лоренца.с величиной вектора масштабированной скорости.

Объяснение:

Определение коэффициента Лоренца, где v - скорость, а c - скоростьlight: gamma = 1 / sqrt(1 - v^2 / c^2)

Это работает, потому что фактор Лоренца приближается к бесконечности с увеличением скорости.Объектам потребуется бесконечное количество силы, приложенной, чтобы пересечь скорость света.При более низких скоростях коэффициент Лоренца очень близок к 1, приближаясь к классической ньютоновской физике.

График коэффициента Лоренца при увеличении скорости:

alt text

Примечание. Ранее я пытался решить аналогичную проблему в игре с астероидами, играя с настройками трения.Я только что придумал это решение, когда читал ваш вопрос ^^

Обновление: Я попытался реализовать это и обнаружил один потенциальный недостаток: ускорение во всех направлениях ограничено, так как скоростьсвета c приближается, включая замедление!(Неудобно, но разве это происходит со специальной теорией относительности в реальном мире?) Я думаю, этот алгоритм можно изменить, чтобы учесть направления векторов скорости и силы ... Алгоритм был измененчтобы учитывать направления векторов, чтобы корабль не «терял управляемость» на высоких скоростях.

Обновление: Вот фрагмент кода из моей игры астероидов, которыйиспользует фактор Лоренца для ограничения скорости игровых объектов.Это работает очень хорошо!

обновление: * добавлено загружаемая демоверсия (только для Windows; сборка из исходного кода для других платформ) этого алгоритма в действии. I'mне уверен, все ли зависимости были включены в zip;пожалуйста, дайте мне знать, если чего-то не хватает.И веселиться ^^

void CObject::applyForces()
{
    // acceleration: change in velocity due to force f on object with mass m
    vector2f dv = f/m;

    // new velocity if acceleration dv applied
    vector2f new_v = v + dv;

    // only apply Lorentz factor if acceleration increases speed
    if (new_v.length() > v.length())
    {
        // maximum speed objects may reach (the "speed of light")
        const float c = 4;

        float b = 1 - v.length_squared()/(c*c);
        if (b <= 0) b = DBL_MIN;

        double lorentz_factor = 1/sqrt(b);
        dv /= lorentz_factor;
    }

    // apply acceleration to object's velocity
    v += dv;

    // Update:
    // Allow acceleration in the forward direction to change the direction
    // of v by using the direction of new_v (without the Lorentz factor)
    // with the magnitude of v (that applies the Lorentz factor).
    if (v.length() > 0)
    {
        v = new_v.normalized() * v.length();
    }
}
2 голосов
/ 08 октября 2011

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

Вместо того, чтобы вычислять коэффициент Лоренца (который сам является обратным), а затем делить его следующим образом:

        double lorentz_factor = 1/sqrt(b);
        dv /= lorentz_factor;

просто умножьте на обратную величину коэффициента Лоренца, например:

        double reciprocal_lorentz_factor = sqrt(b);
        dv *= reciprocal_lorentz_factor;

Это исключает одну операцию с плавающей запятой из кода, а также избавляет от необходимости фиксировать b в DBL_MIN (теперь он может быть ограничен до 0, потому что мы больше не делим). Зачем делить на обратную величину x , если вы можете просто умножить на x ?

Кроме того, если вы можете гарантировать, что величина v никогда не превысит c , то вы можете исключить проверку b , которая меньше нуля.

Наконец, вы можете исключить две дополнительные операции sqrt(), используя length_squared() вместо length() во внешнем операторе if:

    if (new_v.length_squared() > v.length_squared())
    {
        const float c = 4;

        float b = 1 - v.length_squared()/(c*c);
        if (b < 0) b = 0;

        double reciprocal_lorentz_factor = sqrt(b);
        dv *= reciprocal_lorentz_factor;
    }

Это может привести к разнице в скорости только на 0,1%, но я думаю, что код проще таким образом.

2 голосов
/ 23 мая 2010

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

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

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

Это оставляет нам снижение эффективной силы вашего двигателя до 0 при достижении определенной скорости. Теперь имейте в виду, что если вы движетесь с максимальной скоростью в северном направлении, вы все же хотите, чтобы сила могла подтолкнуть вас в восточном направлении, поэтому ваши двигатели не должны отключаться только с необработанной скоростью, а должны основываться на скорости вашего двигаясь в направлении, указанном вашими двигателями.

Итак, по математике:

Вы хотите сделать крестик точечное произведение между вектором наведения вашего двигателя и вектором скорости, чтобы получить эффективную скорость в направлении, указанном вашими двигателями. Если у вас есть эта скорость, скажем, 125 миль в час (с максимальной скоростью 150), вы можете уменьшить силу ваших двигателей до (150-125) / 150 * (Force of Engines).

Это кардинально изменит график скорости, показывающий, сколько времени вам понадобится, чтобы разогнаться до полной скорости. По мере приближения к полной скорости ваши двигатели становятся все менее и менее мощными. Проверьте это и посмотрите, хотите ли вы этого. Другой подход состоит в том, чтобы просто сказать Force of Engines = 0, если скалярное произведение> = 150, в противном случае это полная сила. Это позволит вам линейно ускоряться до максимальной скорости, но не дальше.

Теперь, когда я думаю об этом, эта модель не идеальна, потому что вы могли бы разогнаться до 150 миль в час в северном направлении, а затем повернуть на восток и разогнаться до 150 миль в час, двигаясь в этом направлении, в общей сложности 212 миль в час в направление на северо-восток, поэтому не идеальное решение.

1 голос
/ 23 мая 2010

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

Уравнение Ньютона для силы: F = M*A Мы можем изменить это значение на A = F/M, чтобы получить ускорение. В основном вам нужно выяснить, насколько корабль должен ускоряться и в каком направлении (векторе), затем прибавить это ускорение к скорости корабля и добавить скорость корабля в его положение.

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

gravity = //calculate force of gravity acting on ship from Newton's law of universal gravitation
friction = //ten percent of the ship's velocity vector, in the opposite direction
engines = 0
if (engines_are_firing)
    engines = 500
forces = gravity + friction + engines
acceleration = forces / ship.mass
ship.velocity += acceleration
ship.position += velocity
redraw()
0 голосов
/ 23 мая 2010

Мне трудно понять ваш вопрос, но похоже, что вы не используете настоящую физику для этой игры. Рассматривали ли вы использование реальных физических уравнений, таких как скорость, ускорение, сила и т. Д.?

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

Например, в среде имеется вектор гравитации (сила направленности), поэтому вам необходимо учитывать это при расчете силы, направленной двигателем.

Ваш корабль должен хранить собственную мощность двигателя, ускорение и скорость.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...