Эта страница смотрится лучше со включённым JavaScript

DunGen для RATOMON

 ·  ☕ 5 min read

Дисклеймер: это не туториал, это краткое описание моего опыта работы с DunGen и пары нюансов, с которыми столкнулся при использовании его в RATOMON. У этого ассета одна из самых понятных инструкций, да и в целом он построен очень логично. По крайней мере тот функционал, который я использовал, недоумения не вызвал ни разу.

DGR

DunGen - это генератор лабиринтов, составленных из комнат* согласно набору правил. Некоторые правила задаются глобально для всего лабиринта сразу, например, количество комнат по главному** маршруту. Другие - локально, например, количество внутрикомнатного контента. Есть вещи, которые можно настроить и так, и так, например, количество возможных ответвлений от главного маршрута может быть задано для каждой комнаты или для всего лабиринта.

В какой-то момент автор переименовал “комнаты” в “тайлы” (набор комнат - в “TileSet”, соответственно), создав путаницу с родными юнитёвыми тайлами и тайлсетами. В чём была причина переименования, я не знаю.
Предполагается, что в лабиринте есть комната-начало, с неё начинается генерация (с неё, скорее всего, стартует игрок). И есть комната-цель, которая может иметь важную игровую роль, может не иметь, но комната-цель обязательно будет создана. Т.е. минимальный лабиринт будет состоять из двух комнат, комнаты-начала и комнаты-цели.
Главный маршрут создаётся в первую очередь, а потом уже генерируются ответвления, если они предусмотрены правилами.

Main Path

Итоговый лабиринт может выглядеть вот так. Главный маршрут показан тонкой красной линией.

Кратко, формулы генерации можно так записать (Внимание! Сейчас будет непонятно):

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 - это самое высокоуровневое описание лабиринта. Тут описывается, сколько всего комнат будет в главном маршруте, будет ли количество ответвлений считаться глобально для всего лабиринта или для каждой комнаты отдельно и самое интересное: из каких составных частей лабиринт состоит.

Dungeon Flow

Ещё раз приведу картинку с главным маршрутом, чтобы не листать туда-сюда:
Main Path

Здесь разными цветами показаны:
красная комната - одна из комнат тайлсета STS,
зелёная - из тайлсета GTS.
жёлтые комнаты - из тайлсета первого архетипа,
оранжевые - из тайлсетов второго архетипа,
между ними - комната “минибосса” из соответствующих тайлсетов ноды,
фиолетовая - комната “босса” из тайлсетов второй ноды,
голубые комнаты - особые комнаты, тупики ответвлений, задаются в архетипе,
белая - это часть функционала Special Tile Injection.

Если после этого описания просветление не наступило, ничего страшного. На практике оно гораздо проще, чем в описании.

Перейду к личному опыту.

1.

Первый нюанс, с которым сталкиваешься при работе с DunGen, - это ориентация дверей: обратите внимание, что углы поворота для обычной стены - нулевые, а вот для стены под Doorway - творится “дичь” (сама дверь там тоже вывернута). Выворот идёт для того, чтобы “внешняя” сторона двери была направлена наружу (капитан, вы здесь?). К этой внешней стороне двери будет прикладываться внешняя сторона двери другой комнаты. И комнаты могут законтачиться только так. Почему не получается обойтись без лишних поворотов, я год назад не понял. Может надо ещё раз попробовать.

Doorway Orientation

Прикольный функционал у Doorway - можно добавить объекты со сцены или префабы в списки для включенного и выключенного состояния двери. У меня так отключаются околодверные факелы, если при генерации лабиринта дверь заменилась на стену.

Doorway Torches

Здесь же вспомню про Local Prop Set. Смысл в том, что можно в комнату накидать кучу всякого добра, а компонент Local Prop Set в момент генерации оставить из кучи пару элементов (столько, сколько задано в его настройках). В RATOMON так определяется, сколько баннеров останется висеть на стенах.

Local Prop Set

2.

Ещё один нюанс связан с общим количеством комнат в лабиринте. Допустим, длина главного маршрута - 10 комнат, от каждой комнаты может быть 0, 1 или 2 ответвления, и длина ответвлений для этого архетипа варьируется от 0 до 5. И вот сюрприз: итоговый лабиринт случайным образом может быть как 10 комнат, так и 82. В среднем, конечно будет около 40, но сбалансировать игру с таким разлётом нереально сложно. Не увеличивать же скорость бега игрока для “неудачных” генераций?
В итоге, эта задача решилась написанием кастомного кода в генерирующем лабиринт методе, автор подсказал конкретное место, куда его лучше добавить и скинул пример кода.

Помимо возможности вклиниваться в процесс генерации, у DunGen предусмотрена система пост-процессинга, в которую можно дописать свои “адаптеры”. В частности, у меня после генерации лабиринта выполняются адаптеры для построения карты и миникарты. У адаптеров есть доступ к генератору, откуда можно достать всю информацию по комнатам, соединяющим их дверям и т.д. и т.п.

3.

Последний кусочек личного опыта связан с ограничением видимости (culling) для комнат, которых “не видно”. Но тут всё предельно скучно, в DunGen есть функционал для этого, мне пришлось дописать всего один метод, чтобы скрыть комнаты, в которые игрок ещё не заходил (а то вдруг обрадуется раньше времени).

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

Надеюсь, вам это ассет придётся по душе, и вы поделитесь своим опытом применения DunGen или аналогов в своих играх. А любопытные богачи могут уже сейчас посмотреть, как это работает в RATOMON.

Микро-иллюстрация режима, где DunGen собирает некоторую аналитику, исходя из текущих настроек лабиринта:

Share on