Подтвердить что ты не робот

Математика 2D космического корабля

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

Объяснение:

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

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

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

alt text

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

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

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

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

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 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

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

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

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

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

Итак, для математики:

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

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

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

Ответ 3

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

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

        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% -ную разницу в скорости, но я думаю, что этот код проще.

Ответ 4

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

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

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

gravity = //calculate force of gravity acting on ship from Newton law of universal gravitation
friction = //ten percent of the ship 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()

Ответ 5

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

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

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

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