«Super Meat Boy» - это сложный платформер, недавно вышедший для ПК, требующий исключительного контроля и идеального прыжка в пикселях. Физический код в игре зависит от частоты кадров, которая установлена на 60 кадров в секунду; это означает, что если ваш компьютер не может запустить игру на полной скорости, физика сойдет с ума, в результате чего (среди прочего) ваш персонаж будет работать медленнее и падать сквозь землю. Кроме того, если vsync выключен, игра работает очень быстро.
Могут ли те, кто имеет опыт программирования 2D-игр, объяснить, почему игра была написана таким образом? Разве физический цикл, работающий с постоянной скоростью, не будет лучшим решением? (На самом деле, я думаю, что физический цикл используется для частей игры, так как некоторые из сущностей продолжают нормально двигаться независимо от частоты кадров. С другой стороны, ваш персонаж работает точно [fps / 60] так же быстро.)
Что меня беспокоит в этой реализации, так это потеря абстракции между игровым движком и графическим рендерингом, которая зависит от системных особенностей, таких как монитор, видеокарта и процессор. Если по какой-либо причине ваш компьютер не может справиться с vsync или не может запустить игру со скоростью ровно 60 кадров в секунду, он впечатляюще сломается. Почему шаг рендеринга должен каким-либо образом влиять на физические расчеты? (В настоящее время большинство игр либо замедляют игру, либо пропускают кадры.) С другой стороны, я понимаю, что платформеры старой школы на NES и SNES зависели от фиксированной частоты кадров для большей части их управления и физики. Почему это так, и можно ли создать патформер в этом ключе, не имея зависимости частоты кадров? Обязательно ли происходит потеря точности, если вы отделяете рендеринг графики от остальной части движка?
Спасибо, и извините, если вопрос был запутанным.
Ответы:
Горстка причин, сделай свой выбор: они не знали ничего лучше. Это быстрее и проще в реализации. Они были сосредоточены больше на игровом процессе и меньше на крайних случаях, которые могут не возникнуть в большинстве случаев.
Вы довольно хорошо объяснили, почему нет. Я уверен, что вы заметили, что есть много тем, которые охватывают эту тему . Я не уверен, что вы найдете удовлетворительный ответ помимо тех, которые я перечислил.
источник
Изначально SMB был консольной игрой, в которой можно с уверенностью предположить, что он способен работать со скоростью 60 кадров в секунду на всех Xbox360 (ну, может быть, 50 для некоторых игроков PAL). Предполагая, что фиксированный временной шаг упрощает код довольно много.
Хотя многие вещи легко масштабировать с помощью переменного временного шага - «pos + = скорость * временного шага», довольно сложно сделать это правильно, когда вы имеете дело с ускорениями, скоростями изменения ускорения и так далее.
Разделение игрового процесса и рендеринга - хорошее теоретическое решение , но реализовать его хорошо (с хорошей интерполяцией) довольно сложно, и вещи могут легко запутаться. Этот метод довольно редко используется в реальных играх (хотя некоторые крупные игры делают это, особенно в играх RTS, но больше для синхронизации сетевых игр).
При проектировании для фиксированного разрешения экрана и фиксированной частоты кадров есть еще одна вещь, которую вы можете сделать, чтобы сделать прокрутку более плавной. Вы можете гарантировать, что игра прокручивается с целым числом пикселей на кадр - избегая любого «субпиксельного колебания», которое вы можете получить, прокручивая дробное число пикселей на кадр.
источник
Очевидное решение состоит в том, чтобы иметь 2 параллельных цикла - рендеринг каждые 1/60 секунды и игровой цикл каждые 1/60 секунды.
Но с моим опытом во Flash (AS3, в котором я уверен, что Super Meat Boy был создан), планировщик не всегда очень точен. Точность также сильно зависит от окружающей среды. В автономном флеш-плеере он может иметь разрешение менее миллисекунды. Но при запуске в некоторых веб-браузерах точность становится частотой кадров.
Таким образом, самый близкий способ, которым вы можете добраться до разделения рендеринга и игровых логических циклов, - это чтобы все движения были основаны на времени (и запускали каждый кадр на основе того, сколько времени прошло с последнего кадра). Это может привести к некоторому усложнению математики (например, применять гравитацию непрерывно, а не увеличивать скорость объекта через заданные интервалы). Поскольку игра может отставать на секунду, а затем ваш игрок будет двигаться на 200 пикселей за один шаг, обнаружение столкновений и реагирование могут стать еще более сложными. Если бы программист делал обнаружение коллизий по кадрам (проверяя коллизию на каждом временном шаге), им также пришлось бы переключаться на обнаружение коллизий по времени. И если бы они хотели, чтобы это казалось естественным, им пришлось бы использовать метод гравитации, описанный выше, который заставляет движение объекта быть кривой (в противоположность линии),
источник
Я не думаю, что слишком много просить, чтобы 2D-игры для ПК играли со скоростью 60 кадров в секунду. Даже большинство 2D-игр теперь аппаратно ускорены, так что лично я бы не беспокоился о требовании fps.
Реальный вопрос в том, почему бы вам не использовать пиксельную игру, в играх полно читов и ярлыков.
Если вы делаете игру, основанную на физике (возможно, бросание птиц?), Ответ очевиден, но клон Супер Марио? основанное на времени движение может быть немного большим.
источник
Чтобы избежать странного поведения в двумерной физике, которую они используют?
Честно говоря, я могу только догадываться. Я попробую объяснение:
В основе игры лежит основной игровой цикл. Который в основном выглядит так:
updateGame обновляет gameState: проверяет ввод игрока, применяет ввод игрока в игровой мир, запускает симуляцию физики и т. д.
renderGame рисует и оживляет игру.
Это связывает обновление физики с рендерингом. Если вы хотите отделить его, вам нужно будет использовать потоки и правильно синхронизировать каждый доступ к данным рендеринга и потока gameUpdate с общими данными, например позицией игрока. Это можно сделать.
Другая проблема может заключаться в том, что физическое моделирование требует постоянного временного шага для стабильной работы. Это зависит от того, как supermeatboy рассчитывает движение (Опять же, мы можем только догадываться, как они это сделали;)).
Наивный подход был бы (который я использую в своей игре * вздох *):
Это называется интеграцией Эйлера и, как правило, считается плохой идеей. Если временной шаг не постоянен, возникают ошибки вычисления, которые делают симуляцию менее стабильной. Объект может перемещаться с чрезмерной скоростью или не полностью или летать сквозь стены за пределы экрана. Даже если временной шаг постоянен, интеграция Эйлера вызывает незначительные ошибки в расчетах. Лучше использовать другой метод интеграции, такой как RK4, или использовать физический движок.
Кроме того, могут возникнуть проблемы с обнаружением столкновений, если временной шаг становится слишком большим. Поскольку столкновения не проверяются между двумя обновлениями игры, объекты могут проходить через препятствия.
источник