Unity 6.3
0 онлайн 55 гостей 3 в системе
Вход
Введение в сетевое взаимодействие многопользовательских игр Глава 7 из 11 Оригинал, стр. 60

Задержка и производительность сети

Задержка и производительность сети

Если вы играли онлайн, то наверняка замечали, как задержка ухудшает впечатление от игры. Недостаточная пропускная способность и нестабильное соединение приводят к рывкам персонажей, неравномерной частоте кадров и заметной задержке ввода. Теперь, понимая обмен между клиентами и сервером, легко увидеть причину. При передаче через интернет многое может пойти не так. Даже с механизмами надёжности Unity Transport UDP-пакеты способны потеряться, прийти в неверном порядке или повредиться по пути. Всё это вызывает задержку, которую игрок воспринимает как лаг.

Имитация задержки Чтобы изучить и смягчить влияние задержки во время разработки, в Unity Editor можно имитировать разные сетевые условия с помощью Debug Simulator компонента UnityTransport или Network Simulator.

Debug Simulator в Unity Transport Настройте Debug Simulator в компоненте UnityTransport, чтобы добавить искусственную задержку, джиттер и потерю пакетов. Эти параметры находятся в Inspector объекта NetworkTransport сцены. Задайте несколько значений, имитирующих перегрузку сети:

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

Jitter: добавляет колебания задержки, имитируя нестабильные сетевые условия. Например, задайте 50 мс и посмотрите, как нестабильное соединение влияет на игру. Packet Loss: задаёт процент отбрасываемых пакетов для имитации плохого качества связи. Попробуйте установить потерю пакетов 5 %, чтобы оценить её влияние на игровой процесс. Снова запустите игру и посмотрите, как смоделированные условия влияют на игровой процесс.

Настройте Debug Simulator в Unity Transport.

Network Simulator Network Simulator из пакета Multiplayer Tools позволяет тестировать неблагоприятные сетевые условия и находить проблемы до выпуска игры. Он имитирует сетевые события: разрывы соединения, всплески задержки и потерю пакетов.

Установите Network Simulator из пакета Multiplayer Tools.

Проверьте влияние задержки с помощью Network Simulator.

Другие инструменты эмуляции сетевых условий Debug Simulator и Network Simulator работают только в редакторе. Для сборок приложения задержку можно имитировать с помощью других инструментов эмуляции сетевых условий. Например, clumsy для Windows и Network Link Conditioner для macOS/iOS позволяют воспроизводить различные сетевые условия и тщательно тестировать игру. Подробнее см. в разделе «Тестирование и отладка» далее в этом руководстве. Учет влияния задержки на производительность приложения - одна из главных задач при разработке многопользовательских игр. К счастью, существует ряд подходов, позволяющих ослабить ее последствия. Рассмотрим некоторые из них.

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

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

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

Буферизованный тик

Тики сервера поступают неравномерно, с джиттером, из-за различий в задержке

Тик сервера СЕРВЕР Тик сервера 1

Тик сервера 2

Тик сервера 3

Тик сервера 4

Тик сервера 5

Тик сервера 6

Кадр клиента 1

Кадр клиента 2

Кадр клиента 3

Тик сервера 7 Тик сервера 8

Тик сервера 9

Тик сервера 10

Тик сервера 11

Буфер клиента КЛИЕНТ

Кадр клиента 4

Кадр клиента 5

Кадр клиента 6

Кадр клиента 7

Кадр клиента 8

Обновление кадра на клиенте КЛИЕНТ

Буферизация тиков позволяет выдавать их на клиенте с равномерной частотой

Клиент отображает интерполированные состояния из буфера.

В Netcode for GameObjects интерполяция на стороне клиента включается параметром компонента NetworkTransform. Параметр Interpolation интерполирует положение, поворот и масштаб соответствующего GameObject.

Интерполяция на стороне клиента включена в NetworkTransform.

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

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

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

Объект на сервере

Сервер

Смоделировать новое движение

СЕРВЕР

Отправить ввод

NetworkTransform синхронизирует позицию

Объект на клиенте

Клиент

Объект на клиенте

