[Перевод] Введение в новую систему тайловых карт Unity

c9467ef7c3ac69be35fea0375965760d.png


Знакомство с систему двухмерных тайловых карт Unity даёт отличную возможность экономии времени инди-разработчиков и игровых студий на прототипирование и создание качественных 2D-игр.

Без этой системы можно потратить дни, если не недели на написание собственной системы тайловых карт или переработку чужой. И это только программирование, а как насчёт редактора тайловых карт?

Новая система бесплатна и встроена непосредственно в редактор Unity. Она предоставляет множество возможностей, которые мы рассмотрим в этом туториале.

В этой статье мы воспользуемся простой тайловой 2D-игрой, чтобы узнать следующее:

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


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

Примечание: в этом туториале подразумевается, что вы хорошо умеете работать в редакторе Unity. Если вы считаете, что недостаточно в нём освоились, то в туториале Introduction to Unity есть всё необходимое для изучения этого туториала. Кроме того, вам необходима версия Unity 2017.3 или выше.


Что такое тайловая игра?


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

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

Как можно увидеть в этом туториале, обычно тайлы являются квадратами. Но они могут принимать и другую форму — прямоугольники, параллелограммы или шестигранники. В играх обычно используется вид сверху или сбоку, но иногда в тайловых играх применяется и 2.5D.

Возможно, вам уже известны две самые популярные игры, в которых используется система тайловых карт: Starbound и Terraria.

aac4288ee7c7868202364a050a82e34a.png


650d2ddb41661d2b4ae2b948fccee019.png


Приступаем к работе


Скачайте материалы проекта для этого туториала и распакуйте файл .zip.

Запустите редактор Unity и загрузите проект Rayzor-starter из распакованных материалов проекта.

Вот, с чем вы будете работать в этом проекте:

2e3ae3784a7e0cda552c51902367eb8a.png


  • Cinemachine/Gizmos: Unity Cinemachine добавлен только для реализации простой в использовании камеры, следующей за игроком.
  • Palettes: в этой папке мы будем хранить собственные палитры тайлов.
  • Prefabs: несколько заранее созданных заготовок-префабов, которые мы позже используем в игре.
  • Scenes: здесь мы будем открывать и сохранять сцены.
  • Scripts: несколько простых скриптов для управления движением игрока, логики коллизии ловушек и победы/проигрыша в игре. Также в этой папке содержатся скрипты Unity Tilemap из Github-репозитория Unity 2D Extras, которые мы применим позже.
  • Sfx: звуки для игры.
  • Sprites: 2D-спрайты, из которых мы будем создавать палитры тайлов. Они взяты из пака пещер и подземелий для roguelike. Автор пака kenney.nl.


Создание игры


Откройте сцену Game из папки Scenes.

Нажмите на кнопку Play в редакторе, чтобы запустить игру. В окне Game перемещайте героя клавишами WASD или «стрелками».

GIF
20e1a18a8e44d9eeef984cb19e43527e.gif


Пока герой бродит по кажущемуся бесконечным фону камеры с цветом #00000, потерявшись в пустоте.

Чтобы исправить это, нам потребуются инструменты 2D-тайлов для построения интересных уровней и механик игры.

Знакомимся с палитрой тайлов


В редакторе нажмите Window → Tile Palette, чтобы открыть окно 2D Tile Palette.

e9c4c46814518dadf262f42ceab70563.png


Это окно станет вашим лучшим другом при работе над тайловыми играми в Unity.

  1. Этот ряд значков предоставляет основные инструменты манипуляций тайлами, рисования и удаления
  2. Этот селектор позволяет создавать разные палитры, которые можно воспринимать как палитры для рисования, в которых мы располагаем «цвета», а в этом случае — тайлы.
  3. Этот селектор позволяет создавать кисти с различными поведениями. Можно добавлять собственные кисти, поведение которых отличается от кисти по умолчанию (например, рисующую тайлы-префабы с дополнительным функционалом)


Нажмите на Create New Palette и назовите палитру RoguelikeCave. Опции сетки и ячеек не изменяйте.

ab3a35339e71da7a385d6c778abd4f7d.png


Нажмите на Create и выберите сохранение новой палитры в папке Assets\Palettes проекта. В ней создайте новую папку RoguelikeCave.

Теперь структура папок вашего проекта должна выглядеть так:

36208733a60c0a788173c9cb199a1423.png


В окне редактора Tile palette должна быть выбрана RoguelikeCave; на этом этапе у нас всё ещё нет никаких тайлов:

