Как сделать, чтобы уравнение перетаскивания жидкости не зависело от частоты кадров - PullRequest
2 голосов
/ 07 ноября 2011

Я пытаюсь спланировать игру, которую начал писать.(Очень много в начале)

Моя проблема в том, что я хочу, чтобы часть ускорения / движения всех игровых объектов основывалась на силе ускорения и сопротивлении (таким образом приводя к конечной скорости как верхнему пределу доступной скорости)

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

Я делаю 2D-игру и использую переменные Vector2 для положения, курса и силы тяги (примененная сила ускорения).Он работает сверху вниз, поэтому гравитация не является частью уравнения.

Прежде чем кодировать его, я проверяю контрольные примеры в Excel - именно так я проверяю свою математику перед тем, как передать математику в код.И я обнаружил, что мое использование уравнения сопротивления делает рассматриваемый объект зависимым от частоты кадров !! В частности, чем выше частота кадров, тем ниже конечная конечная скорость.

Я пытался изменить уравнения по мере необходимости для учета частоты кадров, но это ускользает от меня.

Если вы хотите работать с той же таблицей, что и я, вы можетескачайте таблицу здесь .

Но вам не нужно - вот особенности.

Уравнение сопротивления, как я понимаю, таково:

Drag = 0.5 * FluidDensity * Velocity * Velocity * DragCoefficient * IncidenceArea

Используя некоторые числа, взятые из воздуха, для вычислений, если Плотность жидкости равна 0,233, а Коэффициент сопротивления равен 0,4, а Попутная площадь равна 0,1, а Сила ускорения составляет 50 пикселей в секунду, то вот что происходит:

Если я рассчитываю, что ускорение применяется каждые 0,25 секунды (один раз в четверть секунды) при 1/4 силы ускорения (для согласования по времени), то мы достигаем конечной скорости около 39,3 пикселей в секунду.

Если я вычисляювместо ускорения каждую секунду мы достигаем конечной скорости около 53,6 пикселей в секунду.

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

//In globals / initialization:
Vector2 Position;
Vector2 Speed;
Vector2 ThrustForce;
float Density = 0.233f;
float DragCoefficient = 0.4f;
float IncidentalArea = 0.1f;

//In the update loop
//DeltaTime is a float based upon how much of a second passed
Vector2 AccelerationToApply = ThrustForce * DeltaTime;
Vector2 NewSpeed = Speed + AccelerationToApply;
Vector2 Drag = Speed * Speed * 0.5f * Density * DragCoefficient * IncidentalArea;
NewSpeed -= Drag;
Speed = NewSpeed;

Это математическая проблема.Вот вопрос:

Как это выразить так, чтобы он не зависел от частоты кадров?

Ответы [ 2 ]

3 голосов
/ 07 ноября 2011

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

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

1 голос
/ 08 ноября 2011

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

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

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

//In globals / initialization:
Vector2 Position;
Vector2 Speed;
Vector2 ThrustForce;
float Coefficient = 0.009f;
float PreviousDrag = 0.000f;

//In the update loop
//DeltaTime is a float based upon how much of a second passed
Vector2 AccelerationToApply = ThrustForce * DeltaTime + PreviousDrag * DeltaTime;
Vector2 NewSpeed = Speed + AccelerationToApply;
PreviousDrag = Coefficient * NewSpeed * NewSpeed;
Speed = NewSpeed;

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

...