В этой статье мы с вами разберёмся, для чего нужна стабилизация в играх и нужна ли она вообще. А так же какая стабилизация предпочтительнее, какие у неё есть минусы и плюсы. Итак, для чего же нужна стабилизация в играх? У всех компьютеров разные вычислительные возможности, во всех компьютерах разная графическая подсистема, обладающая разной производительностью, поэтому наивно полагать, что игра на них будет идти с одинаковой скоростью и равномерно. Те из вас кто пытался поиграть в старые игры для пентиум-1 и аналогичных наверняка сталкивались с проблемой чрезмерной резвости этих игр на вашем ПК, это связанно именно с тем, что в играх не было сделано элементарной стабилизации скорости выполнения игры на разных ПК. А вот теперь другой пример, вы наверняка запускали «тяжелую» игрушку на своём ПК и она у вас заметно «тормозила» или весь игровой процесс напоминал сон из-за медлительных действий на экране. (Автор сам прошел GTA-3 на достаточно слабом ПК для неё, а потом спустя пару лет удивился тому, какой игра стала динамичной на новом ПК, оказывается, тогда я играл в сильно замедленном режиме по причине опять таки отсутствующей стабилизации). Если вы не хотите, чтобы и ваша игра выкидывала такие вот фокусы, вам необходима стабилизация скорости выполнения игры. Большой популярностью в среде Blitz-разработчиков игр пользуется следующий стабилизатор (код для BlitzMAX): 'stabilizator1.bmx Const FPS:Int=75 Global period:Float=1000.0/FPS,elapsed:Int,Ticks:Int,tween:Float, time:Int time=MilliSecs()-period Repeat Repeat elapsed=MilliSecs()-time Until elapsed Ticks=elapsed/period tween=Float(elapsed mod period)/Float(period) For k=1 To Ticks time=time+period '############# C A L C U L A T I N G ############### 'logic code Next '###################### D R A W I N G ###################### Многие используют его не задумываясь, как он работает, а ведь часто это приводит к непредсказуемым последствиям. Давайте разберемся, что здесь к чему. FPS – это максимально число кадров в секунду в вашей игре, стабилизатор не допустит превышение этого числа, что не даст вашей игре работать слишком резво. Period – это расчётное время подготовки одного кадра в миллисекундах. Elapsed – это фактически затраченное время на подготовку одного (прошлого) кадра в миллисекундах. Ticks – необходимое число расчётов логики чтобы темп игры не отставал при низком fps от запланированного. Time – расчётное время начала расчёта текущего кадра. at elapsed=MilliSecs()-time Until elapsed Смысл этого цикла в следующем, дождаться, когда затраченное время на расчёт кадра станет больше ноля. Теоретически время, затраченное на кадр всегда больше ноля миллисекунд, но на практике не все микропроцессоры обладают достаточной дискретностью таймера и/или не позволяют получать точное время с точностью до миллисекунды, поэтому иногда эта разница может быть и отрицательной. Вот для предотвращения возможных с этим ошибок и создан этот цикл. Он выполняется минимум 1 раз и вычисляет затраченное время на расчёт кадра, причём это время минимум 1мс. icks=elapsed/period tween=Float(elapsed mod period)/Float(period) Здесь в первой строчке вычисляется отношение расчётного времени к реально затраченному на расчет прошлого кадра, число округляется до меньшего целого и это является коэффициентом ускорения всех движений в игре, чтобы запаздывающая графика успевала за темпом игры. Во второй строчке считается точный коэффициент для ускорения анимации. For k=1 To Ticks time=time+period '############# C A L C U L A T I N G ############### 'logic code Next В этом цикле, который выполняется от 0 до Ticks раз, рассчитывается вся логика игры, именно внутри этого цикла нужно помещать AI, обновление положения игрока и юнитов и т.д. Внутри цикла строчка "time+period" выполняет очевидную функцию – вычисляет расчётное время окончания этого кадра, естественно оно не совпадёт с фактическим, но именно это позволит сгладить эффект округления числа повторов логики до целого, за счёт постепенно нарастающей разницы между "time" и реальным временем. ###################### D R A W I N G ###################### 'graphics code Forever В этом, последнем куске кода размещается сам графический вывод изображения, т.е. очистка экрана, рендер мира и отображение заднего буфера. Так же здесь же располагаются команды вывода 2д графики и текста, однако нужно не забывать использовать их только после RenderWorld() (если используется 3Dграфика). Плюсы данного стабилизатора: Честно выполняет свою роль, т.е. не даст вашей игре разогнаться больше допустимого, а так же скомпенсирует fps ступенчатостью движений. Простота использования Минусы При текущем fps выше расчётного, число проходов логики равно нулю, что делает бесполезным следующий проход графики (т.к. на экране ничего не изменится). Стабилизация является неравномерной (т.е. не строго пропорционально замедлению графики), т.к. Ticks – целое число, из чего следует, что fps должен упасть в 2 раза, чтобы Ticks изменилось, и проходов логики стало 2 вместо 1. Поэтому происходит чередование кадров с удвоенным проходом логики и с обычным проходом логики. В результате на низких fps возможно неравномерное подёргивание движущихся объектов. Советы Пороговый fps лучше устанавливать как можно выше, это приведёт к более плавным движениям, т.о. минимальное значение порогового fps должно быть не менее 75, а лучше его брать равным 1,5 желаемого fps в игре. Целесообразность применения такой стабилизации становится под сомнение в свете следующих фактов: При экстремально низких пиковых реальных fps, отношение его к пороговому максимальному fps может достигать десятков. В результате на слабом ПК (по видео части) возникает противоречие, ЦП должен отработать десятки повторов логики чтобы сгладить запаздывание графики, что в свою очередь не оставит времени на расчёт графики и ещё усугубит ситуацию, ввергнув игр в пучину тормозов и лагов, это замкнутый круг. С другой стороны при реальном fps выше порогового, стабилизатор не даст логике игры выполняться, пропуская для части кадров расчёт логики вообще. Но при этом выполнит графическую часть, что абсолютно бесполезно т.к. на экране ничего не изменится. Т.е. при превышении порогового fps начинается пустая трата процессорного времени и времени видеокарты на расчёт идентичных предыдущим кадров, в то время когда можно было бы дать им отдохнуть, тем более что работу под 100% нагрузкой долго не выдерживают особенно бюджетные видеокарты и ЦП. Подводя итог этих фактов, следует признать большую полезность простого ограничителя кадров на базе ждущего таймера, т.к. он ограничивает fps и при превышении порогового fps даёт отдых как ЦП, так и видеокарте. Так же из-за отсутствия повторителя логики он позволяет игре выполняться чуть быстрее на слабых ПК по отношению к выше приведённому стабилизатору. Однако минусом его является снижение игрового темпа пропорционально падению fps. Как компромисс возможно использование комбинированного стабилизатора, в котором при превышении порогового fps направляет ход выполнения программы на ждущий таймер, и разгружаем процессор, а при недостатке fps стабилизируем путём увеличения числа проходов логики. И ввести ограничение на число повторов логики, например до 5, и при превышении числа повторов логики сверх лимита не просчитывать пусть игра начнёт снижать темп. Это лучше чем лаги на высокой скорости. Для аркадных же игр нетребовательным к вычислительной мощи ПК лучше обойтись ограничением fps на базе ждущего таймера настроенного на частоту около 50-60Гц.
Источник: http://blitzetc.boolean.name/ |