9f80f3e894a6a3d64c3f9951b03046e5.png


Как художник может творить свои шедевры, если у него нет материалов?

Не закрывая окно Tile Palette, выберите папку проекта Sprites/roguelike-cave-pack и разверните ассет roguelikeDungeon transparent.png. Затем выделите все спрайты в этом листе спрайтов: выберите первый спрайт, зажмите shift и выберите последний спрайт.

Перетащите все выбранные спрайты в окно Tile Palette RoguelikeCave:

GIF
055d5baae6a8c222f66f0fec36824e05.gif


Перетащив спрайты в окно Tile Palette, выберите в Unity место для хранения ассетов.

Создайте в Assets/Palettes/RoguelikeCave новую папку Tiles и выберите эту папку в качестве места хранения:

16f6093279a3a3b3c5c728ebdcd07afd.png


Unity сгенерирует тайловый ассет для каждого спрайта, добавленного из листа спрайтов. Дождитесь завершения процесса, затем увеличьте размер окна Tile Palette и полюбуйтесь на ровные ряды красивых новых тайлов, расположившихся в палитре RoguelikeCave:

27dc87f368115a032b42d4b8058bdd1d.png


Повторите описанный выше процесс для создания палитры тайлов с помощью окна Tile Palette, но на этот раз назовите новую палитру RoguelikeCustom.

Поместите новую палитру в новую папку. Назовите папку RoguelikeCustom и переместите её в папку Assets/Palettes проекта.

На этот раз, воспользовавшись описанным выше процессом, используйте спрайты из листа Assets/Sprites/roguelike-custom/roguelike-normal-cutdown-sheet.png для заполнения тайлами новой палитры. Создайте внутри папки палитры RoguelikeCustom папку Tiles и переместите ассеты тайлов туда:

402c0dfb6ca659f755ba63cafa6c288b.png


Порадуйтесь за себя, теперь вам известна магия создания тайловой палитры!

782ed3b0f5bc2546c2116c07f9652f7f.png


Создание сетки карты тайлов


Откройте меню GameObject в верхней части редактора Unity (или панель меню Unity, если вы работаете под MacOS), нажмите на 2D Object, а затем Tilemap, чтобы создать новую сетку Tilemap:

25999de4efb34557bac40669f988fcdd.png


Вы должны увидеть, что в иерархию сцены добавился новый GameObject Grid. Разверните его и выберите встроенный GameObject Tilemap.

Воспринимайте этот объект Tilemap как слой (возможно, один из многих) вашей игры. Можно добавить новые объекты для создания дополнительных слоёв Tilemap.

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

1a0f583faa33dfc44002dde103c8d97e.png


  • Компонент Tilemap используется движком Unity для хранения спрайтов в схеме, помеченной компонентом Grid — в нашем случае это GameObject Grid. При первом создании Tilemap не стоит особо беспокоиться о всех технических особенностях того, как Unity связи между всеми этими компонентами.
  • Tilemap Renderer назначает материал, который будет использоваться для рендеринга тайлов в Tilemap. Также он позволяет настроить свойства сортировки этого слоя Tilemap.


Переименуйте GameObject Tilemap в BaseLayer.

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


Переключитесь в редакторе на режим Scene.

Не закрывая окно Tile Palette, выберите палитру RoguelikeCave, а затем выберите инструмент brush (или нажмите B). Выберите тайл песка, как показано ниже:

dcd44ccb47904a96bcae52075ea37e3e.png


В окне Scene переместите курсор на сетку рядом с игроком. Кисть с тайлом песка будет привязываться к сетке.

Зажав и удерживая левую клавишу мыши, нарисуйте вокруг игрока прямоугольную область. Она будет отрисована на слое Tilemap BaseLayer:

GIF
3c56d606885a624960d5ed83106893dd.gif


Рисование больших областей может оказаться монотонным занятием, поэтому существует кисть Filled Box, которую можно использовать для закрашивания крупных площадей. В окне Tile Palette нажмите на квадратный значок кисти (или нажмите U).

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

GIF
85df5f35c7f37f325e814568d970553f.gif


Хотя мы добавили в игру немного цвета, это песчаное подземелье выглядит уныло. Настало время добавить немного деталей!

Используйте опцию меню GameObject → 2D Object → Tilemap для создания нового слоя Tilemap. На этот раз это будет единственный созданный в иерархии объект, потому что у нас уже есть подходящая Grid. Переименуйте этот слой в DungeonFloorDecoration:

