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

Настройка первого проекта Netcode

Настройка первого проекта Netcode

Если вы еще не работали с сетевыми решениями Unity, для создания базового проекта Netcode потребуется импортировать необходимые сетевые пакеты и настроить многопользовательские компоненты. В этой главе мы добавим сетевое взаимодействие в демонстрационный проект с помощью Netcode for GameObjects. Напомним, что в Unity 6 новый многопользовательский проект можно настроить через Multiplayer Center, а дополнительные сервисы Unity интегрировать с помощью Multiplayer Widgets.

Прежде чем начать Убедитесь, что у вас есть: - Активная учетная запись Unity с действующей лицензией. - Unity Hub - Поддерживаемая версия Unity Editor. Для некоторых показанных возможностей требуется Unity 6 или новее; подробности см. в требованиях Netcode for GameObjects.

- Доступ к Unity Cloud Dashboard для подключения необходимых проекту сервисов Unity; настроить его можно через Unity Hub.

Настройка демонстрационного проекта Удобнее всего знакомиться с инструментами сетевого кода на существующем проекте с однопользовательским управлением персонажем. В этом руководстве используется пакет Starter Assets - ThirdPerson из Unity Asset Store. Он демонстрирует простой трехмерный игровой процесс с гуманоидным персонажем на Universal Render Pipeline (URP). Загрузите этот бесплатный ресурс из Unity Asset Store, затем импортируйте его с помощью Package Manager.

Пакет Starter Assets из Unity Asset Store

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

Установка Netcode for GameObjects В Package Manager (Window > Package Manager) установите фильтр Unity Registry, затем установите следующие пакеты: - Netcode for GameObjects: базовая сетевая библиотека, которая добавляет многопользовательские возможности в существующий рабочий процесс GameObject/MonoBehaviour. Она упрощает разработку сетевых игр и служит отличной отправной точкой. - Multiplayer Tools Window: дополнительный набор из пяти инструментов Unity 6, улучшающих рабочие процессы многопользовательской разработки: - Multiplayer Tools Window предоставляет в одном месте удобный доступ ко всем многопользовательским инструментам и их документации. - Network Simulator воспроизводит реальные сетевые условия - задержку и потерю пакетов, разрывы соединения - и помогает выявить проблемы до выпуска игры. - Runtime Network Stats Monitor (RNSM) отображает сетевую статистику в реальном времени и позволяет настраивать экранный мониторинг производительности сети.

- Network Scene Visualization упрощает отладку, наглядно отображая сетевую активность и владение объектами в окне Scene. - Hierarchy Network Debug добавляет в правую часть окна Hierarchy слой, который отмечает сетевые объекты небольшим значком сетевого куба.

- Multiplayer Play Mode: пакет Unity 6 для тестирования многопользовательских возможностей без выхода из Unity Editor. Он позволяет имитировать до четырех игроков - Main Editor Player и трех Virtual Players - и ускоряет проверку игрового процесса.

Установите Netcode for GameObjects и его вспомогательные пакеты.

Добавление NetworkManager Для поддержки сетевой многопользовательской игры каждому проекту нужен компонент NetworkManager. Он управляет сетевым состоянием проекта, соединениями и параметрами сети. Чтобы добавить NetworkManager в сцену, создайте в окне Hierarchy новый GameObject и добавьте компонент NetworkManager (Netcode > NetworkManager). В компоненте NetworkManager настройте сетевой транспорт, выбрав Unity Transport.

Транспорт не выбран. Для работы Netcode нужен транспорт. Какой вариант использовать?

Выберите транспортный слой в NetworkManager.

К GameObject будет добавлен компонент UnityTransport. Транспортный слой отвечает за низкоуровневые сетевые задачи, включая управление соединениями, передачу данных и шифрование пакетов.

Для локального тестирования отключайте удалённые подключения, чтобы не открывать порты устройства.

