Мультиплеер в Unity: создание онлайн-игр от основ до реализации

Пройдите тест, узнайте какой профессии подходите
Сколько вам лет
0%
До 18
От 18 до 24
От 25 до 34
От 35 до 44
От 45 до 49
От 50 до 54
Больше 55

Для кого эта статья:

  • Разработчики игр, интересующиеся мультиплеерными возможностями Unity
  • Новички в разработке игр, желающие освоить сетевое программирование
  • Учебные учреждения и курсы, обучающие программированию и разработке игр на Unity

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

Изучая Unity и мультиплеерные возможности, вы развиваете ценные навыки программирования, применимые в веб-сфере! На курсе Обучение веб-разработке от Skypro вы сможете глубже понять те же архитектурные принципы клиент-серверного взаимодействия, но в контексте веб-приложений. Знания, полученные при создании мультиплеера, станут отличным фундаментом для разработки современных интерактивных сайтов и веб-сервисов с реал-тайм функциональностью.

Что такое мультиплеер в Unity 3D и как он работает

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

Unity предоставляет несколько подходов к реализации мультиплеера, но все они следуют общим принципам:

  • Клиент-серверная архитектура — один экземпляр игры выступает в роли сервера, который является авторитетным источником игровой информации, а остальные подключаются как клиенты
  • Peer-to-peer модель — устройства напрямую обмениваются данными без централизованного сервера
  • Гибридные решения — комбинация обоих подходов для оптимизации различных аспектов игрового процесса

Ключевые концепции мультиплеера в Unity включают:

Концепция Описание Применение
Network Identity Уникальный идентификатор для сетевых объектов Отслеживание игроков, NPC, интерактивных объектов
Network Transform Синхронизация позиции, вращения и масштаба Передвижение персонажей, объектов
Network Behavior Скрипты с сетевыми функциями Логика для синхронизации состояний
RPC (Remote Procedure Calls) Вызов функций на других клиентах События, действия игрока
Network Variables Автоматически синхронизируемые переменные Счёт, здоровье, состояния игры

Работа мультиплеера основана на обмене сетевыми сообщениями. Когда игрок совершает действие (например, нажимает на кнопку прыжка), клиент отправляет соответствующее сообщение на сервер. Сервер обрабатывает это сообщение, обновляет игровое состояние и рассылает обновления всем подключённым клиентам.

Александр Петров, ведущий разработчик мультиплеерных игр

Когда я только начинал работу над мультиплеером в Unity, я потратил две недели, пытаясь реализовать синхронизацию движения персонажа, которая работала бы без задержек. Мой код становился всё сложнее, пока я не осознал фундаментальную ошибку — я пытался синхронизировать абсолютно всё! Ключевым моментом стало понимание концепции "Network Authority" (сетевого авторитета).

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

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

Пошаговый план для смены профессии

Выбор сетевого решения: Mirror, Photon или Unity Netcode

Выбор правильного сетевого фреймворка определяет сложность разработки и возможности вашей мультиплеерной игры. Unity предлагает несколько решений, каждое с собственными преимуществами и ограничениями. 🛠️

Решение Модель хостинга Сложность освоения Масштабируемость Стоимость
Mirror Self-hosted Средняя Средняя Бесплатно (open-source)
Photon Облачная/Self-hosted Низкая Высокая Базовый план бесплатно, далее платно
Unity Netcode Self-hosted/Unity Game Server Hosting Средняя Высокая Базовый функционал бесплатно

Mirror — популярный open-source фреймворк, созданный как замена устаревшего Unity UNET. Он предлагает высокоуровневый API, основанный на компонентах, что делает его интуитивно понятным для разработчиков Unity.

Пример базовой настройки Mirror:

csharp
Скопировать код
// Пример скрипта игрока с Mirror
using Mirror;

public class Player : NetworkBehaviour 
{
[SyncVar]
public int health = 100;

[Command]
public void CmdTakeDamage(int amount) 
{
health -= amount;
if(health <= 0) 
{
// Логика смерти
}
}
}

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

Основные преимущества Photon:

  • Глобальная серверная инфраструктура с низкой задержкой
  • Масштабируемость — от нескольких игроков до тысяч одновременных сессий
  • Простой API с обширной документацией
  • Бесплатный тариф для проектов на стадии разработки

