Алгоритм процедурної двовимірної карти з пов'язаними контурами


26

Проблема для вирішення: Створіть випадкову 2D карту підземелля для гри на основі плитки, де всі кімнати з'єднані.

Я шукаю кращих рішень, ніж ті, що зараз маю.

Моє поточне рішення полягає в тому, що я запускаю два алгоритми. Перший породжує підземелля зі своїми кімнатами. Другий переконайтесь, що всі кімнати підключені. Мені цікаво, які ще рішення можуть існувати. Швидше та / або легше і т. Д. Швидкість насправді не викликає занепокоєння, але якщо швидкість можна отримати без реальних витрат, ну це добре. Більш важливим є те, що я та інші, хто читає, можуть навчитися різним способам підходу та вирішення проблеми.

Нижче наведено моє поточне виконання. Наразі кімнати не мають виходів і виходів у будь-якому 2, 3 або 4 напрямках.

Генерація кімнат підземелля

Налаштування: встановіть поточну кімнату вгорі ліворуч.

  1. Отримайте дійсний тип приміщення для кімнати (де дійсний тип кімнати - це тип без виходів із підземелля, який має виходи, що відповідає виходу кімнати зверху та кімнаті зліва. Потрібно лише перевірити вище та вгору ліворуч через крок 2 нижче).
  2. Відкладіть кімнату і просуньте координату x на один крок. Якщо координата x перевищує ширину підземелля, встановіть координату x на 0 і просуньте координату y на один крок. Якщо y-координата перевищує висоту підземелля, ми закінчуємо.
  3. Повторіть з №1.

Потім я перевіряю, чи всі кімнати підключені. Якщо вони не всі з’єднані, я запускаю другий алгоритм, який несексуально, але напевно досить добре з точки зору планування підземелля, проходить по кімнатах і змінює їх, щоб все закінчилося до підключення.

Перевірка, чи всі кімнати підключені

Налаштування: Створіть 2D карту цілих чисел, що представляють шляхи, та ініціалізуйте записи до "необробленого" (ще не пройденого) значення -1. Встановіть ціле число індексу старту, яке відстежує поточний шлях на 1. Встановіть поточну кімнату вгорі ліворуч, додавши її до групи номерів для перевірки.

  1. Якщо стек містить кімнати для перевірки, виберіть його, щоб встановити індекс шляху кімнати до поточного індексу шляху. Якщо стек не містить жодних кімнат, збільште індекс шляху і спробуйте дістати номер, просуваючи стовпчик за стовпцем, рядок за рядком, поки ми не отримаємо кімнату, яка ще не була оброблена. Якщо приміщення не знайти, ми закінчили.
  2. Перевірте, чи є в кімнаті вихід зліва. Якщо він додав ліву кімнату до стеку, якщо вона вже не є.
  3. Повторіть крок 2 для напрямку вниз, вправо і вгору (оскільки ми використовуємо стек, який означає, що кімнати проходять в порядку годинникової стрілки, починаючи з верхнього напрямку).
  4. Повторіть з кроку 1.
  5. Якщо кількість індексів шляху більша за одиницю, є відключені кімнати.

Якщо є відключені кімнати, я групую кімнати за індексом їх шляху, отримую індекс найбільшого шляху і з'єдную всі інші кімнати з цими кімнатами. Це незавершена робота, але мій (теперішній, "брутальний") план - пройти через кожну кімнату групи кімнат (крім першої), щоб перевірити, чи є горизонтальна чи вертикальна стежка до групи номерів з більшими наборами, і якщо так, створіть там горизонтальну / вертикальну доріжку, вводячи / оновлюючи кімнати між ними. Промийте і повторіть. Потворно, так, але це щось не помітне з точки зору візуального малюнка, тому воно працює в цьому сенсі.


1
Ви перевірили "Покоління підземелля" на вікі PCG ? Це відповідає на ваші запитання?
congusbongus

@congusbongus Безумовно корисне читання. Цей генератор donjon, пов'язаний на цій сторінці, є приголомшливим. Спасибі.
user1323245

Відповіді:


33

Один з найкращих і найбільш використовуваних алгоритмів, які я бачив там, - це генерувати підземелля, використовуючи Binary Space Partitioning.

Найкраще загальне пояснення, яке я прочитав, - це знайдене в «Хроніках Доріена» (додане наприкінці для цілей резервного копіювання), оскільки пояснює процедуру, не потрапляючи в код, тим самим залишаючи реалізацію читачеві.

Ще два навчальні посібники з цієї ж теми з кодом можна знайти за адресою


Побудова дерева BSP

Починаємо з прямокутної підземелля, наповненого стіновими осередками. Ми будемо розділяти цю підземелля рекурсивно, поки кожен підземелля не матиме розмір кімнати приблизно. Розщеплення підземелля використовує цю операцію:

  • Виберіть випадковий напрямок: горизонтальне або вертикальне розщеплення
  • Виберіть випадкове положення (x для вертикалі, y для горизонталі)
  • Розбийте підземелля на дві підземелля

введіть тут опис зображення

Зараз у нас є дві підземелля А і В. Ми можемо застосувати одну і ту ж операцію до обох.

введіть тут опис зображення

Вибираючи положення розщеплення, ми повинні стежити, щоб не знаходитись занадто близько до межі підземелля. Ми повинні мати можливість розмістити кімнату всередині кожного породженого підземелля. Повторюємось, поки найнижчі підземелля не мають приблизно розмір кімнат, які ми хочемо створити.

введіть тут опис зображення

Будівництво підземелля

Тепер ми створюємо кімнату з випадковим розміром у кожному листі дерева. Звичайно, кімната повинна міститися всередині відповідної підземелля. Завдяки дереву BSP ми не можемо мати дві кімнати, що перекриваються.

введіть тут опис зображення

Щоб побудувати коридори, ми пров'язуємо всі листя дерева, з'єднуючи кожен лист до його сестри. Якщо дві кімнати мають стіни віч-на-віч, ми можемо використовувати прямий коридор. В іншому випадку ми повинні використовувати коридор у формі Z.

введіть тут опис зображення

Тепер ми встаємо на один рівень в дереві і повторюємо процес для батьківських підрегіонів. Тепер ми можемо з'єднати два підрегіони за допомогою зв’язку або між двома кімнатами, або коридором, і кімнатою, або двома коридорами.

введіть тут опис зображення

Повторюємо процес, поки не з'єднали перші два підземелля А і В

введіть тут опис зображення


Можливо, нічого не варто, що ця методика ніколи не створюватиме циклів, проте я не впевнений, чи є спосіб обійти це без додавання більше випадкових коридорів. Ще дуже гарна відповідь, +1
Vality

Це перспективний початок. Просто потрібно з'ясувати спосіб додати до нього певні петлі, але я швидше працюю над цією проблемою, ніж продовжуючи вниз по шляху, на якому я зараз перебуваю. Спасибі.
user1323245

2
Приємно! Мене зацікавив ідентифікатор, тому я зробив невелику спробу. Потрібно бути обережними, коли буде використано випадкові інакше занадто дивні результати. І мені цікаво, чи не слід коригувати коридорами під час рекурсивного розколу, бо я не бачу простого способу побудови коридорів із дерева. У будь-якому разі для всіх, хто цікавиться, скрипка знаходиться тут: jsfiddle.net/gamealchemist/xt57zwb8
GameAlchemist

Хоча я вважаю це дещо проблематичним у повторюваній насіннєвій процедурі у великих середовищах. Це, мабуть, один з найкращих методів, які я коли-небудь бачив для такого роду поколінь, за умови, що ви генеруєте весь свій рівень відразу. Я поставив +1 цьому
Той бездомний хлопець

4

Метод BSP , мабуть, є найпопулярнішим методом генерації підземелля, але це не єдиний.

Для повноти я поясню генератор, який працював на мене . Я повинен визнати , що я не пам'ятаю , де я читав про це , так що я просто скажу , що це не мій винахід ( стара стаття по Jamis Buck звучить дуже знайомо).

Лабіринт з кімнатами

Основна ідея полягає в тому, що підземелля - це лабіринт із кімнатами. Отже, перший крок для цього алгоритму - генерувати лабіринт :

Лабіринт, згенерований за допомогою варіації алгоритму Еллера

Наступний крок - зробити її рідкісною (видалити тупики):

Зробіть рідкісні: видаліть тупики

Крок №3 полягає в тому, щоб додати певні петлі (зробити це не ідеальним ), але я пропускаю зображення, тому що це ледь помітно (мені не знадобився ідеальний лабіринт, тому я взяв кілька ярликів алгоритму генерації лабіринту, так що це вже до цього моменту мали петлі).

Потім для кроку 4 нам потрібно видалити окремі клітини:

Видаліть ізольовані клітини

На даний момент ми закінчили коридори, і ми готові додати кімнати. Для цього ми робимо наступне:

  1. Створіть набір кімнат (ширина та висота)
  2. Для кожної кімнати ми повторюємо всі можливі місця та визначаємо найкраще місце.
    • Найкраще розташування обчислюється додаванням ваги умовам (наприклад, примикання до коридору).
  3. Розміщуємо кімнати.

Поки наша підземелля виглядатиме так: Номери додані

Останній крок - додавання прикрас.

Намалюйте двері та номери кімнат

Кілька заключних думок

  • Я використав стерту версію алгоритму Еллера .
  • Різні алгоритми лабіринту можуть спричинити різну текстуру. Ви можете віддати перевагу іншому алгоритму. Наприклад, на наступному зображенні показані різні текстури, отримані в результаті "Бінарного дерева" (діагональне зміщення) та варіації алгоритмів "Рекурсивний поділ" (довгі коридори): Бінарне дерево проти псевдорекурсивного відділу

2
Хороший матеріал. Я шукаю різні способи зробити це, оскільки використання різних алгоритмів для різних рівнів може зробити гру ще більш універсальною.
user1323245
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.