Компонент UnityTransport

Пока изменять эти параметры не требуется, но с помощью компонента можно имитировать сетевые условия - задержку, потерю пакетов и jitter - при тестировании и отладке в Unity Editor. Сохраните сцену, откройте File > Build Settings и убедитесь, что текущая сцена добавлена в список Scenes in Build. Тогда новый NetworkManager войдет в сборку игры.

NetworkObjects NetworkObject - обязательный компонент любого GameObject, который должен быть доступен по сети или синхронизироваться между клиентами многопользовательской игры. После добавления NetworkObject объект становится сетевым: его состояние и поведение можно передавать и обновлять по сети.

Компонент NetworkObject и его уникальный идентификатор

У каждого NetworkObject есть несколько идентификаторов: - GlobalObjectIdHash идентифицирует ресурс префаба в проекте. - NetworkObjectId - уникальный идентификатор, различающий экземпляры одного и того же префаба. - OwnerClientId указывает клиента, которому принадлежит объект (см. раздел о полномочиях ниже).

Эти идентификаторы позволяют NetworkManager отслеживать объект и поддерживать согласованность его состояния у всех подключенных клиентов. Объекты NetworkObject можно динамически создавать (spawn) и уничтожать во время игры. При создании NetworkObject появляется у всех подключенных клиентов. У каждого такого объекта есть владелец - обычно клиент, управляющий его поведением и состоянием.

Объекты Player NetworkObject У каждого игрока может быть собственный префаб Player NetworkObject. Это особый вид NetworkObject, который обычно содержит контроллер персонажа и его визуальное представление в игре.

Player NetworkObject в демонстрационном проекте

Объекты Player NetworkObject часто хранят и синхронизируют данные конкретного игрока: имя, счет, инвентарь и другие сведения. Синхронизация по сети обеспечивает всем подключенным игрокам согласованное представление состояния игры. При подключении клиента NetworkManager создает принадлежащий соответствующему игроку Player NetworkObject. Игрок получает полномочия над своим PlayerObject и может управлять его поведением и состоянием. Чтобы настроить Player NetworkObject, сначала создайте в проекте обычный префаб GameObject. Он станет шаблоном PlayerObject и будет содержать компоненты и скрипты, определяющие поведение и внешний вид игрока.

Затем добавьте необходимые компоненты Netcode. Например: - NetworkObject: каждому сетевому объекту требуется компонент NetworkObject. Он содержит свойства и события, связанные с созданием, удалением и владением объектом. - NetworkBehaviour: эти скрипты добавляют сетевую логику к базовому классу MonoBehaviour. Они содержат NetworkVariable, удалённые вызовы процедур (RPC) и сетевые обратные вызовы. - NetworkAnimator: этот компонент синхронизирует состояния и параметры анимации между клиентами. - NetworkTransform: этот компонент обеспечивает репликацию позиции, поворота и масштаба игрока с сервера на все подключённые клиенты в реальном времени. NetworkObject игрока часто отвечает за обработку его ввода. Когда игрок выполняет действие - например, перемещается или взаимодействует с игровым миром, - ввод обрабатывается и при необходимости передаётся другим подключённым игрокам. Логика игрока сочетает MonoBehaviour для обычной игровой механики и NetworkBehaviour для управления сетевым состоянием. Несетевые компоненты, такие как контроллер персонажа и Animator, работают обычным образом в локальном экземпляре каждого игрока. Локальная работа этих компонентов не только повышает производительность, но и сокращает сетевой трафик, что особенно важно при ограниченной пропускной способности соединений между клиентами.

Создание NetworkObject игрока Откройте сцену Playground из примера проекта.

Пакет Starter Assets содержит сцену Playground.

В Hierarchy находится объект PlayerArmature, который управляет игровым персонажем. Чтобы превратить его в NetworkObject игрока, перетащите объект из Hierarchy и создайте новый Original Prefab либо измените копию существующего префаба проекта. Найдите GameObject PlayerArmature в окне Hierarchy. Удалите его вместе с дочерними объектами, чтобы в сцене осталось только игровое окружение.