0744a8b330652fe6f4ba7b3939d987ec.png


В окне Tile Palette переключите Active Tilemap на слой DungeonFloorDecoration:

272dc387cdf5f84261eebf6da3dde2a9.png


Выберите инструмент brush (B), затем нарисуйте в окне Scene разбросанные на карте объекты:

bbb4ddf6b3f5ba0393f5a6d3d04254eb.png


Отключите, а затем снова включите в иерархии GameObject DungeonFloorDecoration, чтобы увидеть, как отрисовка на активном Tilemap изменяет слой DungeonFloorDecoration, а все отрисованные тайлы попадают на этот новый слой:

GIF
fe34163a070ac1c85f8d0aee80356a90.gif


Создайте новый слой Tilemap, снова воспользовавшись опцией GameObject → 2D Object → Tilemap. Назовите его Collideable. В дальнейшем мы используем его для создания стен и границ.

Переключите Active Tilemap в окне Tile Palette на Collideable. Выберите инструмент brush (B), а затем нарисуйте следующие тайлы, чтобы построить вокруг игровой области стену. Выделенные красным зоны на изображении ниже — это новые части, которые нужно добавить:

3f07e30041691b855a4d1870d69f2e34.png


Посмотрите на показанный ниже скриншот окна Tile Palette, чтобы разобраться, где найти тайлы, необходимые для постройки стены. Не забывайте, что можно использовать сочетания CTRL-Z или CMD-Z для отмены действия или стирать ошибки с помощью текущей кисти (удерживая Shift):

c9467ef7c3ac69be35fea0375965760d.png


Запустите игру в редакторе и попытайтесь пройти сквозь стену:

Кто включил режим noclip?
49d6fbe88e6368ae9d9d47caa6ed2ece.gif


Вы ведь не этого ожидали?

Проблема в том, что мы просто нарисовали стандартные тайлы и пока не применяли к слою Tilemap волшебную физику Unity.

Выберите GameObject Collideable и добавьте новый компонент, нажав кнопку Add Component в окне Inspector; в поле поиска введите Tilemap Collider 2D:

15e7ec614a110e3de5020f7b5f6a2d4d.png


Этот компонент был создан специально для тайловых 2D-игр на Unity. Он просто применяет форму физического коллайдера ко всем тайлам слоя, к которому он был добавлен, не выполняя никакой другой работы.

Снова запустите игру и попробуйте пройти сквозь стену. Доступ запрещён!

GIF
2b28f1a3a2f60422649719e084a9fd08.gif


Примечание: иногда при движении камеры можно заметить между некоторыми тайлами небольшие чёрные линии. Похоже, что это проблема движения камеры в проектах с системой 2D Tilemap Unity. От неё можно почти полностью избавиться, отключив Anti-Aliasing в параметрах графики. Однако даже если это сделать в проекте-заготовке, эффект всё равно слегка заметен. Решением этой проблемы может стать добавление собственного скрипта движения камеры с пиксельным смещением. Хорошее обсуждение этой проблемы можно найти здесь.


Коллизии работают хорошо, и вы можете подумать, что этого достаточно. Но пока коллайдеры не оптимизированы эффективно. В режиме Scene приблизьте часть стены и посмотрите на контуры коллайдеров:

4ea3f8af32c2e23852a146578a7f9f49.png


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

Выбрав GameObject Collideable, добавьте к нему компонент Composite Collider 2D. Это также автоматически добавит RigidBody2D.

Задайте параметру BodyType RigidBody2D значение Static, а затем поставьте флажок Used by Composite в компоненте Tilemap Collider 2D:

2ca12b9e01baa5b477288bc06cf546cf.png


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

Завершите создание стен, достроив их вверх и замкнув наверху, высотой примерно в 16 тайлов. Не забывайте. что в качестве Active Tilemap окна Tile Palette должен быть выбран Collideable:

7e633f81d090fd304dcee26abb4cf760.png


Участок подземелья не будет представлять никакой сложности для нашего героя без препятствий. Теперь мы начнём работу над созданием комнаты смерти, дополненной красивыми древними мраморными коридорами. После преодоления всех этих препятствий игрока ждёт награда — гора золота.

Для отрисовки этих коридоров мы воспользуемся специальной тайловой кистью Rule Tile. Как вы видели в начале туториала, в проект уже добавлены дополнительные тайловые скрипты из Github-репозитория Unity 2D Extras. Одним из них является Rule Tile.

Rule Tile позволяет нам задавать правила о том, какие тайлы нужно отрисовывать в зависимости от соседних располагаемых нами тайлов.

