Хабрахабр

[Перевод] Как генерируются подземелья в Enter The Gungeon

В последнее время я много играл в Enter The Gungeon. Это потрясающая, ужасно сложная игра в жанре bullet hell, сильно напомнившая мне Binding of Isaac. Но чем больше я играл в неё, тем больше осознавал малозаметную гениальность дизайна подземелий.

Существует много процедурных генераторов, создающих логичные схемы уровней, обеспечивающие правильный темп игры и вознаграждение игроков, и есть другие генераторы, создающие уровни с петли и компактные схемы. Но редко можно встретить в одной игре оба типа. Единственная известная мне игра, в которой была попытка реализации подобного — это Unexplored.

В этой статье я поделюсь с вами тем, что мне удалось найти.
Поэтому я, естественно, запустил декомпилятор, чтобы Gungeon раскрыла мне все свои секреты.

На первый взгляд уровни Gungeon кажутся довольно простыми. Вот типичный пример карты.

Карта типичного уровня 1

Если вы уткнулись в длинный тупик, то для быстрого возврата в комнаты можно пользоваться телепортами. Игрок начинает со входа , пробегает через сундуки и лавочника , чтобы собрать лут, а затем, наконец, побеждает босса . При продвижении к следующим уровням игры игрок видит тот же паттерн снова и снова, только этапы становятся больше. Очевидно, что отдельные комнаты созданы вручную, и населены различными врагами, которых нужно расстреливать.

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

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

Красная линия — это односторонний коридор. Если вы хотите попасть в комнату с сундуком, то нужно проделать долгий путь. Основное большинство сундуков расположено или в конце односторонней петли, или достаточно глубоко внутри уровня, что заставляет игрока с боем проходить множество комнат, просто достичь сундука. Без риска нет награды.

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

Обычные комнаты (Normal room) — это случайно выбираемые комнаты с врагами, комнаты-перекрёстки или большие комнаты с несколькими выходами. Награды (Reward) и босса (boss) объяснять не нужно. Здесь не показаны «соединительные» комнаты, то есть комнаты без врагов, часто с природными опасностями. Остальные комнаты или задаются заранее, или выбираются из особой таблицы комнат.

На уровнях Hollow их меньше всех (всего 4), а в Gungeon Proper — больше всех (8). В Gungeon существует довольно мало таких схем, называемых «потоками» (flow). Это может быть гигантская петля, или важная развилка из множества путей, или необходимость добраться до лавки, чтобы пройти уровень. Это не простые схемы, их дизайн создан на основе определённой особенности, которую можно заметить при многократном прохождении. Я подготовил полный список схем, который можно скачать отсюда. Они настолько заметны, что спидраннеры заметили различия и составили графики, по которым можно максимально быстро найти босса.

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

Это структура данных «граф», то есть в ней хранятся взаимосвязи комнат, но не их расположение. Процесс начинается со случайного выбора файла потока наподобие показанного выше. Соединения имеют направление — каждая схема потока начинается с корневого узла, а затем образует дерево дочерних узлов. Каждая комната содержит метаданные о типе комнаты и соединениях, которые она должна иметь. Я думаю, что это в основном вызвано особенностями разработки игры, но это упрощает процедуры анализа карты, ведь все петли имеют чётко определённые начало и конец. Затем дополнительные соединения разбивают структуру дерева для создания петель.

Преобразование потока

Файл потока может преобразовываться ограниченным количеством способов. Во-первых, некоторые специфические комнаты заменятся сериями комнат случайной длины. Эта функция используется только в поздних, более крупных уровнях. Кроме того, некоторые части файла потока имеют альтернативные пути, и один из них выбирается случайным образом. Эта функция используется только дважды.

Эта функция довольно гибка и используется для множества разных целей. Затем «инъектируются» ещё несколько дополнительных узлов.

Например, секретные комнаты обычно создаются в тупиках, но имеют вероятность 1/5 быть присоединёнными к любой комнате. Каждая «инъекция» содержит данные, определяющие, какой тип объекта должен быть вставлен, где он должен быть вставлен, вероятность создания и любые условия, которые должны быть выполнены (например, наличие master round, высокого curse или то, что игрок пока не спас персонажа). Они имеют вероятность появления 90% и не требуют никаких дополнительных условий.

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

Одна из тюремных камер, которая может быть инъектирована в уровень

В основном это зависит от текущего этапа и необходимого типа комнаты. На этом же этапе генератор выбирает конкретную комнату для каждого узла. Существует огромный список комнат — почти 300 для первого этапа — но генератор старается не выбирать одинаковую комнату дважды.

Их комнаты выбираются позже, пока создаётся схема. Узлы типа «соединитель» работают иначе. Часто это длинные и узкие комнаты, поэтому очень важно выбрать комнату с правильной ориентацией.

