Найти тему
Сделай игру

Скорость работы приложения: то, что всегда за кадром

Оглавление

Обычно, вопрос скорости на повестке не стоит. Замечания начинаются лишь в тот момент, когда заветный FPS падает до неприятных глазу 12-14 кадров в секунду. А то и ниже. И то - только в играх. Ну или когда фильм замирает отчего-то.

Но говоря про скорость, не всегда следует понимать количество кадров: чаще всего речь идёт о скорости работы внутри самого приложения: как часто будет мерцать курсор, как быстро будет заполняться строка ввода, как долго надо держать кнопку, чтобы появилась не одна, а две буквы подряд.

Обычно, данные показатели скрыты от разработчика различными библиотеками и готовыми решениями, однако вопрос крайне актуален! Для наглядности, буду рассматривать скорость работы приложения на примере игры.

На старт, внимание, бег
На старт, внимание, бег

Причём вообще тут скорость?

Собственно, у каждой игры есть свой темп - это та скорость, с которой всё происходит на экране. Задача разработчика - выбрать тот баланс, когда время реакции на вызовы оптимально, то есть не велико (потому что становится скучно) и не мало (потому что становится избыточно трудно). Это можно и считать темпом игры.

Проблема возникает в тот момент, когда необходимо эти скоростные метрики считать. Проще говоря, как определить, насколько быстро должны двигаться объекты на экране и сколько времени есть у пользователя, чтобы нажать нужную кнопку.

Обычно, это называется вражеским словом - тайминг; мы же будем использовать термин "скорость игрового процесса" или СИП.

Первые решения

Изначально, пока процессоры были достаточно медленными, вопрос на повестке дня стоял обратный - как сделать так, чтобы всё не двигалось слишком медленно. Для этого уменьшали количество объектов на экране, оптимизировали алгоритмы - короче говоря шли на различные ухищрения, лишь бы обеспечить минимальную скорость, достаточную для того, чтобы игровой процесс походил бы на процесс, а не на комикс.

Примечательно, что у этого подхода были и побочные эффекты. Например, в игре Space Invaders (это там, где пришельцы спускаются, а их надо расстреливать с катающейся внизу платформы) по мере того, как противников на экране становилось меньше - скорость игры повышалась. И хотя, изначально, это не было запланировано, такое поведение было сохранено как элемент повышения сложности игры.

Надо ли говорить, что довольно скоро подход, опирающийся на быстродействие процессора, начал давать сбой.

Задержки процессора

Время для следующего шага наступило с появлением 286 процессоров и их аналогов: они были сильно производительней своих предшественников (скажем 8086) и там уже нельзя было опереться на тактовую частоту процессора, как на естественный ограничитель скорости.

Чтобы игра не превращалась в стремительное месиво, разработчики массово использовали директиву задержки процессора. Использовался один из двух подходов: либо задержка выполнялась после каждого такта на указанное количество времени в миллисекундах, либо в тактах процессора. Но в то время, это, нередко, было одно и то же: функции рассчёта времени привязывались к популярным на то время процессорам.

Век 286 процессора был, по процессорным меркам, довольно долог. Надо ли говорить, что с появлением следующей линейки процессоров, сильно увеличивших свои производственные мощности, предыдущие решения перестали работать? Не везде, но много где.

До сих пор помню своё недоумение, когда запускал какую-нибудь игру, а играть в неё было невозможно, потому что всё дёргалось в конвульсиях, а попытка нажать на кнопку управления приводило к тому, что персонаж моментально оказывался в другом углу экрана.

Среднее время выполнения

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

Изначально, для этого подходила улучшенная команда sleep(), приостанавливающая работу процесса на указанное количество миллисекунд. Но изменение процессора приводила к тому, что пользовательский опыт на более слабых машинах или на более мощных - становился хуже: время, в течении которого можно было осуществить захват и обработку управления были либо слишком продолжительными, либо слишком короткими.

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

Думаю, вам доводилось сталкиваться: после запуска игры примерно секунду игра работает с повышенной скоростью, а после - замедляется и скорость уже нормальная.

А что сегодня?

Надо сказать, что на сегодняшний день все перечисленные выше приёмы используются. И если привязка к скорости процессора актуальна, преимущественно, для игровых платформ или приставок, то остальные подходы используют повсеместно.

Впрочем, есть и фавориты - это те самые метрики количества кадров в секунду. Это весьма точный показатель скорости работы приложения.

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

Именно этот показатель позволяет довольно эффективно организовывать управление скоростью. Изначально определяется оптимальное количество кадров, а потом, по мере игры, это значение меняется. И для каждого показателя, заодно, вычисляется окно, в течении которого определяется, какие кнопки давит пользователь.

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

Заключение

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