КЛИЕНТ

Перемещение NetworkTransform под управлением авторитетного сервера.

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

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

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

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

Объект на сервере

Сервер СЕРВЕР

Объект на клиенте

Клиент

Объект на клиенте

Клиент прогнозирует новое движение для мгновенного отклика

КЛИЕНТ

Клиент прогнозирует состояние игры.

Одновременно клиент отправляет действия игрока на сервер в пакете. Сервер получает пакет с вводом, обрабатывает данные и выполняет симуляцию, формируя эталонное авторитетное состояние игры. Затем сервер отправляет это состояние клиенту.

Объект на сервере

Сервер

Обработать перемещени е

СЕРВЕР

NetworkTransform синхронизирует позицию

Одновременно отправить ввод на сервер

Объект на клиенте

Клиент КЛИЕНТ

Объект на клиенте Клиент прогнозирует новое движение для мгновенного отклика

Клиент подтверждает авторитетное состояние

Время кругового обхода (RTT)

Сервер возвращает авторитетное состояние.

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

При существенном расхождении, которое также называют рассинхронизацией, клиент должен скорректировать свое состояние в соответствии с авторитетным состоянием сервера. Этот процесс называется согласованием.

Сервер

Обработка движения

Обработка движения

Объект на сервере

Объект на сервере

Задержка вызывает запаздывание

Задержка вызывает запаздывание

СЕРВЕР

Ввод 1 отправлен на сервер

Объект на клиенте

Клиент КЛИЕНТ

Клиент прогнозирует движение по вводу 1

Позиция 0

Ввод 2 отправлен на сервер

Объект на клиенте

Клиент прогнозирует движение по вводу 2

Синхр.

Объект на клиенте

Позиция 1

Интервал кадров клиента

Синхр.

Позиция 2

Интервал кадров клиента

Объект на клиенте

Объект на клиенте

Сервер синхронизирует авторитетную позицию 1

Сервер синхронизирует авторитетную позицию 2

РАССИНХРОНИЗАЦИЯ: авторитетное значение не совпадает с прогнозом

Клиент получает несовпадающее состояние - происходит рассинхронизация.

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

Сервер

Обработка движения

Обработка движения

Объект на сервере

Объект на сервере

Задержка вызывает запаздывание

Задержка вызывает запаздывание

СЕРВЕР

Ввод 1 отправлен на сервер

Объект на клиенте

Клиент КЛИЕНТ

Клиент прогнозирует движение по вводу 1

Позиция 0

Ввод 2 отправлен на сервер

Объект на клиенте

Клиент прогнозирует движение по вводу 2

Синхр.

Объект на клиенте

Позиция 1

Интервал кадров клиента

Позиция 2

Интервал кадров клиента

Синхр.

Объект на клиенте

Объект на клиенте

Сервер синхронизирует авторитетную позицию 1

Сервер синхронизирует авторитетную позицию 2

Согласование на стороне клиента: Принять значение сервера и повторить симуляцию с ввода 1; скорректировать движение до позиции 2

Подтвердить авторитетное значение позиции 2

Клиент устраняет рассинхронизацию путем согласования.

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

Упреждение на стороне клиента в Netcode for GameObjects Netcode for GameObjects поддерживает клиентское упреждение - упрощенный способ работы с задержкой без полноценного прогнозирования и согласования на стороне клиента. Для этого используются следующие компоненты:

- AnticipatedNetworkVariable<T> - обобщенный компонент для скалярных и простых типов данных: целых чисел, чисел с плавающей запятой, цветов и т. п. Он подходит для свойств, не относящихся к Transform, например здоровья, счета или состояния предмета.

- AnticipatedNetworkTransform работает аналогично AnticipatedNetworkVariable, но предназначен для данных Transform: положения, поворота и масштаба. Клиентское упреждение дает игроку немедленный визуальный отклик, пока клиент ожидает авторитетное обновление от сервера. Благодаря этому игра ощущается более отзывчивой. Например, в простом примере ColorTrigger клиент может сразу показать изменение цвета объекта с белого на синий, не дожидаясь подтверждения сервера.

Взаимодействие клиента и сервера при упреждении выглядит примерно так:

Исходный цвет объекта - белый

Клиент

Клиент отправляет запрос на синий цвет. Локально цвет становится синим.

Объект предугадывает синий цвет и ждёт ответа сервера

Клиент получает команду установить синий цвет. Цвет остаётся синим.

Цвет синий

КЛИЕНТ

Сервер получает сообщение и устанавливает синий цвет

Сервер СЕРВЕР

Клиент упреждает состояние игры.

AnticipatedNetworkVariable<T> и AnticipatedNetworkTransform разделяют значения на упрежденное (визуальное) и авторитетное состояния. Упреждение - это прогнозируемое клиентом состояние, которое обеспечивает игроку немедленный локальный отклик. Авторитетное состояние определяет сервер. Получив обновление сервера, клиент сравнивает оба состояния. Если они заметно расходятся, клиент корректирует свое состояние по серверному, сохраняя согласованность между всеми клиентами.

Исходный цвет Клиент задаёт синий цвет. объекта - белый Локально он уже синий.

Клиент

Объект ожидает синий цвет и ответ сервера

Клиент получает синий цвет. Цвет остаётся синим.

Цвет объекта синий

Клиент получает красный цвет. Цвет становится красным.

Теперь цвет объекта красный

КЛИЕНТ

Сервер получает сообщение и задаёт синий цвет

Сервер

Сервер получает сообщение и задаёт красный цвет

СЕРВЕР

Исходный цвет объекта - белый

Клиент

Клиент задаёт красный цвет. Локально он уже красный.

Объект ожидает красный цвет и ответ сервера

Клиент получает синий цвет. Устаревшие данные игнорируются.

Цвет объекта красный

Клиент получает красный цвет. Цвет становится красным.

Цвет объекта остаётся красным

КЛИЕНТ

По времени отправки сообщение устарело.

Клиентское упреждение может игнорировать устаревшие данные.

При клиентском упреждении необходимо учитывать «устаревшие данные» - обновления сервера, отражающие действия, которые произошли до последнего запроса клиента. В Netcode for GameObjects свойство StaleDataHandling предлагает два варианта обработки:

- StaleDataHandling.Ignore игнорирует устаревшие данные и сохраняет упрежденное значение. Это полезно, если состояние меняется быстро и изображение начинает мерцать.

- StaleDataHandling.Reanticipate обрабатывает устаревшие данные как обычное обновление сервера: выполняет откат и повторное упреждение, воспроизводя ввод игрока для сохранения согласованности. Чтобы избежать резких визуальных скачков при расхождении серверных и упрежденных значений, используйте доступный обоим компонентам метод Smooth. Метод Smooth принимает начальное и конечное значения, а также длительность сглаживания. Это помогает сохранить плавный и отзывчивый визуальный отклик при сетевой задержке.

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

Детерминированная физика Детерминированная физическая система гарантирует, что при одинаковых начальных условиях и входных данных симуляция всегда даст одинаковый результат. Netcode for GameObjects использует встроенный физический движок Unity, который не является детерминированным: повторный запуск симуляции с теми же входными данными не гарантирует идентичного результата.

Netcode for Entities, напротив, поддерживает Unity Physics и Havok Physics с возможностью детерминированной симуляции. Благодаря этому пакет обеспечивает полноценное прогнозирование на стороне клиента.

Прогнозирование на стороне клиента в Netcode for Entities Netcode for Entities предоставляет развитые средства клиентского прогнозирования и компенсации задержки. Для каждой сущности на клиенте и сервере выполняется один и тот же код симуляции. Поэтому клиент может прогнозировать состояние игры по вводу игрока и давать немедленный отклик, не ожидая ответа сервера.

Получив от сервера последний снимок, клиент обновляет им все прогнозируемые сущности. Затем он запускает PredictedSimulationSystemGroup. Эта группа систем выполняет симуляцию от самого старого сохраненного тика до текущего целевого времени: откатывает и заново просчитывает состояние игры. Такой процесс исправляет расхождения и поддерживает синхронизацию с авторитетным состоянием сервера.

На сервере цикл прогнозирования выполняется один раз за кадр. Сервер обновляет авторитетное состояние игры и отправляет его клиенту. Клиент хранит историю ввода и прогнозируемых состояний. При рассинхронизации он откатывается к последнему корректному состоянию сервера и повторно просчитывает игру с правильными входными данными. Так клиент остается синхронизированным с эталонным состоянием сервера.

Netcode for Entities также поддерживает расширенные возможности физики: - Несколько физических миров: локальные физические симуляции, которые не нужно реплицировать по сети. - Пользовательские физические прокси: позволяют ghost-сущностям взаимодействовать с физическими объектами, существующими только на клиенте, например с обломками.

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

Сочетание прогнозирования, отката, компенсации задержки и сглаживания сводит к минимуму влияние сети, помогая сохранить целостность и отзывчивость игры. Сравним подходы Netcode for GameObjects и Netcode for Entities к клиентскому прогнозированию:

Характеристика

Netcode for GameObjects

Netcode for Entities

Прогнозирование

Ожидание на клиенте: клиент предугадывает ответ сервера.

Снижение задержки

Предугадывает результат Использует откат и повторную симуляцию сервера и сглаживает переходы. для исправления рассинхронизации.

Снимки

Явно не используются.

Представляют состояние игры в конкретные моменты.

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

Упрощённая модель с параметрами StaleDataHandling.

Полная компенсация задержки с обращением к мирам столкновений.

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

Физические Ограничено клиентским взаимодействия прогнозированием с упреждением преобразований.

Взаимодействие прогнозируемых и только клиентских физических миров.

Сглаживание

Метод Smooth для ожидаемых значений.

GhostPredictionSmoothingSystem сглаживает переходы между прогнозируемым и авторитетным состоянием.

Применение

Простые игры с мгновенной визуальной обратной связью.

Сложные игры, требующие точной синхронизации состояния.

И Netcode for GameObjects, и Netcode for Entities предоставляют механизмы клиентского прогнозирования и компенсации сетевой задержки. Netcode for GameObjects предлагает упрощенную модель клиентского упреждения, а Netcode for Entities - более развитую систему с полноценным прогнозированием, откатом и компенсацией задержки.

Термины Netcode for Entities

Netcode for Entities использует Entity Component System (ECS) и Data-Oriented Technology Stack (DOTS). Этот подход отличается от рабочего процесса MonoBehaviour в Netcode for GameObjects. Ниже перечислены термины, которые могут быть вам незнакомы: Entity (сущность): в ECS это базовая единица данных, представляющая отдельный игровой объект или компонент. Сущности легковесны и содержат только данные, но не поведение.

Game world (игровой мир): вся среда, в которой происходит игра. В нее входят все сущности, их состояния и правила взаимодействия. Collision world (мир столкновений): состояние всех физических объектов игрового мира, включая их положение, скорость и взаимодействия. Используется для обнаружения столкновений и физической симуляции. Snapshot (снимок, или ghost snapshot): набор данных о состоянии игры в определенный момент времени. Клиент и сервер периодически синхронизируют состояние игры с помощью снимков. Ghost: сетевая сущность, реплицируемая между сервером и клиентами. В каждом кадре сервер отправляет клиенту снимок текущего состояния всех ghost-сущностей. Они синхронизируют сущности, чтобы все игроки видели согласованное состояние игрового мира.

Predicted ghost (прогнозируемая ghost-сущность): клиентская сущность, которую локально симулируют для немедленного визуального отклика на действия игрока и снижения воспринимаемой задержки. Используйте такие сущности для объектов под непосредственным управлением игрока и других интерактивных объектов, требующих мгновенного отклика. Interpolated ghost (интерполированная ghost-сущность): представление серверной сущности на клиенте. Клиент отображает ее состояние по полученным от сервера снимкам, плавно смешивая их для уменьшения вызванного задержкой джиттера. Такой вариант подходит для объектов, которыми игрок не управляет напрямую и которым не нужен немедленный отклик: персонажей других игроков, NPC и управляемых сервером сущностей.