Затем откройте префаб в Inspector и добавьте компонент NetworkObject. Благодаря ему объект распознаётся и управляется по сети.

Добавьте компонент NetworkObject в префаб.

Укажите NetworkObject игрока в поле Player Prefab компонента NetworkManager.

Зарегистрируйте NetworkObject игрока в NetworkManager.

В Play mode отображается только игровое окружение. NetworkObject игрока появится лишь после подключения клиента. Выберите NetworkManager, который теперь находится в разделе DontDestroyOnLoad окна Hierarchy.

Запустите хост через NetworkManager.

Нажмите Start Host. После этого будет создан сетевой объект игрока.

В Hierarchy появится объект PlayerArmature_Network. Игрой снова можно управлять, хотя цель камеры отключена. Проверьте перемещение игрока клавишами WASD.

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

Multiplayer Play Mode Для тестирования многопользовательской игры приложение должно работать в нескольких отдельных процессах. Раньше для этого приходилось создавать отдельную сборку игры и запускать её параллельно с Unity Editor. Этот способ по-прежнему доступен, однако в Unity 6 есть Multiplayer Play Mode (MPPM). Он позволяет одновременно открыть несколько экземпляров Unity Editor и воспроизвести многопользовательскую среду, тем самым упрощая тестирование. Установите Multiplayer Play Mode через Package Manager. После этого для проверки каждой новой функции не придётся заново собирать приложение. Откройте Multiplayer Play Mode: Window > Multiplayer Play Mode.

Окно Multiplayer Play Mode

Затем включите в списке на снимке выше хотя бы один дополнительный Virtual Player. Так вы сможете протестировать как минимум один хост и один клиент. Помните: хост это клиент, который одновременно выполняет роль сервера. При переходе в Play mode второй сеанс приложения запускается в клонированном окне.

Multiplayer Play Mode клонирует Virtual Player.

Выберите NetworkManager в Hierarchy. В разделе Start Connection окна Inspector нажмите Start Host. В окне Game появится объект PlayerArmature_Networked. Во втором окне нажмите Layout и включите Inspector и Hierarchy, чтобы оно выглядело как ещё один сеанс Editor. Выберите нужные элементы интерфейса и нажмите Apply.

Включите нужные Layouts в клонированном окне.

В клонированном окне Editor найдите NetworkManager в разделе DontDestroyOnLoad окна Hierarchy. В Inspector, в разделе Start Connection, нажмите Start Client.

NetworkManager содержит кнопки для подключения клиента.

Теперь в Hierarchy отображаются два экземпляра PlayerArmature_Networked. В окне Scene они расположены друг на друге. Переместите один экземпляр с помощью клавиатуры или геймпада, чтобы разделить игроков. Выберите экземпляр PlayerArmature_Networked в Hierarchy и изучите его компонент NetworkObject. Во время выполнения каждый экземпляр определяется сочетанием GlobalObjectIdHash идентификатора ресурса проекта - и NetworkObjectId - уникального индекса экземпляра. Ниже свойство OwnerClientId показывает, кто управляет экземпляром: хост или клиент.

Переключайтесь между экземплярами и сравните флаги IsSpawned, IsLocalPlayer, IsOwner, IsOwnerByServer и другие.

Клиент

Сервер/хост Сравните настройки NetworkObject двух экземпляров.

Чтобы легче различать экземпляры, используйте панель Network Visualization. Этот удобный диагностический инструмент появляется в окне Scene после установки пакета Multiplayer Tools. Экземпляры кодируются цветом по объёму трафика - Bandwidth - или по владению Ownership, которое показывает, какой клиент имеет полномочия над NetworkObject игрока.

Network Visualization помогает отлаживать сетевые объекты.

