Компенсация задержки

Узнайте о компенсации задержки Mirror для быстро развивающихся игр.

Lag Compensation (также известная как Rollback) нужна для динамичных / FPS игр.

Для MMORPG, карточных игр, игр, основанных на раундах, стратегических игр и т.д. это будет не интересно.

Почему Компенсация задержки

Давайте рассмотрим наиболее распространенную причину, по которой играм требуется компенсация задержки.

Давайте рассмотрим такой шутер от первого лица как Counter-strike.

На сервере есть два игрока: вы и ваш друг.

Сервер синхронизирует местоположение вашего друга с вашим. Это занимает 50 миллисекунд.

Вы выстреливаете в друга в игре использующей команду в Mirror [Command] CmdFire(Vector3 direction).

[Command] требуется еще 50 мs, чтобы дойти до сервера.

Затем сервер проверяет, попали ли вы в своего друга, и наносит урон.

За прошедшие 100 мs ваш друг уже продвинулся на два шага влево.

В результате, вы никогда не попадете в своего друга.

Вот почему нужна компенсация задержки в играх с высоким темпом / шутерах от первого лица.

В противном случае игрокам всегда нужно будет целиться впереди своих целей.

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

Разница между включенной / выключенной компенсацией задержки очень заметна для всех.

Для более глубокого понимания, пожалуйста, прочтите Valve's Source Multiplayer Networking article. Это хорошее чтение, и оно стоит потраченного времени, даже если вы еще не все поняли.

Алгоритм компенсации задержки в Mirror

Мы реализовали компенсацию задержки как отдельный алгоритм C#, независимый от Unity и Mirror. В результате его очень легко модифицировать, тестировать и экспериментировать. Это может быть использовано для любого типа данных / компонента реализовав интерфейс Capture и вызывая алгоритм LagCompensation<T: Capture>.

Данный алгоритм можно найти по пути Mirror/Core/LagCompensation.cs:

Для обеспечения стабильности он поставляется с полным набором тестов на все случаи:

Вот основной обзор того, как его использовать:

  • Создавайте Capture (запись) состояния игрока или мира каждый интервал времени. К примеру, вы можете использовать структуру PlayerCapture : Capture которая будет содержать позицию и вращение игрока в текущее время.

  • Создайте словарь, в котором будет хранится ваша структура с данными, которые были в определенное время Queue<KeyValuePair<time, capture>>.

  • Теперь каждый интервал времени, вызывайте LagCompensation.Insert<T>() чтобы создать новую запись. Функция создания записи автоматически удаляет старые снимки, размер которых превышает допустимый лимит, и заботится обо всех крайних случаях за вас.

  • В вашей CmdFire() функции, вам нужно:

    • Оценить, насколько сильно отстает клиент. Мы не хотим доверять клиенту, который сообщит нам об этом времени. Вместо этого, используйте LagCompensation.EstimateTime() для авторитетной оценки сервера.

    • Далее вызовите LagCompensation.Sample(buffer, time) чтобы получить запись в необходимое вам время. Обратите внимание, что ваше расчетное время, скорее всего, находится между двумя записями. Вот почему оно всегда возвращает 'before' (до) и 'after' (после), которые затем вы можете использовать для интерполяции между ними, чтобы найти позицию игрока в это точное время.

    • Теперь, когда у вас есть интерполированный снимок (результат записей), вы можете проверить, был ли соперник в том месте, куда стрелял игрок. Например, вы можете захотеть использовать RayCast или откатить физический движок.

Традиционно алгоритмы компенсации запаздывания выбирали бы результат "до" или "после" из функции Sample(). Если ваша производительность позволяет это, не стесняйтесь Interpolate(before, after, t) для получения более точного результата. Это обычно называют "sub-tick" интерполяцией (смотрите demo).

Подводя итог, вам нужно: Capture, Insert, EstimateTime, Sample.

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

Для получения простого примера, пожалуйста, попробуйте наш пример компенсации задержки в папке примеров:

Это демо очень простое для понимания:

  • Заполненный белый квадрат - это объект на сервере

  • Очерченные белые квадраты - это записи, сделанные с каждым интервалом.

  • Черный квадрат - это объект на клиенте, отстающий на несколько миллисекунд

  • Вы нажимаете на черный квадрат, от этого вызывается CmdFire() на сервере.

  • Если он подсвечивается синим, вы попали. Если он подсвечивается пурпурным, значит, вы не попали.

  • Черный квадрат находится ровно на один квадрат позади белого, что означает, что вы попадете только в том случае, если компенсация запаздывания сработает должным образом.

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

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

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

Demo: Шутер с компенсацией задержки

Мы хотели отправить алгоритм компенсации задержки как можно раньше.

Готовая демо игра FPS находится в нашем roadmap на конец этого года!

А сейчас, пожалуйста прочтите Valve article, проверьте алгоритм и попробуйте наше демо!

Last updated