Вам наверное уже не терпится вставить Вами нарисованную и подготовленную игровую карту на холст в браузере, чтобы полюбоваться своим творением и не нарадоваться красотами своего труда. Но не торопитесь, потерпите, я бы хотел предварительно Вам донести немного теории касательно Tilemap и каким образом их можно загрузить в Вашей программе.
Помните, когда мы создавали карту, она сохранилась в специальном формате с расширением .tmx. Как я уже упоминал, это разновидность xml файла, которая хранит в себе все данные о нашей карте. Давайте взглянем внутрь файла и заметим длинные последовательности кода, состоящей из букв и цифр:
Это информация о слое Platforms в кодировке Base64 (вспомните, мы выбирали тип формата слоёв Base 64 (uncompressed) в предыдущей статье). Найдите ещё следующие фрагменты:
Это данные по коллайдерам с платформой. Коллайдер переводится с английского как столкновение, т.е. из самого названия становится понятным, что, чтобы герой бегал по платформам (по земле), необходимо задать коллайдер этим элементам (земля, земля с травой) и не проваливался под них. Вы спросите - а с какой стати герой будет вообще куда-то проваливаться? И вполне законный вопрос. Забегая вперёд, сразу скажу - в игре задаётся физика с типом arcade и в объекте config глобально для всех добавляемых элементов определяется gravity (гравитация), за счёт которой героя и всех остальных персонажей игры притягивает вниз. Если Вы не добавите информацию о коллайдерах, все объекты с физикой (в других статьях я объясню, что это означает) будут проваливаться вниз до бесконечности, даже за экран. Мы ещё очень подробно вернёмся к этим вопросам, а сейчас давайте рассмотрим загрузку карт.
К сожалению в Phaser 3 не предусмотрено загружать непосредственно карты с расширением .tmx, но есть возможность загружать карты в виде массивов, в CSV формате и наконец в JSON формате. Давайте скрупулёзно рассмотрим каждую альтернативу.
Создание карт из массива
Пусть у нас есть super-mario-tiles.png содержащий все элементы для нашей карты. Предварительно нам необходимо в функции preload, которую мы рассматривали в первой части курса по Phaser 3, загрузить этот tileset следующим образом:
Первый аргумент метода this.load.image это ключ (название), по которому мы можем в будущем обратится к этой картинке, второй аргумент - это путь к файлу с картинкой.
Далее, в функции create (которую мы тоже рассматривали) зададим массив с информацией по карте и сделаем Tilemap:
Я поясню, что означают цифры 0, 1, 2, 3, 4, 5, ... в массиве. Для этого посмотрите на картинку ниже и я думаю, всё станет более, чем понятным:
Это Tileset, каждый блок которого искусственно пронумерован цифрой (естественно, как Вы понимаете в реальном Tileset нет никаких цифр, здесь они добавлены для понимания составления массива). Например самый верхний ряд массива data заполнен нулями, а как видно из Tileset нулю соответствует просто квадратик с голубым фоном, т.е. понятно, что это будет верхний край неба в игре. Далее, во втором ряду встречается последовательность 1, 2, 3 аж два раза. Опять таки, как видно из Tileset - это кусочек облачка из Марио. И так далее. Надеюсь Вы поняли принцип построения карты из данных массива. Кстати, массив получается у нас двухмерный, первый индекс это номер линии на экране (ряда), второй индекс - это номер ячейки с Tile.
Метод this.make.tilemap создаёт объект карты Map, который имеет множество свойств и методов. Он принимает следующие аргументы:
- data - массив с данными для построение карты
- tileWidth - ширина блока в Tileset
- tileHeight - высота блока в Tileset
Затем нам необходимо создать объект tiles из нашего загруженного раннее Tileset. Это делает метод addTilesetImage(key) объекта карты Map. Всё, что необходимо передать в этот метод как параметр - это ключ картинки (помните мы задавали этот ключ, когда загружали tileset с помощью this.load.image).
Эти методы, что мы рассмотрели - лишь подготовка к отрисовки карты, но они не рендерят саму карту. Чтобы отрисовать непосредственно на холсте карту, надо вызвать метод карты Map - createStaticLayer. Приведу описание этого метода из официальной API документации (разумеется в переводе):
createStaticLayer(layerID, tileset [, x] [, y])
- layerId - строка или целое число, задающее название или идентификатор слоя (когда мы будем подключать карту, созданную в Tiled, этот аргумент есть название слоя, которое Вы задавали в программе, например в нашем случае это будет Platforms)
- tileset - объект, который мы создали с помощью метода addTilesetImage (см. выше)
- x - координата X для расположения слоя в игровом мире (опциональный аргумент)
- y - координата Y для расположения слоя в игровом мире (опциональный аргумент)
Ещё есть метод объекта Map - createDynamicLayer, но это рассказ совсем другого курса (возможно в будущем мы изучим и динамические карты, когда будем создавать RPG, например как игра Duna). Вся разница между двумя этими методами в том, что динамические карты можно создавать на лету во время игры, а статические карты - как Вы создали один раз карту в Tiled так она и будет неизменной на все времена и народы. Вспомните игры Sim City, Duna и так далее. Это типичные примеры игр с динамическим принципом построения карт.
Загрузка карт из CSV файла
В Phaser 3 можно загружать карты из CSV файла и делать на их основе игровые миры. Давайте немного вернёмся в программу Tiled, которую мы уже изучили и сконвертируем нашу карту в CSV формат. Когда карта готова, перейдите в меню File => Export As... Выберите из списка Save as Type - CSV files (*.csv).
Теперь надо добавить несколько строк кода и вуаля - карта будет загружена и отрисована у Вас на экране:
Тут всё тоже самое, что мы рассмотрели в предыдущем примере, только добавился метод загрузчика в preload: this.load.tilemapCSV(key, path), который позволяет загружать карты в CSV формате. Сюда передаётся ключ, который потом используется в методе this.make.tilemap, и путь к файлу.
Загрузка карт из JSON файла
И наконец, рассмотрим третий способ загрузки карт в Phaser 3. Это загрузка файла в JSON формате. Точно также, как мы это делали с CSV, предварительно надо экспортировать карту в JSON формате по такому же алгоритму. После чего добавьте следующие строки кода:
Я представил код для нашего проекта и нашей карты, которые я показывал в предыдущей статье. Напоминаю, скачать tileset и tilemap можно по ссылке и иерархия папок и файлов должна быть у Вас ровно точно такая же, как на Яндекс.Диски (всё должно находится у Вас в src/assets).
В этом коде знакомые строки, добавился лишь новый метод загрузчика this.load.tilemapTiledJSON(key, path), что позволяет загрузить карту в JSON формате. Чтобы у себя потренироваться с загрузкой карты в игру, соберу воедино весь код, который мы наполняем в течении всех статей:
Кстати, только сейчас заметил, что я забыл упомянуть о самом главном. А именно инициализация и создание игровой сцены:
Хочу ещё отметить немаловажный момент: сразу договоримся, что мы как будущие серьёзные разработчики игр, будем использовать технологии по последнему слову техники. На Phaser 3 уже прожжённые разработчики игр пишут на ES6, а то уже и седьмая редакция. Предполагается, что Вы хорошо знаете JS и хотя бы ознакомлены с 6-ой редакцией ECMAScript. Таким образом в нашем коде можно даже писать так:
Потому что в ES6, если имя свойства совпадает с именем метода или функции, то можно сокращать до такой записи. Я по ходу дела буду обязательно обращать Ваше внимание на такие мелочи, потому что это важно, если Вы собираетесь стать профессиональными программистами на JS.
Если Вы всё правильно сделали, то Вы должны будете увидеть на экране следующее:
P.S. Как Вы заметили, фон чёрный, потому что мы его ещё не добавляли и нет остальных элементов карты, такие как шипы, в качестве препятствий, воды, главного героя игры и так далее. Всё это предстоит сделать, чем мы и будем заниматься в последующих статьях. Между прочим, обратите внимание, отобразился лишь слой Platforms из карты, ну это и логично, ведь в коде мы написали: this.platforms = map.createStaticLayer('Platforms', tileset, 0, 200);