NetworkManager создаёт отдельный экземпляр для каждого клиента, однако каждый из них независимо управляет одним и тем же персонажем. Перемещение с помощью WASD в окне Scene пока не синхронизируется между клиентом и хостом. При первом подключении игроков NetworkManager синхронизирует их позиции в точке (0, 0, 0), но дальнейшие перемещения уже не синхронизируются. Сейчас поведением персонажа управляют несколько локальных компонентов:

- CharacterController позволяет игроку перемещаться и взаимодействовать с игровым окружением без сложных физических расчётов. - Animator воспроизводит анимацию на основе машины состояний и управляет переходами и смешиванием состояний бега, прыжка и бездействия. - PlayerInput управляет вводом отдельно для каждого игрока, сопряжением устройств и уведомлениями о событиях, предоставляя высокоуровневую оболочку над Unity Input System.

- StarterAssetsInputs преобразует этот ввод в значения перемещения, обзора, прыжка и спринта персонажа. Это компоненты для одиночной игры. Чтобы они работали в многопользовательском приложении, необходимо добавить сетевую логику.

Создание собственных кнопок запуска сеанса Чтобы удобнее запускать сетевые сеансы во время выполнения, добавьте экранные кнопки, которые повторяют функции кнопок NetworkManager в Inspector. Для этого подойдут Unity UI (UGUI) или UI Toolkit. Создайте в выбранной системе интерфейса три кнопки: Client, Host и Server. Назначьте им соответствующие методы синглтона NetworkManager: - NetworkManager.Singleton.StartClient - NetworkManager.Singleton.StartHost - NetworkManager.Singleton.StartServer Эти методы позволяют запускать сетевой сеанс без кнопок в окне Inspector.

Добавление NetworkBehaviour Для управления компонентами MonoBehaviour объекта PlayerArmature_Networked можно использовать NetworkBehaviour. NetworkBehaviour - специализированный тип MonoBehaviour для сетевой логики. Он предоставляет средства синхронизации действий и состояний между игровыми клиентами. NetworkBehaviour поддерживает те же события жизненного цикла, что и MonoBehaviour, а также предоставляет сетевые возможности: Методы RPC: NetworkBehaviour может использовать удалённые вызовы процедур (RPC) для обмена данными по сети. Такие методы помечаются атрибутом [Rpc]. Для отправки RPC на сервер или клиент используются соответственно [Rpc(SendTo.Server)] и [Rpc(SendTo.Client)].

- NetworkVariable: специализированная переменная для синхронного управления состоянием по сети. Изменения NetworkVariable на сервере автоматически передаются всем клиентам. - OnNetworkSpawn и OnNetworkDespawn: методы жизненного цикла, вызываемые при создании и удалении NetworkBehaviour. OnNetworkSpawn выполняет инициализацию - подобно OnEnable или Start, но для сетевого поведения. OnNetworkDespawn очищает ресурсы перед удалением объекта из сети, аналогично OnDestroy или OnDisable. - Владение: NetworkBehaviour позволяет назначить определённые объекты конкретным клиентам или серверу. Такая модель полномочий, при которой NetworkObject принадлежит клиенту либо серверу, гарантирует, что управлять объектом и взаимодействовать с ним смогут только назначенные игроки.

Для управления перемещением игрока реализуем NetworkBehaviour с именем ClientPlayerMove. Он гарантирует, что ввод хоста и клиента воздействует только на соответствующие им объекты игроков. Ниже приведён пример настройки:

C#
using Unity.Netcode;
using StarterAssets;
using UnityEngine;
using UnityEngine.InputSystem;
namespace NetcodeDemo {
    public class ClientPlayerMove: NetworkBehaviour {
        [SerializeField] CharacterController m_CharacterController;
        [SerializeField] ThirdPersonController m_ThirdPersonController;
        [SerializeField] PlayerInput m_PlayerInput;
        [SerializeField] Transform m_CameraFollow;
        private void Awake() {
            m_PlayerInput.enabled = false;
            m_ThirdPersonController.enabled = false;
            m_CharacterController.enabled = false;
        }
        public override void OnNetworkSpawn() {
            base.OnNetworkSpawn();
            ∕∕ Enable Включить клиенте. enabled = IsClient;
            // if на this is a client. if (!IsOwner) {

                ∕∕ клиенту // Отключить, Disable if если this объект is not не theпринадлежит owner enabled = false;

                m_PlayerInput.enabled = false;
                m_CharacterController.enabled = false;
                m_ThirdPersonController.enabled = false;
                return;
            }
            ∕∕ Enable Включить, если is объект принадлежит клиенту // if this an owner m_PlayerInput.enabled = true;

            m_CharacterController.enabled = true;
            m_ThirdPersonController.enabled = true;
        }
    }
}

Добавьте этот компонент в префаб PlayerArmature_Networked, затем заполните нужные поля в Inspector.

Заполните поля ClientPlayerMove в Inspector.

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

В Hierarchy поочерёдно выбирайте два экземпляра PlayerArmature_Networked.

Клиент

Компоненты отключены, если клиент не владелец

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

Обратите внимание: у экземпляров игрока, которыми не владеет соответствующий клиент, теперь отключены некоторые компоненты, например PlayerInput. Хост управляет одним экземпляром игрока, а клиент - другим. Теперь разными экземплярами игроков можно управлять независимо, однако их перемещение ещё не синхронизируется по сети. Чтобы хост и клиент видели одинаковое движение, добавим сетевые компоненты, например NetworkTransform.

Свойства полномочий и владения По умолчанию NetworkObject принадлежат серверу, однако подключённый и одобренный клиент тоже может получить объект во владение с помощью метода SpawnWithOwnership. В Netcode for GameObjects сервер является авторитетной стороной: только он может создавать и удалять NetworkObject.

NetworkBehaviour предоставляет несколько свойств для быстрой проверки полномочий и владельца экземпляра: - IsClient показывает, выполняется ли экземпляр на клиенте. - IsServer показывает, выполняется ли экземпляр на сервере.

- IsHost показывает, выполняется ли экземпляр на хосте, который одновременно является сервером и клиентом. - IsLocalPlayer показывает, является ли связанный NetworkObject объектом локального игрока.

- IsOwner показывает, владеет ли локальный игрок этим объектом либо является ли объект локальным игроком. - IsPlayerObject показывает, представляет ли GameObject сетевого игрока, которым обычно управляет определённый клиент. - IsSceneObject показывает, является ли GameObject изначально частью сцены, а не создаётся динамически во время игры. Обычно сервер управляет объектами сцены, чтобы их состояние оставалось согласованным по сети. При проверке NetworkObject во время выполнения отображаются некоторые из этих свойств.

Настройки NetworkObject

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

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

В Multiplayer Play Mode активируйте окно хоста: теперь можно управлять игроком и наблюдать, как его движение синхронизируется с клиентом. Это первый шаг к сетевой игре.

Затем добавьте компонент NetworkAnimator в PlayerArmature_Networked и перетащите существующий компонент Animator в пустое поле.

Укажите в поле

Снимите флажки с ненужных осей

Добавьте компоненты NetworkTransform и NetworkAnimator.

Окно клиента представляет второе устройство, подключённое к хосту. В идеале любое действие на хосте должно отображаться на клиенте и наоборот. NetworkTransform синхронизирует позицию, поворот и масштаб Transform, а NetworkAnimator - состояния анимации. Теперь перемещения игрока-хоста по сцене Playground передаются клиенту в Multiplayer Play Mode. Однако не всё работает как ожидается. Переключитесь на окно клиента и попробуйте управлять персонажем. Хост корректно синхронизируется с клиентом, но перемещения клиента могут не отображаться на хосте.

Экземпляр клиента анимируется локально, но не перемещается

Игрок словно бежит на месте.

Клиент получает ввод - это видно по анимации бега на месте, - но экземпляр игрока не перемещается. Причина в том, что NetworkTransform подчиняется серверу и синхронизирует с клиентом только позицию сервера. При попытке переместить игрока на клиенте сервер переопределяет требуемую позицию и возвращает объект в точку (0, 0, 0).

Передача полномочий клиенту По умолчанию NetworkTransform работает в режиме серверных полномочий. Изменения осей Transform отслеживаются на сервере и передаются подключённым клиентам.

В нашем примере переместить игрока на клиенте не удаётся: сервер сохраняет авторитетное состояние с Transform в точке (0, 0, 0) и переопределяет изменения клиента.

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

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

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

Клиент

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

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

Клиент пытается переместить объект

КЛИЕНТ

Клиент возвращается к авторитетному состоянию в точке (0, 0, 0)

Серверные полномочия переопределяют состояние клиента.

Один из способов решить проблему - передать полномочия от сервера клиенту. Тогда клиент сможет управлять собственным Transform, а сервер не будет переопределять изменения.

Для этого создадим компонент ClientNetworkTransform, как в следующем примере кода. Он заменяет серверные полномочия полномочиями владельца:

C#
using Unity.Netcode.Components;
using UnityEngine;
namespace NetcodeDemo {
    [DisallowMultipleComponent] public class ClientNetworkTransform : NetworkTransform {
        protected override bool OnIsServerAuthoritative() { return false; }
    }
}

Этот код переопределяет метод OnIsServerAuthoritative и возвращает false. В префабе NetworkObject игрока замените NetworkTransform пользовательским ClientNetworkTransform. Аналогичным образом можно создать NetworkAnimator, управляемый клиентом:

C#
using Unity.Netcode.Components;
using UnityEngine;
namespace NetcodeDemo {
    [DisallowMultipleComponent] public class ClientNetworkAnimator: NetworkAnimator {
        protected override bool OnIsServerAuthoritative() { return false; }
    }
}

Замените NetworkAnimator компонентом ClientNetworkAnimator и не забудьте назначить поле Animator в Inspector.

Компоненты ClientNetworkTransform и ClientNetworkAnimator.

Теперь в Multiplayer Play Mode можно управлять игроком с клиента: его позиция и состояния анимации должны корректно синхронизироваться с хостом. Поведение под управлением клиента также снижает задержку в сетевых приложениях. В режиме полномочий владельца сетевые действия выполняются сразу и ощущаются отзывчивыми: клиенту не нужно ждать, пока пакет дойдёт до сервера и вернётся обратно.

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

Компоненты в режиме полномочий владельца Скрипты из примеров выше можно написать самостоятельно либо взять готовые ClientNetworkTransform и ClientNetworkAnimator из пакета Multiplayer Samples Utilities проекта Unity Boss Room (com.unity.multiplayer.samples.coop).

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

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

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

Например, если клиенты сами выбирают место появления на карте, её планировка может дать им несправедливое преимущество. Лучше, чтобы сервер случайным образом назначал одну из заранее заданных точек появления.

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

Точки появления стратегически размещены по всему уровню.

Управлять ими может несетевой MonoBehaviour. В данном примере класс ServerPlayerSpawnPoints содержит список m_SpawnPoints со ссылками на GameObject каждой точки появления.

В примере также используется универсальный шаблон Singleton из проекта Unity для Asset Store Level up your code with design patterns and SOLID:

C#
public class ServerPlayerSpawnPoints : Singleton<ServerPlayerSpawnPoints> {
    [SerializeField] private List<GameObject> m_SpawnPoints;
    public GameObject GetRandomSpawnPoint() {
        if (m_SpawnPoints.Count == 0) return null;
        return m_SpawnPoints[Random.Range(0, m_SpawnPoints.Count)];
    }
}

