Серверная игровая петля

8

Многие Java-игры используют thread.sleep () для управления частотой кадров. Поскольку сервер не отображает графику, должен ли серверный игровой цикл продолжать работать только для расчета времени дельты? Как этот пример:

long lastLoopTime = System.nanoTime();
final int TARGET_FPS = 60;
final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;   

while (gameRunning)
{
   long now = System.nanoTime();
   long updateLength = now - lastLoopTime;
   lastLoopTime = now;
   double delta = updateLength / ((double)OPTIMAL_TIME);

   doGameUpdates(delta);
}
Wolfrevo Kcats
источник
11
«Многие Java-игры используют thread.sleep () для управления fps». Чувак, надеюсь, нет.
MichaelHouse
1
@ Byte56 Я бы не сказал много, но некоторые могли бы поступить так. Хотя сониг это нечто общее, его механизм не предопределен. Thread.SleepЭто самый простой способ, некоторые могут ждать прерываний ОС. Вы даже можете считать vSync спящим механизмом.
Ali1S232

Ответы:

6

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

  1. Компьютерные ресурсы ценны. даже если они бесплатны, вы не должны тратить их впустую. рассмотрим случай, когда два или более сервера работают одновременно на одном компьютере. Если один экземпляр сервера потребляет все циклы ЦП, другие экземпляры просто не будут работать. Surly OS будет пытаться справиться с этим своего рода жадным поведением, но это будет стоить дорого. Вы не будете знать, где ОС остановит ваш процесс и передаст циклы ЦП другому. Также вы можете захотеть выпустить свой сервер вместе с самой игрой, чтобы игроки могли запускать свои собственные игры по локальной сети. Немного раздражает, если я выделил одно из своих процессорных ядер только для запуска игрового сервера!

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

  3. Существует простая причина, по которой люди используют Thread.Sleep, как вы и предлагали, потому что добавление большей точности не приведет к лучшей игре. Когда вы играете в игру, вы обычно не замечаете, находится ли объект на расстоянии одного или двух пикселей. Так что вы ничего не получите, увеличив точность. Также существует ограничение ширины полосы сети, как на стороне сервера, так и на стороне клиента. Это означает, что вы обычно не сможете отправлять более 30-60 обновлений в секунду. Поэтому я могу спросить, почему вы должны вычислять состояния, которые вы просто собираетесь выбросить?

  4. Есть много случаев, когда повышение точности может вызвать проблемы. Например, люди, как правило, используют «Вертикальную синхронизацию», чтобы графический буфер не обновлялся во время отправки данных на монитор (что может привести к разрушению). Кроме того, большинство игр используют числа с плавающей точкой в ​​качестве основного контейнера, но они не точны. Вы можете не заметить, когда числа находятся между 2 ^ -20 и 2 ^ 20, но за пределами этого диапазона вы увидите неточное поведение. Например, если вы попытаетесь добавить 10 ^ -5 к 10 ^ 5, это просто проигнорирует ваше добавление. Подобные ошибки обычно не видны, но когда вы не имеете полного контроля над своим шагом времени, все может стать уродливым. В вашем случае, поскольку не требуется рендеринг, я предполагаю, что ваше время обновления должно быть не более 10 ^ -4, то есть все изменения для чисел выше 100 будут испорчены!

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

Ali1S232
источник
Спасибо, вы сделали хорошие замечания там. Я думаю, что мне не нужен переменный временной шаг. Еще одна вещь, что вы предлагаете в качестве спящего механизма?
Wolfrevo Kcats
@WlofrevoKcast Это полностью основано на потребностях вашей игры, но для большинства игр внутренние языковые таймеры (или временные прерывания ОС) являются достаточно хорошим выбором.
Ali1S232
4

Вы должны прочитать это (Полуфиксируемый или Полностью фиксированный временной шаг?) И это (Торгуйте в играх - Исправьте свой временной шаг) .

Я не уверен, почему вы включаете целевой FPS в логику вашего сервера. Найдите фиксированный временной шаг, который вам подходит, и обновите его в соответствии с этим.

По сути, в вашем while (gameRunning)цикле будет еще один цикл while, который будет накапливать время, пока он не будет готов к обновлению. Затем вы делаете обновления через фиксированные интервалы.

MichaelHouse
источник