Пример подключения с Photon PUN:

csharp
Скопировать код
using Photon.Pun;
using Photon.Realtime;

public class NetworkManager : MonoBehaviourPunCallbacks 
{
void Start() 
{
PhotonNetwork.ConnectUsingSettings();
}

public override void OnConnectedToMaster() 
{
Debug.Log("Подключено к Photon!");
PhotonNetwork.JoinRandomRoom();
}

public override void OnJoinRandomFailed(short returnCode, string message) 
{
PhotonNetwork.CreateRoom(null, new RoomOptions { MaxPlayers = 4 });
}
}

Unity Netcode for GameObjects (ранее MLAPI) — это официальное решение от Unity, интегрированное в экосистему Unity и совместимое с Unity Gaming Services.

Ключевые особенности Netcode:

  • Тесная интеграция с Unity Editor
  • Встроенная система релевантности (интерес) для эффективной синхронизации
  • Network Variables с различными режимами репликации
  • Поддержка Unity Game Server Hosting

Выбор решения зависит от ваших конкретных требований:

  1. Для обучения и небольших проектов — Mirror (простой и бесплатный)
  2. Для быстрой разработки без настройки серверов — Photon (облачное решение)
  3. Для серьёзных проектов с перспективой масштабирования — Unity Netcode (официальная поддержка)

Марина Соколова, тимлид студии мобильных игр

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

Оценив затраты на решение этих проблем, мы приняли непростое решение — мигрировать на Photon. Процесс занял две недели, но результат превзошел ожидания. Уровень задержек снизился, проблемы с NAT решились автоматически, а облачная инфраструктура Photon позволила нам сосредоточиться на игровой механике, а не на сетевом стеке. Важный урок, который мы извлекли: правильное сетевое решение должно соответствовать не только текущим потребностям, но и учитывать будущее масштабирование проекта.

Настройка базового мультиплеера: Network Manager и компоненты

Network Manager — это центральное звено в мультиплеерной системе Unity, координирующее все сетевые операции. Давайте рассмотрим, как настроить базовую мультиплеерную систему на примере Mirror (принципы похожи для других фреймворков). 🔌

Первым шагом установите Mirror через Unity Package Manager или Asset Store. После импорта компонентов создайте пустой GameObject и добавьте компонент NetworkManager:

  1. Создайте пустой GameObject в сцене (GameObject -> Create Empty)
  2. Переименуйте его в "NetworkManager"
  3. Добавьте компонент Network Manager (Add Component -> Network -> Network Manager)
  4. Добавьте также Network Manager HUD для отладки (Add Component -> Network -> Network Manager HUD)

Основные настройки Network Manager включают:

  • Transport — компонент, отвечающий за фактическую передачу данных по сети
  • Player Prefab — префаб игрока, который будет создан для каждого подключившегося клиента
  • Registered Spawnable Prefabs — префабы, которые могут быть созданы по сети
  • Scene — настройки сцен для сетевой игры

Базовая настройка Network Manager выглядит так:

  1. Настройте транспорт (по умолчанию используется KCP Transport)
  2. Создайте префаб игрока с необходимыми сетевыми компонентами
  3. Назначьте этот префаб в поле Player Prefab в Network Manager
  4. Добавьте все сетевые префабы в список Registered Spawnable Prefabs

Для создания сетевого префаба игрока:

  1. Создайте базовый объект игрока (например, капсулу с компонентом Character Controller)
  2. Добавьте компонент Network Identity
  3. Добавьте Network Transform для синхронизации движения
  4. Создайте скрипт, наследующийся от NetworkBehaviour, для сетевой логики
  5. Превратите объект в префаб

Пример скрипта сетевого игрока:

csharp
Скопировать код
using UnityEngine;
using Mirror;