Нажмите правой клавишей мыши на папке Prefabs проекта и выберите Create → Rule Tile (этот пункт должен быть в верхней части меню). Назовите новый элемент MarbleFloorRuleTile:

70242b66c05805fb9a147521da24aa89.png


Выберите этот новый MarbleFloorRuleTile и используйте инспектор, чтобы присвоить Default Sprite значение roguelikeDungeon_transparent_335. Затем добавьте новое правило Tiling Rule, нажав на значок +. Выберите для Sprite этого правила значение roguelikeDungeon_transparent_339 и нажмите на все внешние квадраты в схеме правила, чтобы на каждом была указывающая наружу зелёная стрелка:

GIF
546707124181cac98c682dfadeb56491.gif


Воспользовавшись инструментом box fill brush (B) в окне Tile Palette и выбрав слой Tilemap BaseLayer, нарисуйте прямую секцию мраморной стены. Нужно, чтобы она закрывала всё пока свободное пространство пола.

Можно заметить, что когда мы будем это делать, слой будет закрывать тайлы стен с колладерами, потому что пока не задан порядок слоёв. Это легко исправить, выбрав GameObject Collideable и изменив Order in Layer компонента Tilemap Renderer на более высокое значение (достаточно будет 5):

GIF
314631467ec638cad00a0082fae58113.gif


Вернитесь в папку Prefabs проекта, откройте окно Tile и выберите палитру RoguelikeCave, а затем перетащите MarbleFloorRuleTile в пустое место на палитре:

GIF
de3c7b15b5b9e8531b15824c196d480d.gif


Воспользуйтесь box fill brush и нарисуйте в комнате несколько секций мраморного пола:

GIF
0921201ff5eb1be81f34bfebff121079.gif


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

Это ловушка!


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

Создайте в иерархии новый пустой GameObject и назовите его ShootingTrap. Создайте в ShootingTrap пустой дочерний GameObject. Назовите его Sprite:

66e75455eda0bbdb02033ebc5cff618f.png


Выберите Sprite и добавьте к нему компонент Sprite Renderer. Задайте Sorting Layer значение Player, а Order in Layer значение 1, чтобы он рендерился поверх остальных слоёв. Выберите поле Sprite, а в качестве спрайта поставьте roguelikeDungeon_transparent_180.

Теперь поверните Transform объекта Sprite на -90 по оси Z:

540666ded98bc99613b7dd5d6c7beeb7.png


Далее вернитесь к GameObject ShootingTrap и добавьте с помощью инспектора новый компонент. В поле поиска найдите Shooting Trap и прикрепите этот скрипт.

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

Задайте параметру Item to Shoot Prefab компонента Shooting Trap значение Projectile (префаб находится в /Assets/Prefabs):

a596146dc4ec7d91eb3f17e9976f5945.png


Снова запустите игру в редакторе и воспользуйтесь режимом Scene, чтобы найти ловушку. Она работает!

GIF
ef07715aed64732a12386defeec1b1cb.gif


Перетащите копию ShootingTrap из иерархии в папку /Assets/Prefabs проекта, чтобы создать префаб. Удалите ShootingTrap из иерархии.

Мы используем ещё один скрипт тайловой кисти под названием PrefabBrush для создания кисти, способной рисовать префабы на слоях Tilemap.

Нажмите правой кнопкой на папке /Assets/Prefabs проекта и выберите Create → Prefab Brush. Назовите объект PrefabBrush.

Воспользуйтесь инспектором, чтобы задать параметру Prefabs Size PrefabBrush значение 1, а параметру Element 0 — значение ShootingTrap.

c8458e0df00c239708a275d5c17fd25b.png


Создайте в Grid новый слой Tilemap под названием Traps и откройте окно Tile Palette.

Выберите обычную тайловую кисть (B) и воспользуйтесь раскрывающимся меню в нижней части окна Tile Palette для выбора PrefabBrush. Выберите в качестве слоя Active Tilemap Traps и используйте окно Scene для отрисовки нескольких префабов ловушек вдоль левой границы комнаты.

GIF
ce1f3a3b6fbea97b23f8a388404772e8.gif


Разверните в иерархии GameObject Traps и поэкспериментируйте со значением Shoot Start Delay для каждого value on each Gameobject ShootingTrap с помощью скрипта Shooting Trap в инспекторе. Добавляйте к значению каждой ловушки по 0.25, т.е.:

  • Первая ShootingTrap → Shoot Start Delay = 0.1
  • Вторая ShootingTrap → Shoot Start Delay = 0.35
  • Третья ShootingTrap → Shoot Start Delay = 0.6
  • И так далее…


