Как мы делаем процедурную генерацию локаций
Технический пост. Если неинтересно, смело скипайте.
Как я писал тут, ключевая сложность в разработке Агентов - это контент и его разнообразие.
Один из двух способов это решить - процедурная генерация локаций.
За основу взяли ассет DunGen, из коробки он очень хорош и многое умеет.
Вкратце: заранее вручную создаёте префабы комнат.
В комнате задаёте сокеты дверей - места, где может быть (или не быть) соединение с соседними комнатами.
Дальше DunGen собирает локацию из этих комнат в рандомном порядке, но так, чтобы они не пересекались.
Плюс можно задавать «Flow» - правила создания локации.
Например, что определённый вид комнат появится только в конце или что какие-то комнаты не могут соединяться.
В чём тогда сложность? Вроде взяли ассет, и всё.
Всё, увы, намного сложнее.
1. Прежде всего, у нас ко-оп игра, а DunGen из коробки вообще ничего не знает про нетворк-логику.
То есть в рантайме у разных игроков получаются разные локации.
Это фиксится несложно.
К счастью, создание локации детерминированное: рандомизация использует цифровой seed.
Если seed одинаковый, локация будет такой же.
Так что достаточно сгенерировать seed у хоста и синхронизировать для всех клиентов.
2. Дальше идёт сложность с дверьми.
Двери - это интерактивный объект, их можно открывать и закрывать.
А значит, у них network-поведение, а не monobehaviour.
И просто так засунуть нетворк-объект в генерацию DunGen, не связанную с Mirror и пр., нельзя.
Как решается: после генерации доп. скрипт у хоста собирает все двери, выключает их визуал и коллайдеры и спавнит на их месте такие же, но уже нетворк-двери с интерактивной логикой.
3. Но ещё есть ключи.
Помимо открытия/закрытия, двери ещё могут быть запертыми, и к ним нужны ключи.
У DunGen есть своя логика «запирания» дверей, но она слишком глубоко завязана на не-нетворк объекты.
Поэтому её выкинули и сделали свою: после спавна нетворк-дверей скрипт-менеджер проходит по всем, делает некоторые запертыми по весам вероятности и спавнит ключи на локации.
4. А ещё есть спавн объектов.
Мы хотим, чтобы в комнатах спавнились разные объекты: тулзы для игрока вроде оружия, препятствия.
Но при этом мы хотим знать, где именно в данжене находится объект: в основном пути или в ответвлении и как далеко он зашёл (на старте локации не хотим давать что-то супер крутое).
Для этого скрипт-менеджер собирает спавн-точки, в которые прокинуты конфиги со списком возможных предметов и их вероятностей.
И для каждого предмета определяется, в какой комнате он заспавнился, исходя из этого корректируются вероятности.
5. И не забыть про вентиляционные шахты.
Отдельная фишка, которую мы хотим, это шорт-каты вентиляций для обхода запертых дверей и охраны.
Такого функционала у DunGen нет, поэтому поверх него идёт доп. слой: после генерации локации выбираются пары точек возможной вентиляции, строится 3D-вокселизированная сетка и ищутся пути между этими точками.
Путь при этом должен обходить комнаты и другие вент-шахты.
Когда путь найден, по нему строится сплайн с мешем вент-шахты.
6. Ну и вишенка на торте, это запекание света.
DunGen собирает локацию на сцене из префабов комнат.
А запекать свет в префаб в Unity по умолчанию нельзя, только в самой сцене.
Чтобы запечь свет в префабы комнат отдельно, мы нашли вот такой бесплатный хелпер
Он позволяет запечь свет и хранить лайтмапы в самом префабе комнаты, чтобы потом префаб можно было перетащить на другую сцену.
Помимо этого, есть проблема с лайтпробами, точками, которые передают свет для динамических объектов.
Их тоже нельзя засунуть в префаб, они живут только на сцене.
Поэтому мы дописали хелпер, и теперь он также сохраняет координаты и параметры всех лайтпроб комнаты в сам префаб.
Затем, когда DunGen соберёт локацию, заранее разложенные на сцене «пустые» лайтпробы переставляются в префабы комнат исходя из их настроек.
А в Unreal все это было бы не нужно и можно просто включить реалтайм свет :(
В общем, процесс процедурной генерации не самый простой
Post #85
853