public class NetworkPlayer : NetworkBehaviour
{
[SerializeField] private float moveSpeed = 5f;

// SyncVar автоматически синхронизирует значение на всех клиентах
[SyncVar(hook = nameof(OnNameChanged))]
public string playerName = "Player";

// Вызывается только на локальном игроке
public override void OnStartLocalPlayer()
{
Camera.main.transform.SetParent(transform);
Camera.main.transform.localPosition = new Vector3(0, 1, -3);

// Установим случайное имя
CmdSetName("Player" + Random.Range(100, 999));
}

void Update()
{
// Проверяем, управляется ли этот объект локальным игроком
if (!isLocalPlayer) return;

// Получаем ввод
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");

// Вычисляем вектор движения
Vector3 movement = new Vector3(horizontal, 0f, vertical) * moveSpeed * Time.deltaTime;

// Перемещаем игрока
transform.position += movement;
}

// Command выполняется на сервере, но вызывается с клиента
[Command]
void CmdSetName(string newName)
{
playerName = newName;
}

// Хук для SyncVar, вызывается при изменении переменной
void OnNameChanged(string oldName, string newName)
{
Debug.Log($"Имя изменено с {oldName} на {newName}");
// Здесь можно обновить UI с именем игрока
}
}

Кроме Network Manager и префаба игрока, для полноценного мультиплеера потребуются дополнительные компоненты:

Компонент Назначение Типичное использование
Network Identity Идентификация объектов в сети Требуется для всех сетевых объектов
Network Transform Синхронизация позиции и вращения Движущиеся объекты, игроки
Network Animator Синхронизация анимаций Персонажи с анимациями
Network Proximity Checker Определение видимости объектов Оптимизация для больших карт

Для запуска мультиплеерной игры:

  1. В редакторе нажмите кнопку "Host" в Network Manager HUD — это запустит игру как сервер и одновременно клиент
  2. В собранном билде игроки могут нажать "Host" для создания сервера или "Client" для подключения к существующему серверу

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

  • В редакторе: запустите игру как Host
  • Запустите сборку игры и подключитесь как Client к localhost
  • Или используйте инструмент ParrelSync для запуска нескольких экземпляров редактора

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

Синхронизация объектов и состояний в мультиплеере Unity

Синхронизация игровых объектов и их состояний — это сердце мультиплеерной системы. От правильной архитектуры синхронизации зависит, насколько "плавным" будет игровой опыт для всех участников. 🔄

В Unity существуют четыре основных механизма синхронизации:

  1. State Synchronization — непрерывное обновление состояния объектов
  2. Remote Procedure Calls (RPCs) — вызов функций на удалённых клиентах
  3. Network Variables — автоматически синхронизируемые переменные
  4. Network Messages — низкоуровневый обмен пакетами данных

Рассмотрим каждый из этих механизмов подробнее.

State Synchronization используется для непрерывно меняющихся данных, например, положения игрока. В Mirror это реализуется через компоненты Network Transform:

csharp
Скопировать код
// Добавьте Network Transform к объекту с Network Identity
// Настройте параметры синхронизации в инспекторе:
// – Sync Direction (Server To Client или Client To Server)
// – Interpolation (плавность движения)
// – Compression (для оптимизации трафика)

Для нестандартных случаев вы можете написать собственную систему синхронизации:

csharp
Скопировать код
using Mirror;

public class CustomSync : NetworkBehaviour 
{
[SyncVar] // Атрибут для автоматической синхронизации
private Vector3 serverPosition;

[SerializeField] private float lerpRate = 15f; // Скорость интерполяции

void Update() 
{
if (isServer) 
{
// На сервере обновляем значение переменной
serverPosition = transform.position;
}
else 
{
// На клиенте плавно интерполируем к серверной позиции
transform.position = Vector3.Lerp(transform.position, serverPosition, Time.deltaTime * lerpRate);
}
}
}

Remote Procedure Calls (RPCs) позволяют вызывать функции на других устройствах. Mirror предоставляет несколько типов RPC:

  • [Command] — клиент вызывает функцию на сервере
  • [ClientRpc] — сервер вызывает функцию на всех клиентах
  • [TargetRpc] — сервер вызывает функцию на конкретном клиенте

Пример использования RPC для системы стрельбы:

csharp
Скопировать код
using Mirror;
using UnityEngine;

