Создание сервера для онлайн ММО игр на PHP и Unity ч. 11 — FPS, Ping,паузы между командами, интерполяция и экстраполяция

В этой серии статей речь пойдет о том что такое PING и какими приемами можно сгладить задержку пересылки пакетов при его высоком значении в realtime онлайн играх с примерами кода на C# в игровом движке Unity для игр на ПК, мобильных устройствах и браузерных игр WebGL.

Статья включает в себя видео примеры, демонстрации кода и алгоритм подсчета PING без использований командной строки устройств

Создание сервера для онлайн ММО игр на PHP и Unity ч. 11 — FPS, Ping,паузы между командами, интерполяция и экстраполяция

Что такое PING

Начнем с теории: отправляя команду в ММО игре на сервер она доходит не моментально - ей требуется время дойти до физического сервера ("железа") по кабелю который проложен в том числе по дну океана и часто этот сервер находится очень далеко (поэтому часто делают несколько серверов в странах близких к игрокам).

Сервер так же может отправлять пакеты игроку на устройство, но т.к. у нас websocket сервер это не происходит сразу после запроса (хотя можно сделать, но будет неправильно) как например в HTTP соединениях (то есть наш сервер подойдет не только к браузерным играм, но и для ПК , мобильных устройств и консолей, однако для демонстрации я использую браузерную на моем сайте).

я изменил картинку из предыдущей статье что бы показать что websocket это не классическая модуль запрос - ответ
я изменил картинку из предыдущей статье что бы показать что websocket это не классическая модуль запрос - ответ

Время которое затрачено на отправку пакета и его возврат обратно - называется Ping , выражается (обычно) в миллисекундах (в одной секунде 1000 мс.) и чем он ниже - тем лучше. Важно отметить что в него не включено время программных вычислений для обработки запроса, как например в расчете RPS сайтов и web приложений

Как высчитать PING

В Unity для версий игр ПК и мобильных устройств есть готовые инструменты анализа PING на устройстве, но в браузерных версиях игр (WebGL) они не работают.

Создание сервера для онлайн ММО игр на PHP и Unity ч. 11 — FPS, Ping,паузы между командами, интерполяция и экстраполяция

Я расскажу о своем приеме расчета PING который сможет заменить встроенный инструмент в Unity и использоваться в браузерных версиях игр:

  1. Отправляем с пакетом временную метку Unix Timestamp с точностью до миллисекунды по времени клиента. На скриншоте ниже пример демонстрационной игры с моего сайта (код ее открыт и доступен в GIT) я добавляю метку к каждому запросу (по времени на устройстве пользователя)
Создание сервера для онлайн ММО игр на PHP и Unity ч. 11 — FPS, Ping,паузы между командами, интерполяция и экстраполяция

2. На сервере когда нужно отправить пакет по данной команде обратно я отнимаю от этой метки-времени время которое прошло с момента как сервер получил данную команду (разница в миллисекундах) - строки $event['time'] - $microtime .

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

код написан на PHP, но это не важно - идею можно использовать на любом языке
код написан на PHP, но это не важно - идею можно использовать на любом языке

3. При получении команд в клиентской части я снова по времени клиента отнимаю полученные значения и это и есть чистый сетевой Ping. Для статистики я сохраняю результаты в массив (список) что бы выводить среднее значение (сумма всех значений деленое на количество этих значений в массиве).

Создание сервера для онлайн ММО игр на PHP и Unity ч. 11 — FPS, Ping,паузы между командами, интерполяция и экстраполяция

4. Периодически шлю вместе с пакетами из клиента на сервер дополнительный параметр ping, тем самым сервер знает средний пинг каждого игрока (этот параметр не влияет ни на какие вычисления на сервере и служит как информативный в связи с тем что его легко подменить в клиентской части через код)

Создание сервера для онлайн ММО игр на PHP и Unity ч. 11 — FPS, Ping,паузы между командами, интерполяция и экстраполяция

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

Однако можно заметить что PING в нашем случае зависит от размера пакета (в добавок Websocket протокол на базе TCP в случае потери пакетов начнут их повторно отправлять, будет ждать подтверждение и т.п.), но как по мне это значение более удобно (мне важнее сетевые задержки на реальных игровых пакетах, чем анализ скорости отправки пары байт).

На вопрос каким является хороший показатель Ping в играх Google ответил цифру 50 мс.

Создание сервера для онлайн ММО игр на PHP и Unity ч. 11 — FPS, Ping,паузы между командами, интерполяция и экстраполяция

Эта цифра означает что если наш пакет из клиента (игры) будет идти 25 мс. в одну сторону и 25мс. с сервера в клиент (игру), т.е. в другую.

