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

Чем рисовать карты

Для демонстрационной игры я взял самый простой вариант — тайловые карты. Готовый редактор для них есть: Tiled. Он умеет изометрию, гексагональную сетку и обычную ортогональную.

изометрические карты
изометрические карты
гексогональные карты
гексогональные карты
ортогональные карты
ортогональные карты

Главное, что он выгружает всё в XML: непроходимые области, объекты, анимацию, плюс инструменты автоподстановки тайлов по заданному правилу. Так выглядит сам файл:

пример xml фаила
	<?xml version="1.0" encoding="UTF-8"?>
	<map version="1.5" tiledversion="1.7.1" orientation="orthogonal" renderorder="right-down" width="100" height="100" tilewidth="32" tileheight="32" infinite="0" nextlayerid="5" nextobjectid="4">
	 <tileset firstgid="1" name="tmw_desert_spacing" tilewidth="32" tileheight="32" spacing="1" margin="1" tilecount="48" columns="8">
	  <image source="tmw_desert_spacing.png" trans="4affea" width="265" height="199"/>
	 </tileset>
	 <tileset firstgid="49" name="tmw_desert_spacing2" tilewidth="32" tileheight="32" spacing="1" margin="1" tilecount="48" columns="8">
	  <image source="tmw_desert_spacing.png" trans="4affea" width="265" height="199"/>
	  <tile id="0">
	   <objectgroup draworder="index" id="2">
		<object id="1" x="5.76013" y="7.63843" width="16.2786" height="16.9047"/>
	   </objectgroup>
	  </tile>
	 </tileset>
	 <layer id="1" name="Слой тайлов 1" width="100" height="100">
	  <data encoding="csv">
		...
	 </data>
	 </layer>
	 <objectgroup id="3" name="Слой объектов 1">
	  <object id="1" gid="3221225473" x="105.5" y="66.5" width="32" height="32" rotation="90"/>
	  <object id="2" gid="3221225503" x="204.639" y="72.6027" width="58.5" height="41" rotation="324.844"/>
	 </objectgroup>
	</map>

Как этот файл попадает в базу

Под загрузку таких файлов я сделал веб-приложение на PHP.

Веб-приложение для загрузки карт
веб-приложение для загрузки карт

Каждый элемент карты — это класс PHP со своими атрибутами и вложенными сущностями, а в базе им отвечают одноимённые таблицы и поля.

корневая сущность - карта
корневая сущность - карта
вложенная в карту сущность - слой карты
вложенная в карту сущность - слой карты

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

(new Tiled\Xml\Map($id))->parse(file_get_contents('1.tmx'))->save();	

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

А вот собирать из этих данных картинку через GD оказалось плохой идеей: PHP съедает на этом непозволительно много памяти.

Чего тогда не хватало

Хотелось браузерный аналог Tiled: править карты прямо в приложении и выгружать обратно. Похожие проекты в сети есть:

https://victorribeiro.com/tileEditor/?example=01
https://blurymind.github.io/tilemap-editor/

Любопытная деталь: сам Tiled вырос из разработки открытой игры The Mana World — её карты загрузились в приложение без правок.

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

Браузерный редактор карт в итоге появился: карты правятся в админке, а импорт из Tiled принимает архив целиком — вместе с тайлсетами и графикой. Карты The Mana World, с которых всё начиналось, теперь живут в открытом бесшовном мире и стыкуются краями друг с другом.

Как это выглядит в игре, показываю на канале проекта: 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. Тесты для кода, который пишет ИИ: контракты вместо ассертов