public class WeaponSystem : NetworkBehaviour 
{
[SerializeField] private GameObject bulletPrefab;

// Обрабатываем ввод только для локального игрока
void Update() 
{
if (!isLocalPlayer) return;

if (Input.GetButtonDown("Fire1")) 
{
// Вызываем команду на сервере
CmdFire();
}
}

// Выполняется на сервере по запросу клиента
[Command]
void CmdFire() 
{
// Создаем пулю на сервере (с Network Identity)
GameObject bullet = Instantiate(bulletPrefab, transform.position + transform.forward, transform.rotation);

// Задаём скорость пули
bullet.GetComponent<Rigidbody>().velocity = transform.forward * 20f;

// Регистрируем пулю в сетевой системе
NetworkServer.Spawn(bullet);

// Уведомляем всех клиентов о выстреле для визуальных эффектов
RpcOnFire();
}

// Выполняется на всех клиентах
[ClientRpc]
void RpcOnFire() 
{
// Звуковые/визуальные эффекты выстрела
GetComponent<AudioSource>().Play();
// Анимация отдачи и т.д.
}
}

Network Variables (SyncVars в Mirror) автоматически синхронизируют значения переменных с сервера на клиенты:

csharp
Скопировать код
public class Player : NetworkBehaviour 
{
[SyncVar(hook = nameof(OnHealthChanged))]
private int health = 100;

// Хук вызывается при изменении переменной
void OnHealthChanged(int oldValue, int newValue) 
{
// Обновляем UI или визуальное представление
UpdateHealthBar(newValue);
}

// Метод, изменяющий здоровье (вызывается на сервере)
[Server]
public void TakeDamage(int amount) 
{
health -= amount;
if (health <= 0) 
{
health = 0;
// Логика смерти
}
}

void UpdateHealthBar(int currentHealth) 
{
// Обновление UI здоровья
// ...
}
}

Синхронизация сложных объектов, таких как инвентарь или состояние игрового мира, часто требует комбинирования этих механизмов:

csharp
Скопировать код
public class Inventory : NetworkBehaviour 
{
// Список предметов в инвентаре
[SyncVar]
private string serializedInventory;

// Локальная копия инвентаря
private List<Item> items = new List<Item>();

// При изменении серализованной строки обновляем локальный инвентарь
public override void OnStartClient() 
{
if (!string.IsNullOrEmpty(serializedInventory)) 
{
items = JsonUtility.FromJson<List<Item>>(serializedInventory);
UpdateUI();
}
}

// Добавление предмета (вызывается на сервере)
[Server]
public void AddItem(Item item) 
{
items.Add(item);

// Сериализуем инвентарь для синхронизации
serializedInventory = JsonUtility.ToJson(items);

// Уведомляем клиента о новом предмете
TargetItemAdded(connectionToClient, item.id);
}

// Уведомление конкретного клиента
[TargetRpc]
void TargetItemAdded(NetworkConnection target, int itemId) 
{
// Анимация/звук получения предмета
PlayItemAcquiredEffect(itemId);
}
}

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

  • Приоритизация данных — синхронизируйте только то, что важно для игрового процесса
  • Компрессия данных — используйте квантование, дельта-сжатие и другие методы
  • Сетевая релевантность — отправляйте обновления только тем клиентам, которым они нужны
  • Интерполяция и предсказание — для сглаживания движения при высоком пинге

Для крупных игр с открытым миром часто используют зоны интереса (Areas of Interest):

csharp
Скопировать код
// Пример использования Network Proximity Checker
public class NetworkOptimizer : NetworkBehaviour 
{
[SerializeField] private float visibilityRange = 100f;

public override void OnStartServer() 
{
// Добавляем компонент только на сервере
gameObject.AddComponent<NetworkProximityChecker>().visRange = visibilityRange;
}
}

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

Пошаговая реализация простой мультиплеерной игры в Unity

Давайте создадим базовую мультиплеерную игру с возможностью перемещения персонажей и простым взаимодействием. Этот пример использует Mirror как сетевое решение. 🎮

