Pull to refresh

Comments 37

speed += acceleration * deltaTime;
speed *= pow(friction, deltaTime);
position += speed * deltaTime;

И хотя это как будто сработает, на самом деле так делать неправильно. Можете проверить сами.


Потому что физику не обманешь — расстояние это интеграл от изменения скорости по времени, а не просто произведение моментальной скорости на время. По-сути, он считал раньше интеграл дискретным суммированием и делать это можно лишь с минимальным возможным шагом времени, но попытка увеличивать этот шаг сразу же дает ошибку. В правильном варианте надо вывести функцию изменения скорости (а вывести ее с таким трением будем не просто) и затем интегрировать. В крайнем случае можно хотя бы приближенно брать (speed — prevSpeed) * deltaTime/ 2, но это тоже не очень точно.

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


Это в Maple формулка такая вышла?
Это в Mathematica. Вверху видно условие, а ниже решение, которое получилось )
Решалась обратная задача — имея формулу движения найти сколько времени лететь до остановки.
Тут, похоже, нужны численные методы с адаптивным шагом. Ну или предрасчёт, зависит от игровой механики.
Я думаю что тут проблема в том, что обычно численные/разностные схемы — многопроходные, а это сильно увеличит время обработки
(посыпает голову пеплом)
(speed — prevSpeed) * deltaTime/ 2

+ конечно же
Да, было бы очень интересно прочитать.
А что там мечтать, идти надо и делать. Начать можно просто, технологий масса.
Слишком сложно?
Геймдев — это ведь не только разработка движков.
Функцию изменения сокрости не обязательно находить, см. интегрирование Верле.
Глядя на вашу формулу, понимаешь, что это тот самый момент, когда проще численно интегрировать. У вашей системы решения гладкие, поэтому при выборе корректного метода, численное решение будет сравнимо по точности с аналитическим. Не прямоугольниками или трапециями, а, например методом Рунге — Кутты, или как выше сказал — Верле, через разложение в ряд Тейлора.
Большое спасибо за ссылку на Верле, не знал о таком
Зачем вычислять моментальную скорость (которая нам не нужна) и неправильно считать от неё позицию, когда можно просто составить формулу позиции от времени, которая совершенно несложная?

Вы не поверите, именно это я и написал, теми же словами :)

Ха, при чтении поста не покидало желание скинуть в комменты линк на другой Ваш перевод. И тут на тебе, заключение.
Спидраннеры. Спидраннеры заметят. Вскоре после выхода игры они заметили, что некоторые люди в списках рекордов спидрана имели более плохое время прохождения, но по подсчёту оказавшееся более хорошим, чем у других. И непосредственной причиной этого была нечёткость таймингов и отключение vsync в игре (или 144-герцовые мониторы). Поэтому стало очевидно, что нужно выключать эту нечёткость при отключении vsync.


Лично мне стало очевидно, что необходимо вводить две отдельные категории для спидранов. Все баги в программе не поправить, найти новые баги в программе упорные спидранеры всегда смогут. Какой смысл ориентироваться на них?
дело не только в спидранерах, запустите старую игру, вроде half-life и попробуйте «двинуть ящик» он улетит очень далеко, а все дело в том, что было рассчитано на 20-30 фпс, а при фпс 100 (комфортный по плавности) все ускоряется.
Насколько я знаю, в спидранах уже давно есть категории по использованию багов, причем больше двух и для разных игр разные (в зависимости от того, насколько эти баги влияют на геймплей).
А неправильный подсчет времени, который зависит от случайных факторов — это довольно неприятно, и не только для спидраннеров. Если его можно исправить без критических проблем, то очевидно, что лучше это сделать.
Насколько я знаю, в спидранах уже давно есть категории по использованию багов, причем больше двух и для разных игр разные (в зависимости от того, насколько эти баги влияют на геймплей).

И я знаю. К чему это?

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

Для кого ещё кроме спидранеров и разработчика (по вполне очевидным причинам)?
Update c произвольным deltaTime всё равно будет источником накопления ошибок округления.
.1+.2=.30000000000000004
Можно считать симуляцию мира с фиксированным шагом, а само отображение делать за счёт интерполяции сколько угодно FPS.
Т.е. непосредственно для отрисовки переменный шаг времени — это отлично, но для самой игры, проверки столкновений, ИИ — это не нужно. Непонятно почему автор не предлагает гибридный подход.
А можно ли в отдельном потоке в бесконечном цикле запустить функцию общёта симуляции мира, а в потоке отрисовки его отображать с фиксированным интервалом?
Отдельные потоки для симуляции и отрисовки уже давно используются.
V-Sync по факту фиксированный интервал, привязанный к монитору.
UFO just landed and posted this here
А что делать, если фпс ниже чем шаг времени для изменения мира?
А это так и должно быть. Вполне нормально считать физику за 20-30 а то и больше итераций на кадр.
Ну это зависит от необходимой точности и метода интегрирования. Для метода Эйлера, как в статье, это так.
Но для фиксированного шага можно использовать, например, интегрирование Верле — там число итераций можно сделать меньше. Не обязательно каждый кадр считать физику, особенно если там 144 Гц монитор и быстрая видеокарта.
Как раз наоборот, игра считает физику не 20/30 за кадр, а каждый кадр. Просто изначально железо позволяло дать 20/30 кадров и все работало с нужной скоростью, а на современном железе ситуация другая.
Стоит уточнить что есть «считает физику». Новое положение объектов (анимация) действительно вычисляется каждый кадр, однако это достаточно просто, можно целиком запихнуть в вершинный шейдер чтобы видеокарта сама считала поворот и смещение.
Рассчёт геометрии для коллизий, приложенных сил и импульсов, ограничений, ИИ — более тяжёлые в вычислительном плане операции, которые довольно накладно делать каждый кадр.
Можно замедлить игру (если это для одного игрока) или несколько раз за кадр пересчитывать мир (что не такая уж и редкость на самом деле).

Автор как раз ссылается на такой подход из статьи Гленна Филдера "Fix Your Timestep", сложности и недостатки подхода тоже перечислены в статье автора.

Это хорошее замечание.
Да, более того — этот подход уже реализован.
Когда я делал игры с переменным шагом обновления, я просто не допускал ситуаций с deltaTime > 1. Если оно реально становилось больше, я просто повторял цикл обновления нужное количество раз, сначала с deltaTime = 1, и потом с дробным остатком. Да, это заметно медленнее, но и код значительно проще, а ситуация с регулярным deltaTime > 1 в принципе неадекватна (компьютер не тянет игру), чтобы считать её нормой, а не исключением.

Делают расчет физики на 60 герц, а потом у людей с нормальными мониторами (144 Hz) все работает непонятно как.


Апофиозом из того что я наблюдал было слизерио. На 144-герцевой развёртке невозможно было играть — жуткие дёргания 2-3 раза в секунду. Пришлось переключаться на 60 герц.


Считайте ключевые точки на 60 герцах и интерполируйте между ними если сложно сделать переменный шаг.

А сбрасывание дельты при достаточном накоплении погрешности к чему приведёт?
Мне кажется что это тоже может решить часть проблемы, но я в этом не уверен.
Сам с рендером работал только на начальном уровне. Но в будущем планирую развернуться немного.
Потому подобная статья и советы от знающих ценю :)
Sign up to leave a comment.

Articles