Простое физическое движение

Я работаю над 2D-игрой, где я пытаюсь ускорить объект до максимальной скорости, используя некоторый базовый физический код.

Вот псевдокод для этого:


const float acceleration = 0.02f;
const float friction     = 0.8f;  // value is always 0.0..1.0
      float velocity     = 0;
      float position     = 0;

move()
{
   velocity += acceleration;
   velocity *= friction;
   position += velocity;
}

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

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

т.е.


const float max_velocity = 2.0; 
const int   ticks;       = 120; // If my game runs at 60 FPS, I'd like a 
                                // moving object to reach max_velocity in 
                                // exactly 2 seconds.
const float acceleration = ?
const float friction     = ?

6 ответов

Решение

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

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

Пункт 2: Существуют более реалистичные физические модели для эффекта трения сопротивления. Одна модель (предложенная Адамом Лиссом) включает в себя силу сопротивления, пропорциональную скорости (известную как сопротивление Стокса, которое обычно применяется в ситуациях с низкой скоростью). Тот, который я ранее предложил, включает в себя силу сопротивления, пропорциональную квадрату скорости (известную как квадратичное сопротивление, которое обычно применяется в ситуациях с высокой скоростью). Я расскажу каждому из них о том, как вы могли бы вывести формулы для максимальной скорости и время, необходимое для эффективного достижения максимальной скорости. Я воздержусь от полных выводов, так как они довольно сложны.


Сопротивление Стокса:

Уравнение для обновления скорости будет:

velocity += acceleration - friction*velocity

которая представляет собой следующее дифференциальное уравнение:

dv/dt = a - f*v

Используя первую запись в этой интегральной таблице, мы можем найти решение (предполагая, что v = 0 при t = 0):

v = (a/f) - (a/f)*exp(-f*t)

Максимальная (т.е. конечная) скорость возникает при t >> 0, так что второе слагаемое в уравнении очень близко к нулю и:

v_max = a/f

Что касается времени, необходимого для достижения максимальной скорости, обратите внимание, что уравнение никогда по-настоящему не достигает ее, а вместо этого асимптотически приближается к ней. Однако, когда аргумент экспоненты равен -5, скорость составляет около 98% от максимальной скорости, вероятно, достаточно близко, чтобы считать ее равной. Затем вы можете приблизить время к максимальной скорости как:

t_max = 5/f

Затем вы можете использовать эти два уравнения для решения для f и заданного значения vmax и tmax.


Квадратичное сопротивление:

Уравнение для обновления скорости будет:

velocity += acceleration - friction*velocity*velocity

которая представляет собой следующее дифференциальное уравнение:

dv/dt = a - f*v^2

Используя первую запись в этой интегральной таблице, мы можем найти решение (предполагая, что v = 0 при t = 0):

v = sqrt(a/f)*(exp(2*sqrt(a*f)*t) - 1)/(exp(2*sqrt(a*f)*t) + 1)

Максимальная (то есть конечная) скорость возникает, когда t >> 0, так что экспоненциальные члены намного больше 1, и уравнение приближается:

v_max = sqrt(a/f)

Что касается времени, необходимого для достижения максимальной скорости, обратите внимание, что уравнение никогда по-настоящему не достигает ее, а вместо этого асимптотически приближается к ней. Однако, когда аргумент экспоненты равен 5, скорость составляет около 99% от максимальной скорости, вероятно, достаточно близко, чтобы считать ее равной. Затем вы можете приблизить время к максимальной скорости как:

t_max = 2.5/sqrt(a*f)

что также эквивалентно:

t_max = 2.5/(f*v_max)

Для желаемых значений vmax и tmax второе уравнение для tmax скажет вам, каким должно быть f, а затем вы можете включить это в уравнение для vmax, чтобы получить значение для a.


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

Еще один момент: я не сразу понял это, но обновление скорости больше не нужно, если вы вместо этого используете формулы, которые я получил для v(t). Если вы просто моделируете ускорение из состояния покоя и отслеживаете время с начала ускорения, код будет выглядеть примерно так:

position += velocity_function(timeSinceStart)

где "speed_function" - одна из двух формул для v(t), и вам больше не понадобится переменная скорости. В общем, здесь есть компромисс: вычисление v(t) может быть более вычислительно дорогим, чем простое обновление скорости с помощью итерационной схемы (из-за экспоненциальных членов), но оно гарантированно останется стабильным и ограниченным. При определенных условиях (например, попытка получить очень короткое tmax), итерация может стать нестабильной и взрывной, что является общей проблемой для прямого метода Эйлера. Однако поддержание ограничений на переменные (например, 0 < f <1) должно предотвратить эту нестабильность.

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

Предупреждение: частичное решение

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

В качестве альтернативы рассмотрим две силы, действующие на ваш объект:

  • Постоянная внешняя сила, F, которая ускоряет его, и
  • Сила сопротивления, d, которая пропорциональна скорости и имеет тенденцию замедлять ее.

Так что скорость на итерации n становится: vn = v0 + n F - dvn-1

Вы попросили выбрать максимальную скорость, vnmax, которая возникает при итерации nmax,

Обратите внимание, что проблема недостаточно ограничена; то есть F и d связаны между собой, поэтому вы можете произвольно выбрать значение для одного из них, а затем вычислить другое.

Теперь, когда мяч катится, кто-нибудь готов поднять математику?

Предупреждение: это уродливо и включает в себя степенные ряды!


Изменить: почему последовательность n**F** в первом уравнении появляются буквально, если нет пробела после n?

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

static double lastUpdate=0;
if (lastUpdate!=0) {
  deltaT = time() - lastUpdate;
  velocity += acceleration * deltaT;
  position += velocity * deltaT;
}
lastUpdate = time();

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

velocity *= friction;

Это не мешает скорости двигаться вокруг определенной точки...

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

Итак, вы хотите что-то вроде этого:

velocity += (acceleration - friction);
position += velocity;
friction = a*exp(b*velocity);

Где вы выбираете значения для а и б. b будет контролировать время, необходимое для достижения максимальной скорости, а a будет контролировать, как резко возрастает трение. (Опять же, не проводите собственных исследований по этому вопросу - я исхожу из того, что помню из физики 12-го класса.)

Если вы хотите увидеть, что можно сделать с очень простыми физическими моделями с использованием очень простых математических упражнений, взгляните на некоторые проекты Scratch по адресу http://scratch.mit.edu/ - вы можете получить некоторые полезные идеи, и вы конечно повеселиться.

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

Другие вопросы по тегам