Шаг 1: Настройка проекта и импорт Mirror

  1. Создайте новый 3D проект в Unity
  2. Импортируйте Mirror через Package Manager (Window -> Package Manager -> Add package from git URL -> введите https://github.com/vis2k/Mirror.git?path=/Assets/Mirror)
  3. Дождитесь завершения импорта

Шаг 2: Создание базовой сцены

  1. Создайте плоскость для пола (GameObject -> 3D Object -> Plane)
  2. Масштабируйте плоскость до размера 5x5 (в инспекторе Scale = 5, 1, 5)
  3. Добавьте на плоскость компонент Box Collider
  4. Создайте пустой GameObject и назовите его NetworkManager
  5. Добавьте компоненты Network Manager и Network Manager HUD

Шаг 3: Создание префаба игрока

  1. Создайте капсулу (GameObject -> 3D Object -> Capsule)
  2. Переименуйте её в "PlayerPrefab"
  3. Добавьте компоненты:
    • Network Identity
    • Network Transform
    • Rigidbody (с отключенной гравитацией)
    • Capsule Collider
  4. Создайте вложенный объект для камеры:
    • Создайте пустой GameObject как дочерний для PlayerPrefab
    • Назовите его CameraMount
    • Позиционируйте его на высоте (0, 0.5, 0) относительно родителя
  5. Перетащите PlayerPrefab в папку Prefabs, чтобы создать префаб

Шаг 4: Написание скрипта управления игроком

csharp
Скопировать код
using UnityEngine;
using Mirror;

public class PlayerController : NetworkBehaviour
{
[Header("Движение")]
[SerializeField] private float moveSpeed = 5f;
[SerializeField] private float rotationSpeed = 120f;

[Header("Персонализация")]
[SyncVar(hook = nameof(OnColorChanged))]
public Color playerColor = Color.white;

[SyncVar(hook = nameof(OnNameChanged))]
public string playerName = "Player";

[Header("Компоненты")]
[SerializeField] private Transform cameraMount;

// Кэшированные компоненты
private Renderer playerRenderer;
private TextMesh nameText;

void Awake()
{
// Получаем необходимые компоненты
playerRenderer = GetComponentInChildren<Renderer>();

// Создаем текстовое поле для имени
GameObject textObj = new GameObject("NameTag");
textObj.transform.SetParent(transform);
textObj.transform.localPosition = new Vector3(0, 1.2f, 0);
textObj.transform.localRotation = Quaternion.identity;

nameText = textObj.AddComponent<TextMesh>();
nameText.alignment = TextAlignment.Center;
nameText.anchor = TextAnchor.MiddleCenter;
nameText.fontSize = 36;
nameText.text = playerName;
}

public override void OnStartLocalPlayer()
{
// Настраиваем локального игрока
Camera.main.transform.SetParent(cameraMount);
Camera.main.transform.localPosition = new Vector3(0, 0, -3);
Camera.main.transform.localRotation = Quaternion.identity;

// Генерируем случайный цвет и имя
CmdSetColor(new Color(Random.value, Random.value, Random.value));
CmdSetName("Player" + Random.Range(100, 999));
}

void Update()
{
// Контролируем только локального игрока
if (!isLocalPlayer) return;

// Получаем ввод
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");

// Вращение
transform.Rotate(0, horizontal * rotationSpeed * Time.deltaTime, 0);

// Движение вперед/назад
Vector3 movement = transform.forward * vertical * moveSpeed * Time.deltaTime;
transform.position += movement;
}

// Команды (вызываются на клиенте, выполняются на сервере)

[Command]
void CmdSetColor(Color color)
{
// Валидация на сервере (например, запрет на черный цвет)
if (color.r + color.g + color.b < 0.3f)
{
color = Color.red; // Слишком темный цвет, используем красный
}

playerColor = color;
}

[Command]
void CmdSetName(string name)
{
// Валидация имени
name = name.Substring(0, Mathf.Min(name.Length, 12));
playerName = name;
}

// Хуки для SyncVar
void OnColorChanged(Color oldColor, Color newColor)
{
playerRenderer.material.color = newColor;
}

void OnNameChanged(string oldName, string newName)
{
nameText.text = newName;
}
}

Шаг 5: Настройка Network Manager

  1. Выберите объект NetworkManager в сцене
  2. Перетащите префаб игрока в поле Player Prefab
  3. Убедитесь, что транспорт настроен (по умолчанию используется KCP Transport)

Шаг 6: Создание простого игрового объекта для взаимодействия

csharp
Скопировать код
using UnityEngine;
using Mirror;

public class CollectibleItem : NetworkBehaviour
{
[SyncVar]
private bool isCollected = false;

private void OnTriggerEnter(Collider other)
{
// Проверяем, что объект не собран и игрок – NetworkBehaviour
if (!isCollected && other.TryGetComponent<NetworkIdentity>(out NetworkIdentity identity) && identity.isLocalPlayer)
{
// Вызываем команду на сервере
CmdCollectItem(identity.netId);
}
}

[Command(requiresAuthority = false)]
void CmdCollectItem(uint playerNetId)
{
// Проверка, не собран ли уже предмет
if (isCollected) return;

// Отмечаем предмет как собранный
isCollected = true;

// Находим игрока по netId
if (NetworkServer.spawned.TryGetValue(playerNetId, out NetworkIdentity player))
{
// Оповещаем всех клиентов
RpcItemCollected(player.netId);

// Скрываем объект (можно также уничтожить его)
GetComponent<MeshRenderer>().enabled = false;
GetComponent<Collider>().enabled = false;
}
}

[ClientRpc]
void RpcItemCollected(uint playerNetId)
{
Debug.Log($"Игрок с ID {playerNetId} собрал предмет!");

// Проигрываем эффект сбора
if (TryGetComponent<AudioSource>(out AudioSource audioSource))
{
audioSource.Play();
}
}
}

Создайте несколько сфер на сцене, добавьте им компоненты Network Identity и скрипт CollectibleItem.

Шаг 7: Тестирование мультиплеера

  1. Запустите игру в редакторе
  2. Нажмите кнопку "Host" в Network Manager HUD
  3. Создайте билд игры (File -> Build Settings)
  4. Запустите билд и нажмите "Client"
  5. Введите "localhost" в поле адреса (или IP вашего компьютера при тестировании по сети)
  6. Теперь у вас должны быть два игрока на одной карте, каждый управляет своим персонажем

Шаг 8: Добавление простого счета очков

Модифицируем PlayerController, добавив систему очков:

csharp
Скопировать код
// Добавьте в класс PlayerController:

[SyncVar(hook = nameof(OnScoreChanged))]
private int score = 0;

private TextMesh scoreText;

// В Awake добавьте:
GameObject scoreObj = new GameObject("ScoreTag");
scoreObj.transform.SetParent(transform);
scoreObj.transform.localPosition = new Vector3(0, 1.5f, 0);
scoreText = scoreObj.AddComponent<TextMesh>();
scoreText.alignment = TextAlignment.Center;
scoreText.text = "Score: 0";

// Добавьте новый метод:
[Server]
public void AddScore(int points)
{
score += points;
}

// И хук для SyncVar:
void OnScoreChanged(int oldScore, int newScore)
{
scoreText.text = $"Score: {newScore}";
}

Изменим CollectibleItem для начисления очков:

csharp
Скопировать код
// В методе CmdCollectItem добавьте:
if (NetworkServer.spawned.TryGetValue(playerNetId, out NetworkIdentity playerIdentity))
{
// Проверяем, есть ли компонент PlayerController
if (playerIdentity.TryGetComponent<PlayerController>(out PlayerController playerController))
{
// Начисляем очки
playerController.AddScore(10);
}

// ... остальной код
}

Шаг 9: Дополнительные улучшения (по желанию)

  • Добавьте звуковые эффекты для действий игрока
  • Создайте UI для отображения списка игроков
  • Реализуйте базовый чат между игроками
  • Добавьте проверку на столкновения между игроками
  • Создайте систему перезапуска уровня или выхода в меню

Этот базовый пример демонстрирует основные принципы мультиплеерной разработки в Unity: синхронизацию состояний с помощью SyncVar, передачу команд от клиентов к серверу через Command и отправку событий всем клиентам через ClientRpc. С этой основой вы можете расширять функциональность для создания более сложных мультиплеерных проектов. 🚀

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

Читайте также

Проверь как ты усвоил материалы статьи
Пройди тест и узнай насколько ты лучше других читателей
Какова основная разница между P2P и клиент-серверной архитектурой в мультиплеерных играх?
1 / 5

Загрузка...