Запустите игру и пройдите испытание, если осмелитесь.

GIF
02b809ea5ea2b177b3da6d537a447794.gif


Конечная цель


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

Создайте в GameObject Grid новый слой Tilemap под названием Goal. Выберите Goal и измените значение Tilemap Renderer Order in Layer на 2:

ece7bff1f2eec46dab6974ec9293d8e8.png


Не закрывая окно Tile Palette, убедитесь, что всё ещё выбрана PrefabBrush. Сделайте так, чтобы Element 0 ссылался на заготовку Goal из папки /Assets/Prefabs проекта.

Это префаб со спрайтом горы золота, с Box Collider 2D со включенным режимом Is Trigger, добавленным источником звука, и с простым скриптом Goal.cs, воспроизводящим звук достижения цели и перезапускающим уровень, когда игрок попадает в область триггера.

Воспользуйтесь стандартной тайловой кистью для отрисовки одного тайла-префаба цели в верхней части комнаты за ловушками:

ee49701c003075b4bb2a048b6d2e8039.png


Снова запустите игру и попробуйте достичь цели. Когда вы доберётесь до этого тайла, запустится логика OnTriggerEnter2D() из Goal.cs, воспроизведя звуковой эффект и перезапустив уровень.

2c1736d0e9eb131101cef9c7ee08a18d.png


Последние штрихи


Сейчас подземелье слишком светлое и свободное. Мы можем добавить ему стиля, переключившись на материал 2D-спрайта, способный реагировать на свет.

Выберите Sprite объектов Player, Goal и ShootingTrap, и сделайте так, чтобы Material компонента Sprite Renderer использовал SpriteLightingMaterial:

9e87ce36a51b69b514f71cf71992f4b5.png


Это материал с прикреплённым к нему шейдером Sprite/Diffuse. Он позволяет освещению сцены воздействовать на спрайты.

В GameObject Grid выберите объекты BaseLayer, DungeonFloorDecoration, Collideable и Goal, а потом воспользуйтесь инспектором, чтобы тоже использовать в материале Tilemap Renderer Material SpriteLightingMaterial.

Затем выберите в GameObject Lights Directional light и снизьте значение Intensity Light до 0.3.

Так гораздо лучше!

6fecb24ed773ea4b843e2ee32d3be164.png


Также вы сейчас заметите, что Player носит с собой Point light, то есть светящий вокруг него Lantern.

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

Перетащите две копии префаба FlickerLight из папки /Assets/Prefabs проекта в Scene и разместите их в GameObject Lights.

Задайте первому префабу позицию (X:-11.25, Y:4, Z:-1.35), а второму — (X:2.75, Y:4, Z:-1.35).

Создайте новый слой Tilemap под названием WallsAndObjects и задайте в инспекторе Tilemap Renderer Order in Layer значение 15. Не забудьте, чтобы Material тоже использовал материал SpriteLightingMaterial.

Переключите кисть палитры тайлов обратно на Default Brush, а Active Tilemap на WallsAndObjects.

Воспользуйтесь инструментом brush (B) для отрисовки двух тайлов «света фонарей» под каждым из новых FlickerLight, которые мы разместили по углам начальной области:

6a82aeb824326ec78184559b0986ef78.png


Время трудностей


Посмотрим, сможем ли мы ещё больше улучшить подземелье. Используйте слой Tilemap WallsAndObjects для создания книжных шкафов в верхней части комнаты подземелья с помощью другой палитры тайлов под названием RoguelikeCustom. Также нарисуйте одну-две части стены с трещинами.

Вернитесь обратно в слой Tilemap DungeonFloorDecoration и добавьте ещё немного деталей на мраморный пол, например, трещины на нескольких тайлах:

GIF
6115d7f2a96969a47b9c262dd215623b.gif


Поздравляю, вы завершили свой первый мини-уровень подземелья! В результате у вас должно получиться нечто подобное:

f1b1900633e1a0fdad59453a238c5a17.png


Куда двигаться дальше?


Если вы пропустили какой-то шаг, то можете посмотреть на готовый результат этого туториала, открыв проект Unity Rayzor-final из скачиваемых материалов.

В этом туториале мы научились многому, но как и в любом другом деле, всегда есть что-то ещё!

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

Также можете изучить создание анимированных тайлов здесь.

© Habrahabr.ru