Затем NetworkBehaviour с именем ServerPlayerMove может использовать экземпляр ServerPlayerSpawnPoints для случайного выбора точки появления.

C#
using Unity.Netcode;
using UnityEngine;
до ClientNetworkTransform [DefaultExecutionOrder(0)] ∕∕ // Выполнить Execute before ClientNetworkTransform

public class ServerPlayerMove : NetworkBehaviour {
    public override void OnNetworkSpawn() {
        ∕∕ только на сервере // Выполнять Only execute on the Server if (!IsServer) { enabled = false; return; }

        SpawnPlayer();
        base.OnNetworkSpawn();
    }
    ∕∕ следующей свободной точке при // Перейти Move to к the next available position whenпоявлении spawning

    void SpawnPlayer() {
        var spawnPoint = ServerPlayerSpawnPoints.Instance.GetRandomSpawnPoint();
        var spawnPosition = spawnPoint ? spawnPoint.transform.position : Vector3.zero;
        transform.position = spawnPosition;
    }
}

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

Добавьте скрипт ServerPlayerMove в префаб PlayerArmature_Networked. В Multiplayer Play Mode каждый клиент подключится и появится в случайной точке сцены Playground.

Этот пример показывает, как NetworkBehaviour взаимодействует с элементами сцены, не управляемыми по сети. Он использует статические данные и объекты, заранее настроенные в Hierarchy. При подключении клиента ServerPlayerMove достаточно получить одну случайную точку появления из существующей игровой сцены. Это сокращает объём передаваемых по сети данных.

Игрок появляется в случайной точке.

Несколько важных моментов: - Поскольку ClientNetworkTransform использует полномочия владельца, компонент CharacterController необходимо отключить в Awake. Снова включите CharacterController после того, как ServerPlayerMove задаст позицию игрока, иначе компонент переопределит рассчитанные координаты и вернёт объект в центр мира. - Также заполните список m_SpawnPoints в Inspector, чтобы игроки не появлялись в точке (0, 0, 0). - Задайте атрибуту DefaultExecutionOrder меньшее значение, чтобы ServerPlayerMove выполнялся раньше ClientPlayerMove. Например, [DefaultExecutionOrder(0)] повышает приоритет ServerPlayerMove и позволяет ему запуститься первым.

Теперь к хосту нашего многопользовательского проекта могут подключаться несколько клиентов. Персонажи от третьего лица появляются в заданных местах уровня и синхронизируют перемещение и анимацию в реальном времени. Такая синхронизация необходима для многопользовательской игры. Компоненты NetworkTransform и NetworkAnimator обеспечивают её из коробки, но игровая логика также потребует собственных NetworkBehaviour.

Теперь рассмотрим другие способы синхронизации данных и игровых состояний по сети.

Шаблон проектирования Singleton Singleton предоставляет удобный доступ к единственному экземпляру определённого типа во время выполнения. Однако он создаёт дополнительные зависимости, поэтому учитывайте недостатки этого шаблона. В Netcode for GameObjects Singleton используется при каждом обращении к NetworkManager.Singleton. В примере проекта также есть универсальная реализация Singleton для любого типа MonoBehaviour. Подробнее о Singleton рассказывает электронная книга Level up your code with design patterns and SOLID. В ней также показаны альтернативные способы взаимодействия объектов сцены, например обычные события и каналы событий.

ВЫВЕДИТЕ КОД НА НОВЫЙ УРОВЕНЬ С ПОМОЩЬЮ ШАБЛОНОВ ИГРОВОГО ПРОГРАММИРОВАНИЯ Принципы SOLID Шаблоны проектирования

ШАБЛОНЫ ПРОЕКТИРОВАНИЯ

Другие ресурсы Шаблоны проектирования повторно используемые решения распространённых задач проектирования ПО.

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