Дисклеймер: это не туториал, это краткое описание моего опыта работы с DunGen и пары нюансов, с которыми столкнулся при использовании его в RATOMON. У этого ассета одна из самых понятных инструкций, да и в целом он построен очень логично. По крайней мере тот функционал, который я использовал, недоумения не вызвал ни разу.
DunGen - это генератор лабиринтов, составленных из комнат* согласно набору правил. Некоторые правила задаются глобально для всего лабиринта сразу, например, количество комнат по главному** маршруту. Другие - локально, например, количество внутрикомнатного контента. Есть вещи, которые можно настроить и так, и так, например, количество возможных ответвлений от главного маршрута может быть задано для каждой комнаты или для всего лабиринта.
*комната
В какой-то момент автор переименовал "комнаты" в "тайлы" (набор комнат - в "TileSet", соответственно), создав путаницу с родными юнитёвыми тайлами и тайлсетами. В чём была причина переименования, я не знаю.
**главный маршрут
Предполагается, что в лабиринте есть комната-начало, с неё начинается генерация (с неё, скорее всего, стартует игрок). И есть комната-цель, которая может иметь важную игровую роль, может не иметь, но комната-цель обязательно будет создана. Т.е. минимальный лабиринт будет состоять из двух комнат, комнаты-начала и комнаты-цели.
Главный маршрут создаётся в первую очередь, а потом уже генерируются ответвления, если они предусмотрены правилами.
Итоговый лабиринт может выглядеть вот так. Главный маршрут показан тонкой красной линией.
Кратко, формулы генерации можно так записать (Внимание! Сейчас будет непонятно):
DF = STS + DA + (N|DA)^X + GTS.
DA = TS + (TS)^X
N = TS + (TS)^X
TS = T + (T)^X
Расшифровываю снизу-вверх:
T - Tile - это комната, конкретная комната, в ней есть двери, через которые игрок может в неё зайти. В неё можно также добавить компонент Local Prop Set, о нём ниже расскажу.
TS - TileSet - это набор комнат, в процессе генерации DunGen будет случайным образом доставать комнату из тайлсета и пытаться присоединить её к уже созданным комнатам. Скорее всего, комнаты каждого тайлсета будут соответствуют определённому стилю.
^X - это я так обозначил повторение элемента.
(T)^X - от нуля до бесконечности тайлов.
(TS)^X - от нуля до бесконечности тайлсетов.
STS - Start TileSet - набор комнат, одна из которых будет выбрана случайным образом и станет стартовой комнатой.
GTS - Goal TileSet - набор комнат, одна из которых будет выбрана случайным образом и станет финишной/целевой комнатой.
Напомню, путь от старта до финиша/цели - это главный маршрут, он создаётся в первую очередь.
N - Node - это комната, посреди лабиринта, может быть выбрана из нескольких заданных для неё тайлсетов.
DA - Dungeon Archetype - архетип подземелья (непонятный набор букв;+)). Смысл архетипа в том, что подземелье может состоять из нескольких разных кусков, для каждого из которых можно задать визуальный стиль, правила ветвления (количество и глубину ответвлений) и ещё несколько параметров.
Например, мы делаем подземелье "Круги ада" и для каждого круга создаём архетип, оформляем его по-разному, и теперь душенька-игрок чётко будет видеть, по какому кругу он телепается.
DF - Dungeon Flow - это самое высокоуровневое описание лабиринта. Тут описывается, сколько всего комнат будет в главном маршруте, будет ли количество ответвлений считаться глобально для всего лабиринта или для каждой комнаты отдельно и самое интересное: из каких составных частей лабиринт состоит.
Ещё раз приведу картинку с главным маршрутом, чтобы не листать туда-сюда:
Здесь разными цветами показаны:
красная комната - одна из комнат тайлсета STS,
зелёная - из тайлсета GTS.
жёлтые комнаты - из тайлсета первого архетипа,
оранжевые - из тайлсетов второго архетипа,
между ними - комната "минибосса" из соответствующих тайлсетов ноды,
фиолетовая - комната "босса" из тайлсетов второй ноды,
голубые комнаты - особые комнаты, тупики ответвлений, задаются в архетипе,
белая - это часть функционала Special Tile Injection.
Если после этого описания просветление не наступило, ничего страшного. На практике оно гораздо проще, чем в описании.
Перейду к личному опыту.
1. Первый нюанс, с которым сталкиваешься при работе с DunGen, - это ориентация дверей: обратите внимание, что углы поворота для обычной стены - нулевые, а вот для стены под Doorway - творится "дичь" (сама дверь там тоже вывернута). Выворот идёт для того, чтобы "внешняя" сторона двери была направлена наружу (капитан, вы здесь?). К этой внешней стороне двери будет прикладываться внешняя сторона двери другой комнаты. И комнаты могут законтачиться только так. Почему не получается обойтись без лишних поворотов, я год назад не понял. Может надо ещё раз попробовать.
Прикольный функционал у Doorway - можно добавить объекты со сцены или префабы в списки для включенного и выключенного состояния двери. У меня так отключаются околодверные факелы, если при генерации лабиринта дверь заменилась на стену.
Здесь же вспомню про Local Prop Set. Смысл в том, что можно в комнату накидать кучу всякого добра, а компонент Local Prop Set в момент генерации оставить из кучи пару элементов (столько, сколько задано в его настройках). В RATOMON так определяется, сколько баннеров останется висеть на стенах.
2. Ещё один нюанс связан с общим количеством комнат в лабиринте. Допустим, длина главного маршрута - 10 комнат, от каждой комнаты может быть 0, 1 или 2 ответвления, и длина ответвлений для этого архетипа варьируется от 0 до 5. И вот сюрприз: итоговый лабиринт случайным образом может быть как 10 комнат, так и 82. В среднем, конечно будет около 40, но сбалансировать игру с таким разлётом нереально сложно. Не увеличивать же скорость бега игрока для "неудачных" генераций?
В итоге, эта задача решилась написанием кастомного кода в генерирующем лабиринт методе, автор подсказал конкретное место, куда его лучше добавить и скинул пример кода.
Помимо возможности вклиниваться в процесс генерации, у DunGen предусмотрена система пост-процессинга, в которую можно дописать свои "адаптеры". В частности, у меня после генерации лабиринта выполняются адаптеры для построения карты и миникарты. У адаптеров есть доступ к генератору, откуда можно достать всю информацию по комнатам, соединяющим их дверям и т.д. и т.п.
3. Последний кусочек личного опыта связан с ограничением видимости (culling) для комнат, которых "не видно". Но тут всё предельно скучно, в DunGen есть функционал для этого, мне пришлось дописать всего один метод, чтобы скрыть комнаты, в которые игрок ещё не заходил (а то вдруг обрадуется раньше времени).
Из незатронутого в статье, и практически не тронутого мной в работе - менеджер ключей, который закрывает части лабиринта на ключи определённых типов, которые сгенерируются в доступной части лабиринта.
Надеюсь, вам это ассет придётся по душе, и вы поделитесь своим опытом применения DunGen или аналогов в своих играх. А любопытные богачи могут уже сейчас посмотреть, как это работает в RATOMON.
Микро-иллюстрация режима, где DunGen собирает некоторую аналитику, исходя из текущих настроек лабиринта: