Карты тайлов

libGDX предоставляет общий API для карт. Все классы для работы с картами можно найти в com.badlogic.gdx.maps (исходный код) пакете. В корне пакета содержатся базовые классы, дочерние пакеты содержат специализированные реализации для карт тайлов и других форм карт.

Базовые классы

Набор базовых классов предназначен быть общим, чтобы мы имели поддержку не только карт тайлов, но любых форматов 2D карт.

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

Свойства

Свойства карт, слоев и объектов представлены классом MapProperties (исходный код). Данный класс является по существу хэш-картой со строковыми ключами и произвольными значениями.

Доступность пар ключ/значение для карты, слоя или объекта зависит от формата, из которого они были загружены. Для доступа к свойствам, вы можете просто сделать следующее:

map.getProperties().get("custom-property", String.class);
layer.getProperties().get("another-property", Float.class);
object.getProperties().get("foo", Boolean.class);

Многие из поддерживаемых редакторов позволяют определить свойства для карт, слоев и объектов. Конкретный тип свойств определяется форматом. Если вы сомневаетесь, загрузите в libGDX приложение вашу карту с помощью загрузчиков карт и проверьте свойства интересующих вас объектов.

Слои карты

Слои в карте упорядочены и проиндексированы, начальный индекс равен нулю. Вы можете получить доступ к слоям карты используя индекс:

MapLayer layer = map.getLayers().get(0);

Также вы можете получить слой по его имени:

MapLayer layer = map.getLayers().get("my-layer");

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

TiledMapTileLayer tiledLayer = (TiledMapTileLayer)map.getLayers().get(0);

Слой имеет несколько атрибутов для каждого поддерживаемого формата:

String name = layer.getName();
float opacity = layer.getOpacity();
boolean isVisible = layer.isVisible();

Вы можете изменять эти атрибуты, тем самым влиять на визуализацию слоя.

В дополнение к этим атрибутам, вы также можете получить доступ к более общим свойствам, как описано выше.

Чтобы получить объекты в слои используйте метод getObjects():

MapObjects objects = layer.getObjects();

Экземпляр MapObjects (исходный код) позволяет извлекать объекты по названию, индексу или типу. Вы также можете вставлять и удалять объекты во время выполнения libGDX приложения.

Объекты карт

libGDX API уже предоставляет несколько специализированных объектов карт, например CircleMapObject (исходный код), PolygonMapObject (исходный код) и так далее.

Загрузчик формата карты будет анализировать данные объекты, и размещать их в соответствующих MapLayer (исходный код) слоях.

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

String name = object.getName();
float opacity = object.getOpacity();
boolean isVisible = object.isVisible();
Color color = object.getColor();

Специальные объекты карт, такие как PolygonMapObject, могут иметь дополнительные атрибуты:

Polygon poly = polyObject.getPolygon();

Изменение любого из этих атрибутов может повлиять на визуализацию объекта.

Как в случае с картами и слоями, можно получить доступ к более общим свойствам, как описано выше.

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

Тайлы принадлежащие карте хранятся не как объекты. Существуют специальные реализации, которые хранят объекты такого типа более эффективно, смотрите ниже.

Визуализация карты

Интерфейс MapRenderer (исходный код) описывает методы позволяющие визуализировать слои и объекты карты.

Перед началом визуализации вы должны установить вид просмотра карты. Думайте о виде просмотра как об окне, через которое вы смотрите на мир игры. Самый простой способ установки вида просмотра, для визуализатора карты, является использование OrthographicCamera:

mapRenderer.setView(camera);

Кроме того, можно указать вручную матрицу проекции и границы вида просмотра:

mapRenderer.setView(projectionMatrix, startX, startY, endX, endY);

Границы вида просмотра представляются в X/Y плоскости, где ось Y направлена вверх. Используемые единицы измерения определяются картой и форматом, из которого она была загружена.

Для визуализации всех слоев карты вызовите метод render():

mapRenderer.render();

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

int[] backgroundLayers = { 0, 1 }; // не выделяйте память при каждом кадре!
int[] foregroundLayers = { 2 };    // не выделяйте память при каждом кадре!
mapRenderer.render(backgroundLayers);
renderMyCustomSprites();
mapRenderer.render(foregroundLayers);

Вы можете достичь эффекта параллакса, путем отдельной визуализации и модификации вида для каждого слоя.

Карты тайлов

Карты, которые содержат слои и тайлы обрабатываются классами, находящимися в com.badlogic.gdx.maps.tiled пакете. Пакет содержит загрузчики для разных форматов.

Карты тайлов загружаются в экземпляры TiledMap (исходный код) класса. TiledMap является подклассом общего Map класса с дополнительными атрибутами и методами.

Слои карты тайлов

Слои с тайлами хранятся в экземплярах TiledMapTileLayer (исходный код) класса. Чтобы получить доступ к тайлам, вам придется приводить тип:

TiledMap tiledMap = loadMap(); // смотрите ниж
// предположим, что слой по этому индексу содержит тайлы.
TiledMapTileLayer layer = (TiledMapTileLayer)tiledMap.getLayers().get(0);

Класс TiledMapTileLayer имеет все те же атрибуты, что и общий MapLayer класс, свойства, объекты и так далее.

В дополнение к этому, TiledMapTileLayer имеет двумерный массив из TiledMapTileLayer.Cell (исходный код) экземпляров.

Чтобы получить доступ к клетке, используйте getCell() метод слоя тайлов:

Cell cell = tileLayer.getCell(column, row);

Индексы строки и столбца указывают местоположение клетки. Тайлы должны быть в системе координат, где ось Y направлена вверх. Таким образом, нижний левый тайл карты будет расположен в точке (0,0), а верхний правый тайл в точке (tileLayer.getWidth()-1, tileLayer.getHeight()-1).

Если тайла в данной позиции не существует или индексы строки/столбца выходят за границы, то метод вернет null.

Вы можете запросить количество тайлов в слое по горизонтали и вертикали:

int columns = tileLayer.getWidth ();
int rows = tileLayer.getHeight ();

Тайлы и наборы тайлов

TiledMap содержит один или более экземпляров TiledMapTileSet (исходный код) класса. Набор тайлов содержит число экземпляров TiledMapTile (исходный код) класса. Существует множество реализаций тайлов, например, статические тайлы, анимационные тайлы и так далее. Вы также можете создать собственную реализацию для специальных целей.

Клетки в слое тайлов ссылаются на эти тайлы. Клетки внутри слоя могут ссылаться на тайлы нескольких наборов тайлов. Однако, для слоя рекомендуется использовать один набор тайлов, чтобы уменьшить количество переключений текстур.

Визуализация карт тайлов

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

Создание визуализации выглядит следующим образом:

float unitScale = 1 / 16f;
OrthogonalTiledMapRenderer renderer = new OrthogonalTiledMapRenderer(map, unitScale);

Визуализатор будет способен всегда визуализировать только ту карту, которую передали ему в конструкторе. Данная связанность позволяет визуализатору выполнить оптимизацию для конкретной карты и кэшировать ее.

Единица масштабирования unitScale говорит визуализатору сколько пикселей соответствует одной единице измерения мира. В приведенном выше случае, 16 пикселей будут равны одной единице. Если вы ходите, чтобы пиксель соответствовал одной единице, то переменная unitScale должна быть равной единице.

Единица масштабирования является способом связи системы координат визуализации и логической или мировой системы координат.

Небольшой пример: предположим, у нас есть карта тайлов, где тайлы размером 32x32 пикселей. В вашем логическом представлении мира, мы хотим сопоставить это с квадратами в 1x1 единиц. Мы указали бы единицу масштабирования как 1/32f. Теперь мы можем настроить камеру так, чтобы работать в таких же единицах масштабирования. Допустим, мы хотим видеть на экране 30x20 тайлов карты, тогда мы можем создать следующею камеру:

OrthographicCamera camera = new OrthographicCamera();
camera.setToOrtho(30, 20);

Работа с изометрической картой аналогична, просто создайте экземпляр IsometricTiledMapRenderer класса:

renderer = new IsometricTiledMapRenderer(isoMap, 1 / 32f);

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

Изометрический визуализатор на мобильных устройствах

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

Загрузка TMX/Tiled карт

Tiled – это редактор карт для Windows, Linux и Mac OS X, которые позволяет создавать слои тайлов и слои объектов, содержащие произвольные фигуры для триггеров в областях и других целей. libGDX предоставляет загрузчик для чтения файлов, созданных с помощью Tiled редактора.

У вас есть для варианта загрузки Tiled карты: загрузить карту напрямую или через AssetManager. Первый вариант работает следующим образом:

TiledMap map = new TmxMapLoader().load("level1.tmx");

Данных фрагмент кода загрузит файл с именем level1.tmx из внутреннего хранилища файлов (assets директория). Если вы хотите загрузить файл, используя другой тип файла, вы должны передать FileHandleResolver в конструктор TmxMapLoader.

TiledMap map = new TmxMapLoader(new ExternalFileHandleResolver()).load("level1.tmx");

Мы выбрали этот механизм, так как TmxMapLoader может быть использован вместе с AssetManager классом, где многим управляет FileHandleResolvers. Чтобы загрузить TMX карту с помощью AssetManager, вы можете сделать следующее:

// необходимо только один раз
assetManager.setLoader(TiledMap.class, new TmxMapLoader(new InternalFileHandleResolver()));
assetManager.load("level1.tmx", TiledMap.class);

// когда AssetManager закончил загрузку
TiledMap map = assetManager.get("level1.tmx");

После загрузки вы можете обращаться к карте, так же как и к TiledMap.

Высвобождение ресурсов TMX карты

Если вы загружаете TMX карту непосредственно, то вы становитесь ответственными за вызов TiledMap#dispose() метода, когда она вам больше не нужна. Данный вызов метода высвободит текстуры, загруженные для карты.

TMX карты и GWT

Если вы хотите использовать TMX карты с GWT бекэндом, то вы должны убедиться, что карта храниться в чистой base64 кодировке. Сжатые TMX форматы не будут работать в связи с ограничениями в GWT.

Загрузка Tide карт

Tide является редактором, в основном нацеленным для работы с картой тайлов, доступен только для Windows платформы. libGDX предоставляет загрузчик карт для формата Tide.

Как для TMX файлов, вы можете загрузить Tide карту непосредственно или через assetManager.

// непосредственная загрузка
map = new TideMapLoader().load("level1.tide");
// загрузка через assetManager
assetManager.setLoader(TiledMap.class, new TideMapLoader(new InternalFileHandleResolver()));
assetManager.load("level1.tide", TiledMap.class);
Высвобождение ресурсов Tide карты

Если вы загружаете Tide карту непосредственно, то вы несете ответственность за вызов TiledMap#dispose() метода, когда она вам больше не нужна. Данный вызов метода высвободит текстуры, загруженные для карты.

Производительность

Существует несколько вещей, которые вы можете учитывать для повышения производительности.

  • Используйте тайлы в слои только из одного набора тайлов. Это позволит уменьшить количество текстурных привязок.
  • Помечайте тайлы, которые не нуждаются в смешивании из-за непрозрачности. На данный момент вы можете сделать это только программно, мы в будущем предоставим способы сделать это в редакторе или автоматически.
  • Не переусердствуйте с количеством слоев.

Примеры