Как стать автором
Обновить

Создание сервера для онлайн ММО игр на PHP ч. 10 — Открытый бесшовный мир в 2D игре

Уровень сложности Простой
Время на прочтение 4 мин
Количество просмотров 4.3K

В этот раз я расскажу как удалось реализовать открытый бесшовный мир в горизонтально масштабируемой 2D онлайн игре.

О проекте

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

Это Российская разработка — аналог западных сервисов таких как Firebase, Photon, PlayFab, Mirror, RakNet, AWS GameLift (во всяком случае так мне ответила нейросеть ChatGPT).

Открытый мир

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

край локации игры Fallout справа внизу
край локации игры Fallout справа внизу

Бесшовный мир

мы видим соседние загруженные игровые локации
мы видим соседние загруженные игровые локации

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

Моя реализация для 2D онлайн игры

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

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

Сразу появилась проблемы — сервер после перезагрузки подымается только если на нем кто то играет (пришлось реализовать внутреннее api для самих серверов который проверяет статус другого, перезагружает, останавливает и запускает выбранную сервер‑локацию), а так же проблема согласованности кто с кем должен соединятся тк соседние локации так же хотят соединится с нами образуя некую сеть (временным решением стало то, что тот сервер у которого сумма цифр в IP выше — тот и должен инициализировать соединение, а в случае если на одном физическом сервере несколько локаций — в дополнении проверим порт тк локации работают на разных портах в рамках одного физического сервера).

Приоритетный сервер подымает локацию и инициирует соединение websocket с ней
Приоритетный сервер подымает локацию и инициирует соединение websocket с ней
Соседняя локация на которой никого нет поднялась и приняла запрос на соединение с приоритетным сервером (где авторизовался игрок)
Соседняя локация на которой никого нет поднялась и приняла запрос на соединение с приоритетным сервером (где авторизовался игрок)

Наш сервер где мы играем получает пакеты от соседних локаций что там происходит (тем сам обладает пониманием кто там есть) и уже ретранслирует всем клиентам игрокам, а так же рассылает пакеты соседним локациям что происходит у него.

Граница нескольких сервер-локаций
Граница нескольких сервер-локаций

Осталось реализовать функционал перехода между серверами (они могут быть физически разными машинами). Идея следующая:

  • Игрок отправляет на сервер команду на выход

  • Сервер сохраняет игрока в бд

  • Сервер убирает из массива существ находящихся на нем игрока, рассылаем всем команду что игрок удаляется с сервера

  • Клиенты получают команду что игрок отключается, ждут пару секунд и убирают со сцены данный «прафаб» (в Unity игровые сущности называются префабами)

  • Если за те пару секунд что клиенты ждут удаление префаба он появился в другой сервер локации — мы анимируем плавный переход границы

В самой панели разработчика клиентской части (в настоящий момент использую Unity) локации и находящиеся в них существа (префабы) выглядят следующим образом.

Группа слоев Map — содержит графику текущей (center) локации и соседней (left)
Группа слоев Map — содержит графику текущей (center) локации и соседней (left)
Группа слоев World — содержит прафабы текущей (center) локации и соседней (left)
Группа слоев World — содержит прафабы текущей (center) локации и соседней (left)

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

Если вам интересно следить за реализацией проекта (адрес my‑fantasy.ru) — вы можете подписаться на меня и быть в курсе выхода новых статей.

Теги:
Хабы:
+9
Комментарии 13
Комментарии Комментарии 13

Публикации

Истории

Работа

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн