Pull to refresh

Tiled2Unity: экспорт из Tiled Map Editor в Unity

Reading time 7 min
Views 12K
Созданию простого 2D платформера посвящено немало публикаций на ресурсах для разработчиков игр. В качестве движка часто используют Unity, а для создания карт — Tiled Map Editor. Взаимодействие этих двух сред осуществляется с помощью бесплатной утилиты Tiled2Unity, которая создает из TME файлов префабы в Unity.

Как это работает, расскажем на примере разработки нашего платформера “X-Drums”.

Двигаться будем по следующей схеме:

  1. Настройка экспорта Tiled2Unity
  2. Настройка столкновений в Tiled Map Editor
  3. Настройка параметров, которые поддерживает Tiled2Unity
  4. Настройка пользовательских параметров в Tiled Map Editor

  • Пользовательские параметры для слоев (объектов)
  • Пользовательские параметры для объектов

1. Настройка экспорта


Итак, у нас есть проект в Unity и есть карта, созданная в Tiled Map Editor. Запускаем Unity и импортируем Tiled2Unity.unitypackage.



В Tiled Map Editor вызываем окно редактирования команд:



Добавляем новую команду, в которой прописан путь до исполняемого файла Tiled2Unity.exe. Вместо %mapfile Tiled автоматически подставит путь к файлу карты. Последний аргумент этой команды — это путь к папке Tiled2Unity, которая должна была появиться в проекте после импорта.



Запускаем команду и в появившемся окне нажимаем большую кнопку.



В результате экспорта получаем префаб карты, который находится в папке Tiled2Unity. Размещаем этот префаб на сцене в Unity. Теперь при работе с картой в TME и ее экспорте, префаб и объект на сцене будут изменяться в соответствии с изменениями в TME.



Так мы настроили экспорт карты из Tiled в Unity и создали игровую среду.

Теперь займемся настройкой объектов на нашей карте.

2. Редактор столкновений


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

Запускаем редактор столкновений в Tiled:



Выбираем нужный нам тайл, к примеру, часть барабана, и редактируем полигоны:



Аналогично редактируем другие нужные нам тайлы (пол, стены и т.д.). В результате, при экспорте Tiled2Unity автоматически создаст коллайдеры PolygonCollider2D, которые и будут выступать для героя препятствиями.





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

3. Параметры, которые поддерживает Tiled2Unity


Впрочем есть список параметров, которые мы можем использовать в Tiled без настройки их в Unity, поскольку Tiled2Unity уже сделал это за нас. Среди них:
unity:layer
unity:sortingLayerName
unity:tag
unity:sortingOrder
unity:isTrigger
unity:ignore
The (physics) layer name in Unity
The Name of the Sorting Layer in Unity
The Name of the Tag in Unity
The `sorting in layer` value in Unity
Whether collider is a trigger or not
Ignore layer (or parts of it) during import(value = [false|true|collision|visual])

Зададим нужные нам параметры для барабанных палочек, по которым будет прыгать герой:



При экспорте в Unity получаем такой результат:



Слою задан параметр OneWayPlatform, он используется для объектов, которые являются проницаемыми снизу.



4. Пользовательские параметры в Tiled


Обработку других параметров, назовем их “пользовательскими”, и экспорт объектов с такими параметрами, мы будем настраивать в Unity. Задавать их в Tiled можно как для слоев (объектов), так и для объектов. В разных случаях может быть удобным первый или второй вариант. Рассмотрим, как это реализовать.

4.1. Пользовательские параметры для слоев (объектов)

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

Создаем слой объектов в Tiled и размещаем на нем наши тарелки. Затем, задаем параметр AddObject для всего слоя.



Поле своих параметров для каждой тарелки остается пустым.



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

Напишем код, который при импорте тарелок для каждого объекта из Tiled создаст экземпляр нашего префаба. Для этого создаем скрипт CustomTiledImporterForHiHats с классом, который наследует интерфейс Tiled2Unity.ICustomTiledImporter и атрибутом [Tiled2Unity.CustomTiledImporter].

Этот скрипт Tiled2Unity будет вызывать для каждого импортируемого из Tiled слоя и объекта. А обрабатываться, соответственно, будут те слои или объекты, у которых среди параметров есть параметр AddObject со значением “Hi-hat”.

using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

[Tiled2Unity.CustomTiledImporter]
class CustomTiledImporterForHiHats : Tiled2Unity.ICustomTiledImporter
{
    public void HandleCustomProperties(GameObject gameObject, IDictionary<string, string> props)
    {
        if (!props.ContainsKey("AddObject"))
            return;

        if (props["AddObject"] == "Hi-hat")
        {
            //Загружаем префаб тарелок
            string prefabPath = "Assets/8 - Prefabs/Hi-hat.prefab";
            Object obj = AssetDatabase.LoadAssetAtPath(prefabPath, typeof(GameObject));
            if (obj == null)
                return;

            //Для каждого тайла, который будет загружен из Tiled, 
            //будет создан экземпляр префаба
            //Сами тайлы будут удалены со сцены
            List<GameObject> childrenToDestroy = new List<GameObject>();
            //Проходим по списку объектов слоя
            foreach (Transform child in gameObject.transform)
            {
                if (child.name == "TileObject")
                {
                    //Добавляем тайл для последующего удаления
                    childrenToDestroy.Add(child.gameObject); 

                    //Создаем экземпляр префаба, настраиваем его положение на сцене
                    GameObject objInstance = (GameObject)GameObject.Instantiate(obj);
                    objInstance.name = obj.name;
                    objInstance.transform.parent = gameObject.transform;
                    objInstance.transform.position = child.transform.position;
                }
            }
            //Удаляем тайлы со сцены
            childrenToDestroy.ForEach(child => GameObject.DestroyImmediate(child));   
        }
    }

    public void CustomizePrefab(GameObject prefab)
    {
    }
}


Скрипт готов, и мы можем экспортировать тарелки.



И вот так герой взаимодействует с ними.



Экспорт нот настроен точно так же как экспорт тарелок. Единственное отличие в том, что в игре есть несколько видов нот с разной стоимостью в зависимости от цвета. Поэтому для каждого типа нот со своим номиналом мы создали префаб в Unity и слой объектов в Tiled, указав ему в параметре AddObject тип ноты. Скрипт импорта, создающий экземпляры префабов, идентичен скрипту тарелок.

4.2. Пользовательские параметры для объектов

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

К примеру, фанатки различаются по цвету, они двигаются с разной скоростью на задаваемое расстояние. Они могут останавливаться, чтобы моргнуть, а при встрече с героем на выбор выдают определенные эмоций. Задаем эти параметры в Tiled для каждого объекта. “Свои параметры” для слоя, соответственно, остаются пустыми.



В Unity для фанаток созданы префабы, к которым присоединен скрипт GirlController, определяющий их поведение и реакцию на героя. Импорт будет аналогичен импорту тарелок, но просто создать экземпляры префаба в этом случае будет недостаточно. Нам нужно обратиться к скрипту GirlController и установить свойства, которые были заданы в Tiled индивидуально для каждой фанатки.

using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

[Tiled2Unity.CustomTiledImporter]
class CustomTiledImporterForGirls : Tiled2Unity.ICustomTiledImporter
{
    public void HandleCustomProperties(GameObject gameObject, IDictionary<string, string> props)
    {
        if (!props.ContainsKey("GirlColor"))
            return;

        //Загружаем нужный префаб в зависимости от указанного в Tiled цвета
        string prefabPath = "Assets/8 - Prefabs/Girls/Girl_" + props["GirlColor"] + ".prefab";
        Object obj = AssetDatabase.LoadAssetAtPath(prefabPath, typeof(GameObject));

        //Создаем экземпляр префаба, настраиваем его положение на сцене
        GameObject objInstance = (GameObject)Object.Instantiate(obj);
        objInstance.name = obj.name;
        objInstance.transform.parent = gameObject.transform.parent;
        objInstance.transform.position = gameObject.transform.position;
        objInstance.transform.localScale = gameObject.transform.localScale;
        objInstance.transform.eulerAngles = gameObject.transform.eulerAngles;

        //Обращаемся к скрипту, который определяет поведение фанатки
        //Считываем параметры из Tiled и присваиваем переменным скрипта
        var girlController = objInstance.GetComponent<GirlController>();
        if (props.ContainsKey("OffsetRight"))
            float.TryParse(props["OffsetRight"], out girlController.OffsetMax);
        if (props.ContainsKey("OffsetLeft"))
            float.TryParse(props["OffsetLeft"], out girlController.OffsetMin);
        if (props.ContainsKey("Velocity"))
            float.TryParse(props["Velocity"], out girlController.Velocity);
        if (props.ContainsKey("Stop"))
            float.TryParse(props["Stop"], out girlController.StopCount);
        if (props.ContainsKey("Fatal"))
            bool.TryParse(props["Fatal"], out girlController.Fatal);
        if (props.ContainsKey("HeartType"))
        {
            string heartPrefabPath = "Assets/8 - Prefabs/Girls/" + props["HeartType"] + ".prefab";
            Object heartObj = AssetDatabase.LoadAssetAtPath(heartPrefabPath, typeof(GameObject));
            girlController.heartPrefab = heartObj;
        }

        //Удаляем тайл со сцены
        Object.DestroyImmediate(gameObject);
    }

    public void CustomizePrefab(GameObject prefab)
    {
    }
}

Выполняем экспорт в Unity и видим, что параметры, указанные в Tiled, были установлены переменным скрипта GirlController:





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

Описанный подход был использован нами для создания нашего платформера. Работа в связке Tiled Map Editor и Unity, именно в этой игре, ускорила процесс ее создания, позволив одновременно работать дизайнеру уровня в TME и программисту в Unity, не мешая друг другу. В проектах, подобных нашему, утилита Tiled2Unity может оказаться невероятно полезной, и, опираясь на статью, желающие могут применить любой из вариантов в своих игровых разработках.
Tags:
Hubs:
+14
Comments 1
Comments Comments 1

Articles