Простое физическое движение - PullRequest
30 голосов
/ 20 марта 2009

Я работаю над 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 ]

37 голосов
/ 20 марта 2009

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

Точка 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 и a при заданных значениях 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 <<strong> f <1) должно предотвратить эту нестабильность. </p>

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

3 голосов
/ 20 марта 2009

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

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

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

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

Таким образом, скорость на итерации n становится: v n = v 0 + n F - d v n-1

Вы попросили выбрать максимальную скорость, v nmax , которая происходит на итерации nmax.

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

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

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


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

нет пробела
2 голосов
/ 21 марта 2009

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

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

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

2 голосов
/ 20 марта 2009
velocity *= friction;

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

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

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

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

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

1 голос
/ 20 марта 2009

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

1 голос
/ 20 марта 2009

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

...