Я подготовил видео, где поясняю и показываю то о чем написал в данном разделе (функционал уже немного изменился, но концепт остался тот же):

Что такое FPS

Между отправкой любой команды вам нужно время на повторное нажатие клавиши (сенсора), но есть команды когда можно держать клавишу нажатой (например движение) и можно предположить что команды шлются на сервер в онлайн играх непрерывно, но это не так - игра поделена на кадры (условно циклы while) в секунду (FPS) и каждый такой кадр (можно реже, но не чаще обычно) она может считывать нажатие клавиши и меняет картинку. FPS может как взлетать до 300 так и опускаться до 30 (ниже тоже может , но уже видны торможения игры) и даже это слишком быстро что бы слать с такой частотой команды (т.к. иначе вы либо будите двигаться при одном нажатии клавиши на доли миллиметра или движение будет настолько быстрым что будет походить на телепортации)

Создание сервера для онлайн ММО игр на PHP и Unity ч. 11 — FPS, Ping,паузы между командами, интерполяция и экстраполяция

Возможно Вы знаете из Wikipedia что глаз человека воспринимает смену изображений как плавную при частоте в диапазоне 48 (фильм "Хоббит" был первым снят с этой частой) - 60 FPS (кадров в секунду), поэтому у каждой команды есть своя пауза и она составляет обычно столько , сколько человеческий глаз может уловить и больше, а значит минимальную комфортную паузу между кадрами можно высчитать по формуле: 1 секунда / 60 FPS = 0,017 (округленно) секунды = 17 мс.

Однако в играх (в том числе realtime стиля "экшен") паузы между командами намного больше , например за одну команду движения персонаж обычно идет больше чем тот минимум который мы способны уловить.

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

Отсюда и считается что хорошим показателем FPS в играх является 60 FPS

PS. В Unity есть циклы выполняющийся раз в фиксированное время FixedUpdate частота которого и выражается в виде миллисекунд. В текущем примере стоят частота 50 FPS

Создание сервера для онлайн ММО игр на PHP и Unity ч. 11 — FPS, Ping,паузы между командами, интерполяция и экстраполяция

Интерполяция

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

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

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

  1. клиентская часть (игра) при запуске игры должна получать список всех возможных команд с их паузами (и в процессе получать новые значения если эти паузы меняются, например при прокачке игрока)
  2. мы знаем среднее значение него PING на текущий момент, а значит мы знаем когда примерно когда пакет достигнет сервера от момента отправки - 1/2 от скорости пинг
  3. при получения ответа от сервера мы знаем что она выполнилась 1/2 пинга назад (т.к. этот пакет шел до нас это время).

Оперируя этими данными мы знаем примерное (т.к. PING величина не постоянная) время когда сервер будет готов принять новую команду и позволить ее заранее отправить с клиента (не дожидаясь предыдущего ответа от сервере).

Создание сервера для онлайн ММО игр на PHP и Unity ч. 11 — FPS, Ping,паузы между командами, интерполяция и экстраполяция
Создание сервера для онлайн ММО игр на PHP и Unity ч. 11 — FPS, Ping,паузы между командами, интерполяция и экстраполяция

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

Видео ниже демонстрирует как работает интерполяция:

Экстраполяция

Выше я уже сказал что PING величина не постоянная и может резко меняться (особенно при работе с беспроводным интернетом) и в моменте он может резко увеличится (ухудшиться) и вернутся на нормальное значение. За это время весь игровой мир может замедлится - такое явление называют "фризы" (от англ. freez - замерзнуть). Для подобных ситуаций используют подход , который продолжает поведение объекта как если бы он продолжил бы делать то же самое , но в нашем случае (в игре) - с меньшей скоростью , называется экстраполяция

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

Создание сервера для онлайн ММО игр на PHP и Unity ч. 11 — FPS, Ping,паузы между командами, интерполяция и экстраполяция

А так же подготовил видео с демонстрацией как это работает в самой игре (это улучшило переход в бесшовном мире)

В настоящий момент проект на моем сайте http://my-fantasy.ru является не коммерческим и я веду его в частном порядке, но верю что продолжая и делясь архитектурными идеями в будущем это станет рабочим продуктом сделанным в России, а статьи помогут в написании игрового сервера для MMO игр.

Буду благодарен за лайк статье.

Если вам интересно чем закончится данный проект - подписывайтесь на мой профиль (я публикую только статьи данного проекта) и следите за новыми видео на Youtube (они выходят чаще чем статьи)

История:

6.8K6.8K показов
478478 открытий
2 комментария

Комментарий недоступен

Ответить

Спасибо. Это лишь начало долгого пути. Надеюсь прототип игры когда я его закончу будет тоже крут

Ответить