Как рисовать в unity
Создание приложения-раскраски на Unity3D
Эта история началась одним морозным весенним вечером, когда в голову пришел вопрос: а есть ли способ определять степень заливки произвольной геометрической фигуры краской (то есть, на сколько процентов она в данный момент закрашена)? Да так, чтобы это не просто не тормозило, а летало на 60 fps на самых слабых мобильных девайсах.
Да и вообще, работать с растром представлялось занятием неспортивным. Взор был обращён в сторону всемогущих полигонов. Несколько волнующих часов расслабленно-упорного кодинга доказали гипотезу: можно воспользоваться такой штукой, как «вершинный цвет» — vertex color.
Думаю, стоит упомянуть, для чего понадобился пресловутый процент закраски, с которого началась статья. Основной идеей приложения-раскраски было следующее: конечная картинка состоит из набора многоугольников. Приложение будет последовательно и автоматически подсовывать пользователю элемент за элементом. Соответственно, пока не раскрасишь до конца один кусок, к следующему не перейдёшь. Подобное решение мне казалось весьма элегантным, прельстивым и в свете глобального засилья «пиксельных» раскрасок в сторах — ещё и свежим.
Первые шаги
Само собой, для того, чтобы сделать полноценную раскраску, необходимо было наколхозить накреативить еще много интригующих решений. Во-первых, я хотел, чтобы при всей полигональной природе приложения, раскрашивание воспринималось как самое что ни на есть растровое, то есть краска должна была растекаться под пальцем, и иметь более-менее реалистичный вид. Изначальное требование по максимальной производительности при этом никуда не исчезало и продолжало висеть грозным кучевым облаком над всем техпроцессом.
Первым делом предстояло сделать человеческую тесселяцию (разбиение большого многоугольника, состоящего из набора треугольников, на стохастическую кучу маленьких треугольников). Ведь если мы заведем массив вершин, и будем туда записывать vertex color по мере закрашивания, то сможем обычным проходом по массиву определять, закрашена ли фигура полностью, и какие ещё куски остались незакрашенными – аналогично пиксельному алгоритму, но с куда большей свободой.
Дальше началось увлекательное путешествие в мир шейдеров. Как вы понимаете, целиком все находки и секреты я открыть не могу, но скажу, что путем взаимодействия с картой шума и олдскульного испускания лучей Unity из пальцев, эффект кисти был достигнут, и даже с некоторым растеканием краски по близлежащим от пальца треугольникам. Использование vertex color предоставило возможность обойтись одним материалом Unity на абсолютно все составные части фигуры и поэтому draw calls в готовой программе не превышает 5-7 (в зависимости от наличия меню и частиц).
Обводка сделана обычным Unity Line Renderer, который предательски глючит на некоторых фигурах, съезжая и демонстрируя изъяны на стыках. Победить это не удалось, поэтому приоритетная задача — переписать компонент с нуля. След за пальцем — это также стандартный Trail Renderer, но в его шейдере используется z-проверка, чтобы элементы следа не накладывались друг на друга, создавая некрасивые артефакты. «Шахматная» текстура фона помогает, в том числе, оценить размер закрашиваемого элемента: чем он больше, тем меньше будет размер клеточек.
Функционал, которого не ждали
В ходе тестирования выяснилось, что часто где-то в углах фигуры оставались незаполненные вершины, что было трудно определить визуально. Несмотря на то, что триггер переключения на следующий элемент срабатывал при степени заливки в 97%, ситуации «а что делать дальше?» – при степени заполненности от 90% до 97% — возникали достаточно часто и смущали пользователей (которым в основном было не более 12 лет). Ставить триггер менее 97% не хотелось, потому что тогда возникал эффект «я еще не докрасил, а оно уже перескочило».
Так я неохотно познакомился с мадам Кластеризацией. Представьте: многоугольник, куча точек внутри, есть какие-то «особенные», иногда отдельно, иногда – группами. Нужно найти и обозначить самую большую «группу». Обычная такая математическая задача. Ни один из найденных мной традиционных алгоритмов не подошел по разными причинам, пришлось делать свой. Хак на хаке, но заработало – и недокрашенные области стали выделяться красивым динамическим кругом. В целях оптимизации, этот алгоритм срабатывает раз в 3 секунды, и только после того, как пользователь озадаченно оторвет палец от экрана в стиле «а что делать дальше». Выглядит вполне органично.
После такого мозгового штурма, сделать по требованиям тестеров вариативную «очередь раскраски» — а именно, дать пользователю возможность выбрать, в какой последовательности он хочет раскрашивать элементы – было делом одного вечера. Всего-то нужно определить геометрические центры каждого меша и выстроить их, как нам надо: слева направо, сверху вниз и т. д. Для большей наглядности, были реализованы частицы на фоне, которые показывают направление очереди.
Здесь показана дефолтная очередь (так, как задумал художник). Если включить режим «очередь по направлению» нажатием на одну из кнопок внизу, очередь раскрашивания изменится, и частицы поедут в указанную сторону.
UX & UI
Мне вообще импонирует идея контролируемого автоматизма в приложениях, и поэтому каждый элемент центруется и масштабируется так, чтобы его можно было закрасить пальцем без необходимости в прокрутке экрана. Минусом такого подхода стало то, что не всегда понятно, что за часть фигуры сейчас на экране. Как выяснилось, пользователям даже нравится такой небольшой челлендж, так как он тренирует краткосрочную память и соотнесение информации – нужно держать в голове общую картину. Ну а выйти на «обзор фигуры с птичьего полета» можно двумя способами – жестом-щипком (pinch) или нажатием на кнопку zoom.
Следуя заветам Apple Interface Guidelines, было принято решение сократить количество кнопок на экране до минимума. Помимо кнопки zoom in/out и очевидной кнопки выхода в меню, еще есть вызов палитры – красить можно как цветом «по умолчанию», установленным художником, так и по собственному выбору.
Кроме того, в режиме «из птичьих глаз» можно поменять градиент фона (рандомно генерируется каждое нажатие) или войти в режим «перекрашивания», который позволяет исправить уже закрашенный элемент. Да, пришлось запрятать этот функционал, но это вполне оправдано — за все тестирование никто ни разу не спросил, как это сделать.
Про палитру
Сама по себе палитра переделывалась два раза. Сначал я просто располагал на экране какое-то количество квадратов с цветами, но пользователи просили больше цветов. Прокрутку в интерфейсе я делать не хотел, и так появилась схема «цвет-оттенок», то есть сначала юзер выбирает нажатием базовый цвет, а затем – один из его оттенков. Палитра убирается кнопкой или вальяжным свайпом вниз. Причем когда она появляется на экране, рабочее пространство художника сокращается на 1/3, что вызывает необходимость в «перемасштабировании» текущей фигуры под изменившийся размер viewport’а.
На сладкое
Ключевым нехватающим звеном всей картины был reward – некая визуально-психологическая награда, которую получает пользователь по завершению процесса раскраски. Идея была подсмотрена лежала на поверхности: фигура раскрашивалась автоматически и заново, в ускоренном режиме, причём именно так, как это делал пользователь – проще говоря, timelapse на 15-20 секунд. Реализовано это через запись последовательности, в которой юзер касался вершин фигур, и затем последующего проигрывания в виде «скармливания» этих данных рисовательному движку с задержками (через coroutines). Каждый меш дублируется несколько раз для достижения эффектов «проявления» и «затухания».
Разумеется, timelapse при проигрывании записывается в видеофайл, и после визуальной феерии пользователю предлагается сохранить/поделиться свежесозданным шедевром. К счастью, как раз весной в Asset Store появился плагин, который позволяет полноценно и мультиплатформенно захватывать видео с экрана (после некоторой настройки), потому что написание такого инструмента с нуля далеко выходит за рамки моей программерской квалификации а вообще я дизайнер.
GameDev с нуля: Unity3D и векторная графика
OVIVO продолжают рассказывать о своём опыте разработки игр. Статья в первую очередь будет интересна новичкам в геймдеве и тем, кто уже освоил азы работы с Unity. Слово автору. 🙂
Цикл статей «GameDev с нуля»
Привет, Хабр! Я занимаюсь программной частью в игре OVIVO и хочу поделиться с сообществом своим опытом внедрения векторной графики в Unity. Ниже я кратко опишу структуру SVG-файлов, расскажу о своих пробах и ошибках, а также продемонстрирую результат.
Постановка задачи
Имеем пустое пространство, заполненное белым цветом. Добавляем туда черные кляксы. Поскольку эти кляксы — интерактивный элемент 2D-игры, то будем звать их платформами. Также есть круглый персонаж, способный перемещаться по платформам и перескакивать из одного цвета в другой. Когда игрок находится в белом мире, на него действует гравитация, направленная вниз. Если же он очутился внутри черной платформы, то его тянет вверх. Перемещаясь между двумя мирами, у игрока сохраняется импульс, благодаря чему он может преодолевать препятствия, требующие определенной прыгучести. Так звучит краткое описание базовой механики нашей игры.
Но сегодня поговорим не о механике, а об этих черных кляксах. Поскольку платформы имеют относительно несложную форму и окрашены всего в один цвет, то для их создания идеальным инструментом будет любой векторный графический редактор. До моего прихода в команду всю графику ребята растрировали и оперировали громоздкими спрайтами в среде Unity. А громоздкими они были оттого, что требовалась высокая четкость картинки, следовательно, на разрешении спрайтов экономить нельзя было. Месяца два мы мучались с вопросом об использовании растра. Все методы перепробовали, но либо размер билда переваливал за один гигабайт, либо мобильные системы не выдерживали такого потребления ресурсов. И однажды мне стало интересно, что же такое векторная графика и с чем ее едят. В нашем случае все оказалось предельно просто: используются лишь кривые Безье и некоторые геометрические примитивы. А самым замечательным открытием для меня был формат SVG, в который без проблем можно было экспортировать всю нашу графику. Я очень обрадовался, узнав, что это всего лишь XML-документ.
Перед парсингом SVG необходимо было четко определиться с тем, как мы это все будем отображать в Unity. Самое очевидное решение: использовать сетку (Mesh). Поскольку наши платформы являются замкнутыми фигурами, то их контур можно представить в виде последовательно соединенных между собой точек, а благодаря триангуляции создать подходящий набор полигонов, которые будут служить заливкой для этой фигуры.
Описание метода решения
Подробно рассказывать о структуре и всех возможностях SVG я не буду, однако остановлюсь на одном из его элементов — path. Ведь именно здесь хранятся почти все интересующие нас данные. Обратить внимание нужно на атрибут d, в котором записана информация о всех последовательно соединенных линиях, образующих единую фигуру.
Как видно из примера, набор чисел можно превратить в гладкую фигуру.
Забегая наперед скажу, что лишь в одном атрибуте d единственного path можно рисовать неограниченное количество фигур, будь то замкнутые контуры или произвольные линии, но об этом позже. Данные из d условно можно разделить на блоки с контрольными точками для каждой кривой.
В работе с каждой платформой мы можем задать ей точность построения контура. Например, если установлено число 8, то каждая кривая будет разбита на 8 отрезков. В итоге, зная тип кривой и владея всеми ее контрольными точками, мы с легкостью можем строить ломаную линию, которая при высокой точности будет выглядеть аналогично гладкой кривой.
В path поддерживаются несколько типов кривых Безье и прямых линий, поэтому необходимо было подстраивать инструмент под возможность парсить каждый тип. Самые неприятные моменты возникали с форматом записи данных в атрибуте d. На протяжении всей разработки игры ребята постоянно сталкивались с тем, что те или иные векторные спрайты просто не строились, а мой инструмент выдавал ошибки. Как оказалось, разные графические редакторы (в том числе и разные версии одной марки) генерировали код SVG зачастую по-разному. Например, один и тот же путь можно записать различными способами: используя в некоторых местах верхний регистр или нижний, пробел или новую строку. Приходилось вручную ковырять каждый такой спрайт и дописывать свой парсер под нужды художников. При том, что иногда редакторы генерировали удобочитаемый код, а иногда все лепили в одну строку. Дело со временем усложнялось еще и тем, что необходимо было строить множество платформ, записанных в один SVG-файл. Потом и вовсе оказалось, что все фигуры можно засунуть в один элемент path. На самом деле, было и множество других сюрпризов, которые уже не вспомнить. Тогда, конечно, все писалось на скорую руку, но на будущее я для себя усвоил урок: сначала детальное изучение спецификации, потом код.
В большинстве случаев точность у нас была фиксированной, однако не всегда итоговая картинка соответствовала ожиданиям. Чем выше степень кривизны линии, тем на большее количество отрезков ее нужно разбить для создания эффекта гладкости. В качестве тестовой фичи я добавил возможность автоопределения точности в зависимости от кривизны линии, но впоследствии мы перешли на ручную настройку точности контура.
Иногда необходимо было подправить совсем небольшой кусочек сетки, но повышать точность всей фигуры целиком не хотелось. Поскольку объекты в сцене никак не привязаны к каким-либо ассетам в проекте, то в каждой платформе я на всякий случай хранил XML-текст по которому можно было распарсить графику. Таким образом, имея возможность подтянуть любой кусок платформы в виде кривой, мы теоретически могли править сетку и коллайдер только в конкретных промежутках. Хотя и пришлось слегка нарушить автоматизм в просчете точек, но в итоге мы обзавелись небольшой утилитой, позволяющей задавать точность отдельно взятых кривых у платформы.
Практическое применение такого инструмента у нас сводится к двум задачам:
Альтернативные решения от сторонних разработчиков
Около полугода назад встал вопрос об отрисовке еще более высокодетализированных и сложных спрайтов. Нужна была стабильность, которую мой инструмент пока гарантировать не мог. В итоге начали смотреть в сторону покупки стороннего плагина из Asset Store. Выбор стоял между Simply SVG и SVG Importer. В итоге, изучив видеоматериалы, документацию и отзывы двух продуктов, остановились на втором варианте.
Однако от использования моего инструмента мы не отказались. Важными его особенностями является возможность построения эдж-коллайдера и редактирование точности отдельных кривых. Конечно, это все можно было бы написать и поверх купленного плагина, но когда вы активно готовитесь к релизу, то хочется сосредоточиться на более насущных вещах и не трогать то, что уже оттестировано и прекрасно работает.
Эпилог
Еще в начале разработки мы не уделили внимание изучению готовых решений и сразу приступили к написанию собственного велосипеда. Можно долго жалеть о потраченном времени и гадать на тему “что было бы, если…”, но, все же, я очень рад получению такого опыта. Это была та самая не рутина, программированием которой я занимался с искрой в глазах.
Лично я верю в то, что команда Unity в скором времени добавит поддержку векторной графики “из коробки”. Благодаря описанному в статье методу можно забыть о проблемах потребления ресурсов как минимум на мобильных платформах и сконцентрироваться на более важных вещах. Конечно, далеко не все сейчас рисуют графику для 2D-игр в векторе, однако, уверен, переход на неё будет вполне оправдан, если на первое место станет размер дистрибутива, раздутый громоздкими ресурсами.
Благодарю за внимание. Все личные вопросы и замечания просьба присылать squakoon_jr.
Введение в новую систему тайловых карт Unity
Знакомство с систему двухмерных тайловых карт Unity даёт отличную возможность экономии времени инди-разработчиков и игровых студий на прототипирование и создание качественных 2D-игр.
Без этой системы можно потратить дни, если не недели на написание собственной системы тайловых карт или переработку чужой. И это только программирование, а как насчёт редактора тайловых карт?
Новая система бесплатна и встроена непосредственно в редактор Unity. Она предоставляет множество возможностей, которые мы рассмотрим в этом туториале.
В этой статье мы воспользуемся простой тайловой 2D-игрой, чтобы узнать следующее:
Примечание: в этом туториале подразумевается, что вы хорошо умеете работать в редакторе Unity. Если вы считаете, что недостаточно в нём освоились, то в туториале Introduction to Unity есть всё необходимое для изучения этого туториала. Кроме того, вам необходима версия Unity 2017.3 или выше.
Что такое тайловая игра?
Тайловая 2D-игра — это любая игра, в которой уровни или игровые области состоят из множества небольших плиток (тайлов), вместе образующих сетку тайлов. Иногда различия между тайлами могут быть очевидными, а иногда они кажутся игрокам сплошными и неразличимыми.
Коллекция имеющихся в игре тайлов называется «тайлсетом», и каждый тайл обычно является спрайтом, частью листа спрайтов (spritesheet). Если вы хотите лучше разобраться с листами спрайтов, то у нас есть туториал, в котором описываются листы спрайтов Unity.
Как можно увидеть в этом туториале, обычно тайлы являются квадратами. Но они могут принимать и другую форму — прямоугольники, параллелограммы или шестигранники. В играх обычно используется вид сверху или сбоку, но иногда в тайловых играх применяется и 2.5D.
Возможно, вам уже известны две самые популярные игры, в которых используется система тайловых карт: Starbound и Terraria.
Приступаем к работе
Запустите редактор Unity и загрузите проект Rayzor-starter из распакованных материалов проекта.
Вот, с чем вы будете работать в этом проекте:
Создание игры
Откройте сцену Game из папки Scenes.
Нажмите на кнопку Play в редакторе, чтобы запустить игру. В окне Game перемещайте героя клавишами WASD или «стрелками».
Пока герой бродит по кажущемуся бесконечным фону камеры с цветом #00000, потерявшись в пустоте.
Чтобы исправить это, нам потребуются инструменты 2D-тайлов для построения интересных уровней и механик игры.
Знакомимся с палитрой тайлов
Это окно станет вашим лучшим другом при работе над тайловыми играми в Unity.
Нажмите на Create и выберите сохранение новой палитры в папке Assets\Palettes проекта. В ней создайте новую папку RoguelikeCave.
Теперь структура папок вашего проекта должна выглядеть так:
В окне редактора Tile palette должна быть выбрана RoguelikeCave; на этом этапе у нас всё ещё нет никаких тайлов:
Как художник может творить свои шедевры, если у него нет материалов?
Не закрывая окно Tile Palette, выберите папку проекта Sprites/roguelike-cave-pack и разверните ассет roguelikeDungeon transparent.png. Затем выделите все спрайты в этом листе спрайтов: выберите первый спрайт, зажмите shift и выберите последний спрайт.
Перетащите все выбранные спрайты в окно Tile Palette RoguelikeCave:
Перетащив спрайты в окно Tile Palette, выберите в Unity место для хранения ассетов.
Создайте в Assets/Palettes/RoguelikeCave новую папку Tiles и выберите эту папку в качестве места хранения:
Unity сгенерирует тайловый ассет для каждого спрайта, добавленного из листа спрайтов. Дождитесь завершения процесса, затем увеличьте размер окна Tile Palette и полюбуйтесь на ровные ряды красивых новых тайлов, расположившихся в палитре RoguelikeCave:
Повторите описанный выше процесс для создания палитры тайлов с помощью окна Tile Palette, но на этот раз назовите новую палитру RoguelikeCustom.
Поместите новую палитру в новую папку. Назовите папку RoguelikeCustom и переместите её в папку Assets/Palettes проекта.
На этот раз, воспользовавшись описанным выше процессом, используйте спрайты из листа Assets/Sprites/roguelike-custom/roguelike-normal-cutdown-sheet.png для заполнения тайлами новой палитры. Создайте внутри папки палитры RoguelikeCustom папку Tiles и переместите ассеты тайлов туда:
Порадуйтесь за себя, теперь вам известна магия создания тайловой палитры!
Создание сетки карты тайлов
Откройте меню GameObject в верхней части редактора Unity (или панель меню Unity, если вы работаете под MacOS), нажмите на 2D Object, а затем Tilemap, чтобы создать новую сетку Tilemap:
Вы должны увидеть, что в иерархию сцены добавился новый GameObject Grid. Разверните его и выберите встроенный GameObject Tilemap.
Воспринимайте этот объект Tilemap как слой (возможно, один из многих) вашей игры. Можно добавить новые объекты для создания дополнительных слоёв Tilemap.
В инспекторе вы увидите два компонента, которые Unity автоматически добавила к этому GameObject:
Использование различных инструментов рисования палитры тайлов
Переключитесь в редакторе на режим Scene.
Не закрывая окно Tile Palette, выберите палитру RoguelikeCave, а затем выберите инструмент brush (или нажмите B). Выберите тайл песка, как показано ниже:
В окне Scene переместите курсор на сетку рядом с игроком. Кисть с тайлом песка будет привязываться к сетке.
Зажав и удерживая левую клавишу мыши, нарисуйте вокруг игрока прямоугольную область. Она будет отрисована на слое Tilemap BaseLayer:
Рисование больших областей может оказаться монотонным занятием, поэтому существует кисть Filled Box, которую можно использовать для закрашивания крупных площадей. В окне Tile Palette нажмите на квадратный значок кисти (или нажмите U).
Вернитесь в редактор и нарисуйте вокруг игрока прямоугольник ещё большего размера, нажав и удерживая левую клавишу мыши, перетаскивая курсор из верхнего левого в нижний праый угол:
Хотя мы добавили в игру немного цвета, это песчаное подземелье выглядит уныло. Настало время добавить немного деталей!
В окне Tile Palette переключите Active Tilemap на слой DungeonFloorDecoration:
Выберите инструмент brush (B), затем нарисуйте в окне Scene разбросанные на карте объекты:
Отключите, а затем снова включите в иерархии GameObject DungeonFloorDecoration, чтобы увидеть, как отрисовка на активном Tilemap изменяет слой DungeonFloorDecoration, а все отрисованные тайлы попадают на этот новый слой:
Переключите Active Tilemap в окне Tile Palette на Collideable. Выберите инструмент brush (B), а затем нарисуйте следующие тайлы, чтобы построить вокруг игровой области стену. Выделенные красным зоны на изображении ниже — это новые части, которые нужно добавить:
Посмотрите на показанный ниже скриншот окна Tile Palette, чтобы разобраться, где найти тайлы, необходимые для постройки стены. Не забывайте, что можно использовать сочетания CTRL-Z или CMD-Z для отмены действия или стирать ошибки с помощью текущей кисти (удерживая Shift):
Запустите игру в редакторе и попытайтесь пройти сквозь стену:
Вы ведь не этого ожидали?
Проблема в том, что мы просто нарисовали стандартные тайлы и пока не применяли к слою Tilemap волшебную физику Unity.
Выберите GameObject Collideable и добавьте новый компонент, нажав кнопку Add Component в окне Inspector; в поле поиска введите Tilemap Collider 2D:
Этот компонент был создан специально для тайловых 2D-игр на Unity. Он просто применяет форму физического коллайдера ко всем тайлам слоя, к которому он был добавлен, не выполняя никакой другой работы.
Снова запустите игру и попробуйте пройти сквозь стену. Доступ запрещён!
Примечание: иногда при движении камеры можно заметить между некоторыми тайлами небольшие чёрные линии. Похоже, что это проблема движения камеры в проектах с системой 2D Tilemap Unity. От неё можно почти полностью избавиться, отключив Anti-Aliasing в параметрах графики. Однако даже если это сделать в проекте-заготовке, эффект всё равно слегка заметен. Решением этой проблемы может стать добавление собственного скрипта движения камеры с пиксельным смещением. Хорошее обсуждение этой проблемы можно найти здесь.
Коллизии работают хорошо, и вы можете подумать, что этого достаточно. Но пока коллайдеры не оптимизированы эффективно. В режиме Scene приблизьте часть стены и посмотрите на контуры коллайдеров:
Вокруг каждого тайла есть коллайдер. Средним секциям стен не нужны эти дополнительные коллайдеры.
Выбрав GameObject Collideable, добавьте к нему компонент Composite Collider 2D. Это также автоматически добавит RigidBody2D.
Задайте параметру BodyType RigidBody2D значение Static, а затем поставьте флажок Used by Composite в компоненте Tilemap Collider 2D:
После этого вы заметите, что эти ненужные квадратные коллайдеры посередине стен исчезнут.
Завершите создание стен, достроив их вверх и замкнув наверху, высотой примерно в 16 тайлов. Не забывайте. что в качестве Active Tilemap окна Tile Palette должен быть выбран Collideable:
Участок подземелья не будет представлять никакой сложности для нашего героя без препятствий. Теперь мы начнём работу над созданием комнаты смерти, дополненной красивыми древними мраморными коридорами. После преодоления всех этих препятствий игрока ждёт награда — гора золота.
Для отрисовки этих коридоров мы воспользуемся специальной тайловой кистью Rule Tile. Как вы видели в начале туториала, в проект уже добавлены дополнительные тайловые скрипты из Github-репозитория Unity 2D Extras. Одним из них является Rule Tile.
Rule Tile позволяет нам задавать правила о том, какие тайлы нужно отрисовывать в зависимости от соседних располагаемых нами тайлов.
Воспользовавшись инструментом box fill brush (B) в окне Tile Palette и выбрав слой Tilemap BaseLayer, нарисуйте прямую секцию мраморной стены. Нужно, чтобы она закрывала всё пока свободное пространство пола.
Можно заметить, что когда мы будем это делать, слой будет закрывать тайлы стен с колладерами, потому что пока не задан порядок слоёв. Это легко исправить, выбрав GameObject Collideable и изменив Order in Layer компонента Tilemap Renderer на более высокое значение (достаточно будет 5):
Вернитесь в папку Prefabs проекта, откройте окно Tile и выберите палитру RoguelikeCave, а затем перетащите MarbleFloorRuleTile в пустое место на палитре:
Воспользуйтесь box fill brush и нарисуйте в комнате несколько секций мраморного пола:
Заметьте, что настроенный тайл правил, полностью окружённый со всех углов и граней, становится украшенным тайлом (спрайтом, выбранным в редакторе Tiling Rules).
Это ловушка!
Нет, мы не будем добавлять в игру в качестве персонажа адмирала Акбара. Мы создадим тайловую кисть префаба ловушки, которой воспользуемся для отрисовки ловушек, стреляющих вращающимися лезвиями!
Создайте в иерархии новый пустой GameObject и назовите его ShootingTrap. Создайте в ShootingTrap пустой дочерний GameObject. Назовите его Sprite:
Выберите Sprite и добавьте к нему компонент Sprite Renderer. Задайте Sorting Layer значение Player, а Order in Layer значение 1, чтобы он рендерился поверх остальных слоёв. Выберите поле Sprite, а в качестве спрайта поставьте roguelikeDungeon_transparent_180.
Теперь поверните Transform объекта Sprite на -90 по оси Z:
Далее вернитесь к GameObject ShootingTrap и добавьте с помощью инспектора новый компонент. В поле поиска найдите Shooting Trap и прикрепите этот скрипт.
Этот скрипт добавлен в скачанные вами файлы проекта; по сути, он каждые две секунды запускает корутину, создающую экземпляр префаба вращающегося лезвия пилы (или любого другого префаба) в текущей позиции ловушки.
Задайте параметру Item to Shoot Prefab компонента Shooting Trap значение Projectile (префаб находится в /Assets/Prefabs):
Снова запустите игру в редакторе и воспользуйтесь режимом Scene, чтобы найти ловушку. Она работает!
Перетащите копию ShootingTrap из иерархии в папку /Assets/Prefabs проекта, чтобы создать префаб. Удалите ShootingTrap из иерархии.
Мы используем ещё один скрипт тайловой кисти под названием PrefabBrush для создания кисти, способной рисовать префабы на слоях Tilemap.
Воспользуйтесь инспектором, чтобы задать параметру Prefabs Size PrefabBrush значение 1, а параметру Element 0 — значение ShootingTrap.
Создайте в Grid новый слой Tilemap под названием Traps и откройте окно Tile Palette.
Выберите обычную тайловую кисть (B) и воспользуйтесь раскрывающимся меню в нижней части окна Tile Palette для выбора PrefabBrush. Выберите в качестве слоя Active Tilemap Traps и используйте окно Scene для отрисовки нескольких префабов ловушек вдоль левой границы комнаты.
Разверните в иерархии GameObject Traps и поэкспериментируйте со значением Shoot Start Delay для каждого value on each Gameobject ShootingTrap с помощью скрипта Shooting Trap в инспекторе. Добавляйте к значению каждой ловушки по 0.25, т.е.:
Конечная цель
Цель этого мини-подземелья заключается в получении груды золота. Слава и богатство ждут тех, кто доберётся до неё, избежав смертельно опасных летающих лезвий.
Создайте в GameObject Grid новый слой Tilemap под названием Goal. Выберите Goal и измените значение Tilemap Renderer Order in Layer на 2:
Не закрывая окно Tile Palette, убедитесь, что всё ещё выбрана PrefabBrush. Сделайте так, чтобы Element 0 ссылался на заготовку Goal из папки /Assets/Prefabs проекта.
Воспользуйтесь стандартной тайловой кистью для отрисовки одного тайла-префаба цели в верхней части комнаты за ловушками:
Последние штрихи
Сейчас подземелье слишком светлое и свободное. Мы можем добавить ему стиля, переключившись на материал 2D-спрайта, способный реагировать на свет.
Выберите Sprite объектов Player, Goal и ShootingTrap, и сделайте так, чтобы Material компонента Sprite Renderer использовал SpriteLightingMaterial:
Это материал с прикреплённым к нему шейдером Sprite/Diffuse. Он позволяет освещению сцены воздействовать на спрайты.
В GameObject Grid выберите объекты BaseLayer, DungeonFloorDecoration, Collideable и Goal, а потом воспользуйтесь инспектором, чтобы тоже использовать в материале Tilemap Renderer Material SpriteLightingMaterial.
Затем выберите в GameObject Lights Directional light и снизьте значение Intensity Light до 0.3.
Также вы сейчас заметите, что 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, которые мы разместили по углам начальной области:
Время трудностей
Посмотрим, сможем ли мы ещё больше улучшить подземелье. Используйте слой Tilemap WallsAndObjects для создания книжных шкафов в верхней части комнаты подземелья с помощью другой палитры тайлов под названием RoguelikeCustom. Также нарисуйте одну-две части стены с трещинами.
Вернитесь обратно в слой Tilemap DungeonFloorDecoration и добавьте ещё немного деталей на мраморный пол, например, трещины на нескольких тайлах:
Поздравляю, вы завершили свой первый мини-уровень подземелья! В результате у вас должно получиться нечто подобное:
Куда двигаться дальше?
Если вы пропустили какой-то шаг, то можете посмотреть на готовый результат этого туториала, открыв проект Unity Rayzor-final из скачиваемых материалов.
В этом туториале мы научились многому, но как и в любом другом деле, всегда есть что-то ещё!
Существуют интересные скрипты тайловых кистей, не рассмотренные в этом туториале. Прочитайте о них здесь и подумайте, сможете ли вы воспользоваться ими.
Также можете изучить создание анимированных тайлов здесь.