Игры (GameDev)

Ray of Life

Кросс-клиентская мультиплеерная игра в реальном времени для мобильных устройств (Unity 2021.3 LTS, Photon PUN 2). В постапокалиптическом открытом мире на автомобилях соревнуются за луч жизни - источник энергии, который появляется в случайной точке карты: нужно добыть ключ на одной из активных станций, добраться до луча, удержать его и зарядить аккумулятор, попутно отбивая ключи у соперников. Победитель определяется по накопленной энергии либо по истечении 10-минутного раунда. Проект реализует полный игровой цикл от матчмейкинга до экрана результатов с детерминированной синхронизацией мира между всеми клиентами.
Unity C# Photon

Задача

Создать готовый к публикации мобильный мультиплеер в реальном времени, в котором:
  • несколько игроков видят одинаковое состояние мира - позицию луча, активные станции, ключи, уровни энергии - независимо от момента входа в комнату;
  • соревновательная механика устойчива к гонкам состояний (race conditions): одновременная зарядка от одного луча, кража ключей, одновременное завершение матча;
  • раунд завершается синхронно у всех ровно через 10 минут, без расхождения таймеров;
  • управление и камера комфортны для сенсорного экрана;
  • весь стек укладывается в бесплатные/доступные инфраструктурные лимиты (relay-сервер Photon, без собственного бэкенда).
Основная сложность - не графика, а сетевой детерминизм: в peer-to-peer-модели Photon без выделенного авторитетного сервера нужно гарантировать, что у всех клиентов мир сходится к одному состоянию.

Решение

Архитектура построена на авторитетной модели master-client: один клиент-хозяин владеет генерацией событий мира и игровым таймером, остальные получают состояние через реплицируемые вызовы.
  • Матчмейкинг - автоматический вход в случайную комнату с фолбэком на создание новой (JoinRandomRoom, OnJoinRandomFailed, CreateRoom), лимит 3 игрока, авто-старт раунда при заполнении.
  • Репликация состояния через буферизированные RPC (RpcTarget.AllBufferedViaServer): создание луча, активация станций, передача ключей, изменение энергии буферизуются на сервере, поэтому поздно подключившийся клиент получает корректное состояние мира, а не пустую сцену.
  • Распределенная синхронизация времени: хозяин транслирует UTC-метку старта, каждый клиент локально отсчитывает обратный таймер от общей точки - раунд заканчивается одновременно у всех, без накопления дрейфа.
  • Детерминированная генерация событий: координаты луча и индексы двух активных станций вычисляются хозяином и рассылаются как параметры RPC, гарантируя идентичную геометрию мира на всех устройствах.
  • Соревновательная механика на синхронизированных счетчиках: общий счетчик игроков у луча (beamPlayers) исключает одновременную зарядку - при конфликте процесс зарядки прерывается; кража ключа реализована через raycast по направлению взгляда с обменом владением ключа и штрафом по заряду.
  • Кросс-сценовая передача данных: итоги раунда сериализуются через Json.NET в PlayerPrefs и восстанавливаются на экране результатов с сортировкой по очкам.
  • Мобильный UX: поверх Cinemachine FreeLook реализован собственный слой мультитач-жестов (pinch-zoom камеры с клампингом радиуса орбиты, свайп-орбита), экранные элементы управления автомобилем и динамический мини-радар.

Архитектура и сложности

Структура приложения - три сцены с четким разделением ответственности:
  1. Menu / Launcher - подключение к Photon, ввод никнейма, матчмейкинг.
  2. Main / GameManager - игровой цикл, спавн игроков, управление комнатой.
  3. Finish - таблица результатов.
Ключевые инженерные решения и преодоленные сложности:
  • Консистентность распределенного состояния. Главный риск любого realtime-мультиплеера - расхождение мира между клиентами. Решено переводом всех изменяющих мир событий в буферизированные серверные RPC и централизацией их источника на master-client. Late-join перестал ломать сессию.
  • Гонки состояний в соревновательной логике. Зарядка от луча, кража ключей и завершение игры - операции, которые могут произойти у нескольких игроков одновременно. Введены синхронизированные счетчики и проверки владения, прерывающие конфликтующие процессы вместо их дублирования.
  • Рассинхрон таймеров. Вместо передачи оставшегося времени (накапливает лаг) транслируется единая точка отсчета, а обратный отсчет считается локально - классический и устойчивый паттерн сетевого времени.
  • Интеграция физики автомобиля с сетью. Vehicle-контроллер из Standard Assets обернут в сетевую модель владения (PhotonView.IsMine) с автоматическим торможением при отпускании газа и спавном по высоте террейна (Terrain.SampleHeight).
  • Навигация и мини-карта. Реализовано преобразование мировых координат в координаты радара (RealToMap) с динамическими маркерами игроков, луча и станций и подсветкой носителя ключа.
  • Сервисный доступ к подсистемам через статическую точку входа (Helper.init), упрощающий связность UI, сетевого слоя и игровой логики в рамках компактного кодового объема.

Результат

  • Завершенный сквозной мультиплеерный цикл: матчмейкинг, синхронный раунд, подсчет очков, таблица результатов - без выделенного бэкенда, только на relay-инфраструктуре.
  • Детерминированное состояние мира у всех клиентов, включая поздно подключившихся, - устранены рассинхрон и пустые late-join-сессии.
  • Синхронное завершение раунда на всех устройствах независимо от момента входа и расхождения системных часов.
  • ~12 связанных игровых систем (матчмейкинг, репликация, таймер, зарядка, кража ключей, мини-карта, камера, физика, UI, результаты) в компактной поддерживаемой кодовой базе из ~1000 строк прикладного кода.
  • Оптимизация сетевого трафика: передается не состояние каждого кадра, а только события мира (создание/уничтожение луча, передача ключей, изменения энергии), что минимизирует нагрузку на канал - критично для мобильных сетей.
  • Адаптация под мобильную платформу: альбомная ориентация, мультитач-камера, экранное управление - игра управляема одной рукой на сенсорном экране.

Стек

  • Движок: Unity 2021.3.18 LTS (C#)
  • Сетевой слой: Photon PUN 2 (Realtime, Chat) - матчмейкинг, буферизированные RPC, master-client authority
  • Камера: Cinemachine FreeLook + собственный слой мультитач-жестов
  • Физика/мир: Unity Physics, Terrain, Standard Assets Vehicles
  • UI: TextMesh Pro, UI Toolkit, uGUI; динамический мини-радар
  • Данные: Json.NET (Newtonsoft), PlayerPrefs (кросс-сценовое состояние)
  • Сеть/HTTP: UnityWebRequest, System.Net.Http
  • Платформа: Android (мобильные устройства, альбомная ориентация)
 
Сюда Туда