Мне было интересно, есть ли какой-нибудь возможный вред, когда мой игровой цикл работает так быстро, как позволяет система?
В настоящее время у меня есть цикл, который, измеряя прошедшее время в наносекундах, без проблем запускает игровую логику и логику рендеринга на предопределенных скоростях. Фактически любая логика, которую я делаю в цикле, синхронизируется с определенным количеством вызовов каждую секунду.
Сам цикл, хотя и работает так быстро, как ему хочется, составляет около 11,7 миллионов циклов в секунду на моей машине.
Петля (простой псевдокод):
while(!isGameOver){
if(canPollInputs){
pollInputs()
}
while(canStepLogic){
stepLogic()
}
if(canRender){
render()
}
}
Мой вопрос заключается в том, может ли этот простой цикл, если он не работает на контролируемой скорости, причинить какой-либо вред системе?
Редактировать: это означает, что моя логика работает 30 раз в секунду (30 тактов в секунду), мой рендерер работает со скоростью 60 кадров в секунду, я опрашиваю ввод 100 раз в секунду, и есть также некоторая логика, чтобы справиться с логикой или рендерингом занимает больше времени, чем ожидалось , Но сама петля не задушена.
Редактирование: Использование, Thread.sleep()
например, для уменьшения основного цикла до 250 циклов в секунду, приводит к уменьшению, но циклы работают со скоростью около 570 циклов в секунду вместо желаемых 250 (добавит код, когда я на своем настольном компьютере ...)
Редактировать: здесь мы идем, рабочий Java Gameloop, чтобы прояснить вещи. Также не стесняйтесь использовать это, но не претендуйте на это свое;)
private void gameLoop() {
// Time that must elapse before a new run
double timePerPoll = 1000000000l / targetPPS;
double timePerTick = 1000000000l / targetTPS;
double timePerFrame = 1000000000l / targetFPS;
int maxFrameSkip = (int) ( (1000000000l / MINIMUM_FPS) / timePerTick);
int achievedPPS = 0;
int achievedFPS = 0;
int achievedTPS = 0;
long timer = TimeUtils.getMillis();
int loops = 0;
int achievedLoops = 0;
long currTime = 0l;
long loopTime = 0l;
long accumulatorPPS = 0l;
long accumulatorTPS = 0l;
long accumulatorFPS = 0l;
long lastTime = TimeUtils.getNano();
while(!isRequestedToStop) {
currTime = TimeUtils.getNano();
loopTime = currTime - lastTime;
lastTime = currTime;
loops = 0;
accumulatorPPS += loopTime;
accumulatorTPS += loopTime;
accumulatorFPS += loopTime;
if(accumulatorPPS >= timePerPoll) {
pollInputs();
playerLogic();
achievedPPS++;
accumulatorPPS -= timePerPoll;
}
while(accumulatorTPS >= timePerTick && loops < maxFrameSkip) {
tick();
achievedTPS++;
accumulatorTPS -= timePerTick;
loops++;
}
// Max 1 render per loop so player movement stays fluent
if(accumulatorFPS >= timePerFrame) {
render();
achievedFPS++;
accumulatorFPS -= timePerFrame;
}
if(TimeUtils.getDeltaMillis(timer) > 1000) {
timer += 1000;
logger.debug(achievedTPS + " TPS, " + achievedFPS + " FPS, "
+ achievedPPS + " Polls, " + achievedLoops + " Loops");
achievedTPS = 0;
achievedFPS = 0;
achievedLoops = 0;
}
achievedLoops++;
}
}
Как вы можете видеть, в каждом цикле практически не выполняется код, но всегда есть определенный выбор, основанный на том, сколько прошло реального времени. Вопрос касается этой «рабочей петли» и того, как она влияет на систему.
источник
Ответы:
Это приведет к тому, что одно ядро процессора будет всегда работать на 100%. Это обычно не наносит никакого вреда системе. Процессоры предназначены для работы на 100% в течение нескольких часов. Но на мобильном устройстве он быстро разряжает батарею и нагревает устройство, что, вероятно, будет стоить вам около звезд в рейтингах вашего магазина. На настольном компьютере это менее проблемная задача, но она потребляет больше электроэнергии пользователя, заставляет вентилятор ЦП вращаться быстрее, что может вызвать некоторый шум и лишние циклы ЦП, которые в противном случае могли бы использоваться другими процессами. Хотя это не критичные дефекты, они все же плохой стиль, поэтому следует избегать их, когда это возможно.
Вы ничего не сказали о том, как работает ваш игровой логический цикл внутри, но когда вы используете подход с дельта-временем (каждый вычисление, которое вы делаете, требует времени с момента последнего вызова), вы имеете дело с очень маленькой дельтой. значения времени Это означает, что вы можете столкнуться с проблемами с неточностями с плавающей точкой, которые могут вызвать все виды странного поведения. Кроме того, разрешение системного таймера часто ограничено, поэтому, когда ваш логический цикл слишком быстрый, вы можете получить значение delta-t, равное нулю, которое затем может вызвать деление на ноль, что приведет к сбою.
Чтобы смягчить эту проблему, вы должны ограничить частоту кадров (графическую и логическую) до максимума, который может воспринимать человеческий глаз. Сколько это оспаривается и зависит от типа анимации и от того, какой тип отображения она отображается, но оценки варьируются от 40 FPS до 120 FPS. Это означает, что вам нужно установить минимальное время выполнения каждого цикла от 20 мс до 8 мс. Если итерация цикла завершится быстрее, оставьте поток ЦП
sleep
на оставшееся время.источник
Вы тратите циклы процессора. Это означает меньшее время автономной работы ноутбуков, планшетов и телефонов, более высокие счета за электроэнергию, больше тепла, выделяемого машиной, более шумные вентиляторы. Кроме того, вы можете питаться циклами из других важных системных процессов (например, сервер окон может работать с рывками), что может повлиять на игровой процесс. Некоторые планировщики систем в современных многозадачных системах также наказывают приложения, использующие слишком много циклов, поэтому сначала вы можете быть быстрыми, а затем внезапно увидеть странный рывок, когда система задушена.
Многие хардкорные геймеры также создают собственные ПК с нуля, которые находятся на грани спецификаций их фанатов, и в этом случае жаркий день и тепло, которое генерирует ваша игра, могут вызвать срабатывание предохранителей в машине (в лучшем случае) или даже перегреть детали и умереть (в худшем случае). Так что, если это ваша целевая аудитория, вы можете убедиться, что вы всегда оставляете немного места «наверху».
Наконец, есть проблемы с геймплеем, когда вы можете превзойти игроков с более быстрыми машинами по сравнению с более медленными. Ограничение игрового цикла на определенной частоте и использование дополнительных циклов исключительно для не относящихся к игровому процессу аспектов (таких как рендеринг графики с более высокой точностью, эффекты объемного звучания и т. Д.) Сделает вашу игру более справедливой.
источник
У вас не должно быть нервного движения / геймплея
Есть два способа реализовать игровую логику - привязать к реальному времени или привязать к количеству «ходов» / этапов обработки. Если какая-то вещь в вашей игре движется влево, будет ли она другой, если ваш stepLogic () был вызван 100 вместо 50 раз?
Если ваш код обрабатывает истекшее время явно везде и делает это правильно, то это может быть нормально; но если в вашем коде есть что-то, что зависит от количества «шагов», то вы получите нежелательные побочные эффекты.
Во-первых, скорость вещей, которые должны постоянно перемещаться, будет непредсказуемо изменяться (в зависимости от использования процессора), и это приводит к очень раздражающему контролю - вы не можете сделать точный удар или прыжок, если вдруг игра ускоряется или замедляется. Даже для игр без «подергивания» это выглядит раздражающим и нервным, если все идет не так гладко.
Во-вторых, у вас могут возникнуть проблемы со способностями персонажа в зависимости от скорости компьютера - классическим примером является старая проблема Quake, когда максимальная дальность прыжка непреднамеренно зависела от вашего fps.
Эти проблемы могут появляться, даже если вы пытаетесь сделать код независимым от fps, накопление ошибок округления часто может привести к таким ошибкам.
источник
Единственный потенциальный вред - это энергопотребление, поэтому не делайте этого на мобильных устройствах. И наоборот, немало встроенных систем проводят всю свою жизнь в цикле, ожидая, когда что-то произойдет.
Раньше было совершенно нормально просто рендерить игровые кадры как можно быстрее, иногда даже без таймера, чтобы компенсировать игровой процесс для разных скоростей процессора. Гоночная игра Bullfrog Hi-Octane особенно сильно пострадала от этого, и я подозреваю, что именно об этом и упоминает плакат, упоминающий Civ2.
Я бы посоветовал вам хотя бы опрашивать входные данные на каждом проходе, если вы работаете в системе Windows или аналогичной, чтобы обеспечить быстрый отклик на ввод.
источник
swap
/present
/flip
функцию сделать ожидание на Vsync сигнала, регулировать цикл игры.