Я начинаю изучать физику DIY, и у меня есть вопрос о реализации интеграции на самом базовом уровне (т.е. это не вопрос Эйлера против РК4).
Почти каждый пример, с которым я сталкиваюсь, имеет некоторую integrate()
функцию, которая получает временной шаг с момента последнего обновления и обновляет ускорение (и / или скорость и / или положение) с момента последнего обновления.
В простейшем виде: position += velocity * deltaTime
Тем не менее, я не понимаю, почему он накапливается так, когда его можно так же легко получить, изменив функцию . Например: getPosition = makeNewFunction()
который может возвращать то, что имеет сигнатуру Time -> Position
, и внутренняя работа этой функции генерируется с помощью соответствующей математической формулы.
Таким образом, нет накопления ... всякий раз, когда необходимо получить позицию, она вызывает эту функцию с текущим временем.
Мое понимание новичка заключается в том, что это также позволит избежать ошибок, возникающих из-за накопления ... так почему это не работает, что я пропускаю?
(FWIW я сделал собрать основные доказательства концепции этого idea- , хотя это также тестирование несколько других вещей , в то же время , так что это не самый чистый пример: https://github.com/dakom/ball-bounce-frp )
РЕДАКТИРОВАТЬ 1: как упомянуто в комментариях, вероятно, важно отметить, что я еще не узнал об изменении ускорения или о работе с рывками и другими вещами, которые требуют интеграции более высокого порядка, чем постоянное ускорение.
EDIT 2: здесь некоторые основные примеры кода идеи, и псевдо Javascript синтаксис - обратите внимание , что getKinematicPosition
это частично применяется так оно возвращает новую функцию только время -> Положение:
Я придерживаюсь позиции здесь, но это может быть что-то еще, например getVelocity
, я думаю ...
getKinematicPosition = initialVelocity => acceleration => time =>
((.5 *acceleration) * (time * time)) + (initialVelocity * time);
getPosition = getKinematicPosition ([0,0,0]) (GRAVITY);
onTick = totalTime => {
position = getPosition (totalTime);
onCollision = () => {
getPosition = changeTheFunction(totalTime);
//changeTheFunction uses totalTime to base updates from 0
//it could use getKinematicPosition or something else entirely
}
}
источник
Ответы:
Это будет работать для определенных классов задач, и ключевая фраза для поиска - это решение в закрытой форме . Например, в космической программе «Кербал» движение космического корабля на орбите рассчитывается таким образом. К сожалению, большинство нетривиальных задач (например, выход в атмосферу упомянутого космического корабля) не имеют известного решения в замкнутой форме. Таким образом, потребность в математически более простых числовых приближениях (то есть
integrate()
во времени).источник
Проблема с вашим подходом в том, что у вас нет истории вашего объекта. Вы можете вычислить позицию, если будете двигаться в направлении, но что произойдет, если вы нажмете что-то и отскочите назад?
Если вы накапливаете с вашей последней известной позиции, вы можете справиться с ударом и идти дальше. Если вы попытаетесь рассчитать его с самого начала, вам придется каждый раз пересчитывать удар или устанавливать его в качестве новой стартовой позиции.
Ваш пример напомнил мне гоночную игру. (Я не знаю, будет ли положение контролироваться физическим двигателем, но я думаю, что это прекрасно работает, чтобы объяснить)
Если вы едете на машине, вы можете ускоряться и замедляться. Вы не можете рассчитать свою позицию, не зная, как профиль скорости вашего автомобиля выглядел с самого начала и до настоящего времени. Накопление расстояния намного проще, чем сохранение скорости, которую вы имели в каждом кадре от начала до настоящего момента.
Отказ от ответственности: я до сих пор не написал физику игры, просто я вижу проблему.
Изменить:
На этой диаграмме вы можете увидеть, как значения меняются со временем.
красный = ускорение (от начала ускорения к наклону вниз)
зеленый = скорость (от начала до остановки)
синий = путь, которым вы пошли.
Общая скорость - это интеграл ускорения от начальной точки до фактической регистрации. (Область между линией и осью)
Путь является интегралом вашей скорости.
Если вам известны значения вашего ускорения, вы можете рассчитать другие значения. Но если я не ошибаюсь, интегралы также рассчитываются путем накопления на ПК. И это намного сложнее хранить все значения ускорения.
Кроме того, это, вероятно, слишком много, чтобы рассчитывать каждый кадр.
Я знаю, у меня отличные навыки рисования. ;)
Редактировать 2:
этот пример для линейного движения. Нарушение направления делает это еще более сложным.
источник
Вы можете!
Он вызывается с использованием аналитической или закрытой формы решения. Преимущество состоит в том, что он является более точным, поскольку ошибки округления, которые накапливаются с течением времени, отсутствуют.
Однако это работает тогда и только тогда, когда вы заранее знаете такую закрытую форму. Для игр это довольно часто просто не так.
Движение игрока нестабильно и просто не может быть помещено в какую-то предварительно вычисленную функцию. Игрок может и будет менять свою скорость и ориентацию довольно часто.
NPC могут потенциально использовать решения в закрытой форме, и фактически они иногда используют. Однако у этого есть некоторые другие недостатки. Подумайте о простой гоночной игре. Каждый раз, когда ваш автомобиль сталкивается с другим транспортным средством, вы должны изменить свою функцию. Может быть, машина движется быстрее в зависимости от метро. Тогда найти такое решение в замкнутой форме будет довольно сложно. В действительности, вероятно, существует больше случаев, когда найти такую замкнутую форму невозможно или настолько сложно, что это просто невозможно.
Отличным примером использования решения в закрытой форме является Kerbal Space Program. Как только ваша ракета находится на орбите и не находится под ударом, KSP может поставить ее «на рельсы». Орбиты предопределены в системе двух тел и являются периодическими. Пока ракета не применяет больше тяги, вы уже знаете, где будет находиться ракета, и вы можете просто позвонить
getPositionAtTime(t)
(она точно не названа, но вы понимаете).На практике, однако, просто использование пошаговой интеграции часто гораздо более практично. Но когда вы видите ситуацию, когда решение в замкнутой форме существует и его легко вычислить, сделайте это! Нет причин не использовать его.
Например, если ваш персонаж нацеливает пушку, вы можете легко показать прогнозируемую точку удара пушечного ядра, используя решение в замкнутой форме. И, если ваша игра не позволяет изменить ход пушечного ядра (например, без ветра), вы даже можете использовать его для перемещения пушечного ядра. Обратите внимание, что тогда вам нужно особенно внимательно следить за препятствиями, движущимися на пути вашего ядра.
Есть много похожих ситуаций. Если вы строите игру на основе раундов, то, вероятно, будет гораздо больше доступных решений закрытых форм, чем при создании игры RTS, поскольку вы заранее знаете все параметры и можете с уверенностью сказать, что они не меняются (ничего не происходит внезапно) на этот путь, например).
Обратите внимание, что существуют методы борьбы с числовыми неточностями ступенчатой интеграции. Например, вы можете отслеживать накопленную ошибку и применять корректирующий термин для контроля ошибки, например, суммирование по Кахану.
источник
В случае простого прыгающего мяча найти решение в закрытой форме легко. Однако более сложные системы, как правило, требуют решения обыкновенного дифференциального уравнения (ОДУ). Числовые решатели необходимы для обработки всех случаев, кроме самых простых.
Действительно, есть два класса числовых решателей ODE: явный и неявный. Явные решатели обеспечивают приближенную форму для вашего следующего состояния, в то время как неявные решатели требуют решения уравнения для этого. То, что вы описываете для своего прыгающего мяча, на самом деле является неявным решателем ODE, знаете ли вы об этом или нет!
Преимущество неявных решателей заключается в возможности использовать намного большие временные шаги. Для вашего алгоритма прыгающего мяча ваш временной шаг может быть как минимум таким же, как и продолжительность до следующего столкновения (что изменило бы вашу функцию). Это может заставить вашу программу работать намного быстрее. Однако, в общем, мы не всегда можем найти хорошие неявные решения для интересующих нас ODE. Когда мы не можем, мы возвращаемся к явной интеграции.
Большое преимущество, которое я вижу в явной интеграции, состоит в том, что ошибки хорошо известны. Вы можете открыть любой учебник 60-х годов и прочитать все, что вам нужно знать о небольших причудах, возникающих при использовании определенных методов интеграции. Таким образом, разработчик изучает эти навыки один раз, и им никогда не придется изучать их снова. Если вы делаете неявную интеграцию, каждый сценарий использования немного отличается, с немного отличающимися ошибками. Немного сложнее применить то, что вы узнали из одной задачи, к следующей.
источник
pos (t) = v (t) * t
работает только если pos (0) = 0 и v (t) = k
Вы не можете связать положение со временем без знания начального условия и всей функции скорости, поэтому уравнение является приближением интеграла
pos (t) = интеграл от v (t) dt от 0 до t
РЕДАКТИРОВАТЬ _________
Вот небольшое доказательство в комментариях (при условии pos (0) = 0)
пусть v (t) = 4
уравнение 1: pos (t) = 4 * t (правильно)
уравнение 2: pos (t) = c + 4 * t от 0 до t = 4 * t (правильно)
пусть v (t) = 2 * t
уравнение 1: pos (t) = 2 * t ^ 2 (неверно)
уравнение 2: pos (t) = c + t ^ 2 от 0 до t = t ^ 2 (правильно)
Я должен добавить, что ваше уравнение уже учитывает постоянное ускорение (т.е. ваше уравнение равно 2, где v (t) = v0 + a * t и пределы интегрирования равны t0 и t), поэтому ваше уравнение должно работать до тех пор, пока вы обновляете начальное положение, начальная скорость и ускорение остаются постоянными.
РЕДАКТИРОВАТЬ 2 ________
Я также должен добавить, что вы также можете рассчитать положение с начальным положением, начальной скоростью, начальным ускорением и постоянным рывком. Другими словами, вы можете создать функцию, основанную на уравнении 2, которая представляет позицию в зависимости от времени, разделив ее на ее производные: скорость, рывок, что будет дальше, и т. Д., И т. Д., И т. Д., Но вы будете точны в своем уравнении, только если v (t) можно смоделировать таким образом. Если v (t) не может быть смоделировано только с помощью скорости, ускорения, постоянного рывка и т. Д., То вам нужно вернуться к приближению 2, что обычно происходит, когда у вас есть прыгающие вещи, сопротивление воздуха, ветер и т. Д. ,
источник