Составные объекты

После завершения создания потока он разбивается на «составные объекты». Каждый составной объект — это или отдельная петля из комнат, или набор связанных комнат без петель (т.е. дерево). Это реализуется поиском наименьшей петли на карте и вырезанием её как составного объекта. Операция повторяется, пока на карте не останется петель. Остальная часть карты становится набором разделённых деревьев и соединениями между отдельными составными объектами.

Тот же самый поток после инъектирования и разделения на составные объекты

Схема составных объектов

Затем каждый составной объект создаётся по отдельности, на отдельной карте. Соединены вместе они будут позже.

Затем к схеме одна за другой добавляются комнаты выбором пары выходов, один из которых относится к новой комнате, а другой — к имеющейся схеме. Для планирования составного объекта первая комната размещается в произвольном месте. Затем новая комната размещается так, чтобы её выход непосредственно соединялся с выходом из предыдущей комнаты. Выходы — это заранее заданные локации в метаданных каждой комнаты. Потом процесс повторяется.

Алгоритм выбирает только те пары выходов, которые приводят к появлению новой комнаты без пересечения с предыдущими. Если конкретнее, то составные объекты деревьев размещаются при помощи обхода дерева поиском в глубину. Если разместить комнату невозможно, то он вернётся назад и заново сгенерирует выбор комнат, повторяя этот процесс до трёх раз. В общем случае алгоритм предпочитает выбирать выходы, расположенные далеко от уже существующих.

Для начала пары выходов выбираются случайно (предпочтение отдаётся противоположным стенам, восток-запад или север-юг). Тем временем составные объекты-петли размещаются добавлением элементов из петли по очереди с обеих сторон линии. После создания всех комнат алгоритму нужно добавить ещё одно соединение между последними двумя комнатами. Когда петля создана наполовину, она начинает отдавать предпочтение парам выходов, сближающим два разомкнутых края петли. При возможности он конструирует между этими выходами небольшую прямоугольную комнату. Он выбирает ещё одну пару выходов. Длина коридора должна составлять от 4 до 30 единиц (в шахтах до 50). В противном случае он выполняет поиск пути между выходами и создаёт «комнату», представляющую собой просто узкий коридор.

Окончательная сборка

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

Та же самая карта в виде составных объектов перед окончательной сборкой

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

Остаётся только выбрать врагов и декорации для комнат, и это уже совершенно другая тема. И на этом создание схемы уровня заканчивается.

В заключение

Похоже, что основная цель разработчиков заключалась в создании процедурного генератора, обеспечивающего удовлетворительный игровой процесс. Очевидно, что для его правильной реализации им пришлось выполнить множество итераций — я нашёл большой объём кода генерации, который, похоже, не используется, потому что разработчики в поисках совершенства изменяли свою процедурную формулу.

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

Более конкретным всё становится только позже. Как и в случае с моим исследованием генерации уровней Diablo 1, меня поразило, насколько эффективно оказывается генерировать часть подземелья в абстрактном виде — в данном случае это граф без информации о расположении. Благодаря абстрагированию от подробностей размещения комнат она позволяет контролировать стиль прохождения игры и масштаб уровня. Функция «инъектирования» была бы попросту невозможной, если бы мы сразу перешли к работе с тайловой картой.

Unity стимулирует активно применять управляемый данными подход. Кроме того, меня восхитила расширяемость системы в целом. Должно быть, это стало сильным подспорьем, потому что Dodge Roll уже выпустила несколько бесплатных DLC и, без всяких сомнений, поддерживает создание модов. Добавление новой комнаты, схемы или даже особого поведения возможно реализовать простым добавлением в соответствующие таблицы новых объектов.

Бонусы

Изучение этого генератора стало моим первым шансом на исследование создания профессиональной игры в Unity. Разработчики из Dodge Roll постарались и написали хороший код. Он хорошо читаем, а в некоторых местах довольно забавен — похоже, их любовь к каламбурам распространилась и на код. Мне понравились вот такие:

  • Движок жидкостей в игре называется DeadlyDeadlyGoopManager
  • Код генерации подземелий называется Dungeonator
  • Различные этапы называются CASTLEGEON/GUNGEON/MINEGEON/CATACOMBGEON и т.д. Интересно, вдохновлялись ли разработчики Diablo 1, в которой используется очень похожая схема?
  • Буквально каждая комната имеет своё название, обычно в виде каламбура (или в честь какого-то Джо; вероятно, это художник с большим самомнением).

Также я заметил, что изначально у студии были планы на этапы в тематике космоса, джунглей и Дикого Запада. Увы, им не суждено было появиться. Dodge Roll решила, что её работа над Gungeon завершена. Я буду ждать их следующую игру и надеюсь, что они вложат в неё столько же любви и внимания.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть