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

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

Я работаю над 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     = ?
4b9b3361

Ответ 1

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

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

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


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

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

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)

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

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

Ответ 2

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

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

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

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

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

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

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

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

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


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

Ответ 3

velocity *= friction;

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

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

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

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

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

Ответ 4

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

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

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

Ответ 5

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

Ответ 6

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