Когда сервер считает мир сам, клиент перестаёт быть игрой и становится витриной: он показывает состояние и отправляет команды, но ничего не решает. Звучит просто — до первого списка того, что такой клиент обязан уметь.

Что должен уметь клиент

Раз сервер авторитарный, на клиента ложится вот что:

  • интерфейс UI с разнообразными меню и кнопочками, джойстиком

  • клиентскую часть подключения к серверу по протоколу websocket (о котором я писал ранее) для отправки команд и получения ответа во время игры

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

  • из желательного было так же поддержка тайловых карт из коробки

Начинал с 2D и с прицелом на 3D в будущем. С игровыми движками я до этого не работал, поэтому взял самый распространённый — Unity: подробная документация, в том числе на русском, много обучающих видео, C# для кода и готовый инструментарий для сцен, анимации, карт и камеры.

главная страница сайта https://unity.com/ru,
главная страница сайта https://unity.com/ru,

Порядок оказался обратным

Хотелось бы сказать, что сначала я сделал API и документацию, а потом клиент. На деле было наоборот: я не понимал, чего ждать, десятки раз переделывал и клиент, и сервер — не устраивала то архитектура, то скорость. Так ушло около четырёх месяцев, прежде чем появилась первая рабочая версия API и первые примеры добавления механик через веб-панель.

Схема работала так: создаёшь метод API, описываешь его код на Lua, JavaScript или PHP во встроенном редакторе, делаешь публичным — и вызываешь с клиента. Демонстрационный метод добавлял на карту гоблина.

гоблин добавляется на сервере и в клиенте в режиме online по вызову метода API
гоблин добавляется на сервере и в клиенте в режиме online по вызову метода API

Заодно понадобился отладчик запросов к API — свой аналог привычных инструментов, но внутри админ-панели. А поскольку Unity собирает игру и под браузер, рядом с запросом стало видно и то, что происходит в самой игре:

панель загрузки браузерной версии игры Unity
панель загрузки браузерной версии игры Unity
пример отладочной панели с игрой на webgl unity
пример отладочной панели с игрой на webgl unity

Как устроен клиент

Дальше код клиента пришлось приводить в порядок и оформлять плагином. Требования к нему я записал так:

  • Код должен представлять собой плагин для Unity и содержать функционал приемки и отправки пакетов.

  • Структура кода игры должна повторять структуру плагина расширяя его классы дополнительным функционалом.

  • Использовать ООП (объектно‑ориентированный подход) т. к. я уже привык с ним работать в PHP (хотя бы постараться его применять в коде игры).

  • Для описания запросов к серверу и ответов использовать «структуры» (позже из за проблем с кодированием и декодирования json struct пришлось переделать в обычные классы но их назначение осталось прежним).

  • На каждом «префабе» в Unity (то есть на любом игровом объекте с которым можно взаимодействовать) должен быть «повешен» фаил — класс который принимает от главного контроллера пакетов пакет именно этого префаба и обновляет данные (например изменение позиции, жизней, маны, запуск новой анимации и т. д).

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

  • Поддержка функционала бесшовного мира сервера и переход между локациями.

  • В проекте должно быть 2 сцены (сцена авторизации/регистрации и пустая сцена, где на лету меняется карта и префабы на ней).

  • Readme к папкам и файлам проекта.

Клиентская часть лежит в открытом доступе. Как устроен проект, видно по структуре папок и readme:

пример фала readme клиентской части онлайн игры
пример фала readme клиентской части онлайн игры

Для тех, кому интересна именно связка Unity с серверным API, я разобрал устройство плагина в отдельном плейлисте — хотя при разработке игры залезать в него не требуется.

Что было дальше

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

Как это выглядит в игре, показываю на канале проекта: youtube.com/@mmogick_ru.

Если вы делали клиент к своему серверу — расскажите, что оказалось самым неприятным: сеть, ввод или сборка под разные платформы.

История:

  1. Введение

  2. Масштабируемость и асинхронность

  3. WebSocket

  4. Redis

  5. LUA и JavaScript

  6. Выбор технологий, протокола и архитектурный шаблон Entity Component System

  7. Игровые локации (тайловые карты)

  8. Клиентская часть на Unity

  9. Игровые серверные механики

  10. Открытый бесшовный мир в 2D игре

  11. FPS, Ping, паузы между командами, интерполяция и экстраполяция

  12. Очереди и параллельное программирование на CPU

  13. Event-driven паттерн, JSON-RPC и почему не сервисная (SOA) архитектура

  14. Сетевая карта и задержка кадра (Latency frame) по RFC 2544 (1242)

  15. Создание сервера для онлайн ММО игр на PHP

  16. Готовое MVP сервиса 2D MMO RPG игр (realtime)

  17. Внедряю ИИ: механики из одного описания

  18. Конвейер контента для MMO: импорт анимации, экипировка и обновление игры без патчей

  19. Каталог ассетов и git: как командой вести игру в облаке

  20. Тесты для кода, который пишет ИИ: контракты вместо ассертов