Algorithmus für prozedurale 2D-Karte mit verbundenen Pfaden

26

Zu lösendes Problem: Erstellen Sie eine zufällige 2D-Dungeon-Karte für ein Spiel auf Kachelbasis, bei dem alle Räume miteinander verbunden sind.

Ich suche nach besseren Lösungen als bisher.

Meine aktuelle Lösung ist, dass ich zwei Algorithmen ausführe. Der erste erzeugt den Kerker mit seinen Räumen. Der zweite stellt sicher, dass alle Räume miteinander verbunden sind. Ich bin gespannt, welche anderen Lösungen es gibt. Schneller und / oder einfacher usw. Geschwindigkeit ist nicht wirklich ein Problem, aber wenn Geschwindigkeit ohne wirkliche Kosten gewonnen werden kann, ist das eine gute Sache. Wichtiger ist, dass ich und andere, die lesen, verschiedene Methoden kennenlernen, um das Problem anzugehen und zu lösen.

Nachfolgend finden Sie meine aktuelle Implementierung. Zimmer haben derzeit keine Ausgänge oder Ausgänge in 2, 3 oder 4 Richtungen.

Die Dungeonräume generieren

Setup: Stellen Sie den aktuellen Raum auf den oberen linken Raum ein.

  1. Holen Sie sich einen gültigen Zimmertyp für den Raum (wobei der gültige Zimmertyp ein Typ ist, der keine Ausgänge aus dem Dungeon hat und Ausgänge hat, die mit den Ausgängen des Raums oben und des Raums links übereinstimmen) Links wegen Schritt 2 unten).
  2. Stellen Sie den Raum ab und verschieben Sie die x-Koordinate um einen Schritt. Wenn die x-Koordinate die Dungeonbreite überschreitet, setzen Sie die x-Koordinate auf 0 und verschieben Sie die y-Koordinate um einen Schritt. Wenn die y-Koordinate die Dungeonhöhe überschreitet, sind wir fertig.
  3. Wiederholen Sie ab # 1.

Ich überprüfe dann, ob alle Räume verbunden sind. Wenn nicht alle miteinander verbunden sind, führe ich einen zweiten Algorithmus aus, der auf eine nicht sexy, aber definitiv gute Art und Weise in Bezug auf die Dungeon-Anordnung die Räume durchläuft und sie so ändert, dass sie alle enden verbunden zu sein.

Überprüfen, ob alle Räume verbunden sind

Setup: Erstellen Sie eine 2D-Karte mit Ganzzahlen, die Pfade darstellen, und initialisieren Sie die Einträge mit dem Wert -1 (noch nicht verarbeitet). Legen Sie eine Index-Ganzzahl für den Startpfad fest, die den aktuellen Pfad auf 1 verfolgt. Legen Sie den aktuellen Raum in den oberen linken Raum fest, indem Sie ihn zu einem Stapel von zu überprüfenden Räumen hinzufügen.

  1. Wenn der Stapel zu überprüfende Räume enthält, setzen Sie den Pfadindex des Raums auf den aktuellen Pfadindex. Wenn der Stapel keine Räume enthält, erhöhen Sie den Pfadindex und versuchen Sie, einen Raum zu erhalten, indem Sie spaltenweise, zeilenweise vorrücken, bis wir einen Raum erhalten, der noch nicht verarbeitet wurde. Wenn kein Platz gefunden werden kann, sind wir fertig.
  2. Überprüfen Sie, ob der Raum links einen Ausgang hat. Wenn es den linken Raum zum Stapel hinzugefügt hat, ist er dort nicht bereits vorhanden.
  3. Wiederholen Sie Schritt 2 für die Richtungen nach unten, rechts und oben (da wir einen Stapel verwenden, bei dem die Räume im Uhrzeigersinn durchlaufen werden, beginnend mit der Richtung nach oben).
  4. Wiederholen Sie ab Schritt 1.
  5. Wenn die Anzahl der Pfadindizes größer als eins ist, gibt es getrennte Räume.

Wenn es getrennte Räume gibt, gruppiere ich die Räume nach ihrem Pfadindex, erhalte den Index des größten Pfades und verbinde alle anderen Räume mit diesen Räumen. Dies ist eine laufende Arbeit, aber mein (aktueller, "brutaler") Plan ist es, in jedem Raum einer Raumgruppe (mit Ausnahme der ersten) zu prüfen, ob ein horizontaler oder vertikaler Pfad zur biggeset - Raumgruppe vorhanden ist, und Wenn ja, erstellen Sie dort einen horizontalen / vertikalen Pfad, indem Sie die Räume dazwischen einfügen / aktualisieren. Spülen und wiederholen. Hässlich, ja, aber es ist etwas, das sich in Bezug auf das visuelle Muster nicht bemerkbar macht, also funktioniert es in diesem Sinne.

user1323245
quelle
1
Hast du "Dungeon Generation" im PCG Wiki ausgecheckt ? Beantwortet es Ihre Fragen?
Congusbongus
@congusbongus Nützliche Lektüre sicher. Der Donjon-Generator, der auf dieser Seite verlinkt ist, ist fantastisch. Vielen Dank.
user1323245

Antworten:

33

Einer der besten und am häufigsten verwendeten Algorithmen, den ich dort gesehen habe, ist das Generieren von Dungeons mit Binary Space Partitioning.

Die beste allgemeine Erklärung, die ich gelesen habe, ist die in The Chronicles of Doryen (am Ende zu Sicherungszwecken beigefügt), weil sie den Vorgang erklärt, ohne in den Code einzusteigen , und die Implementierung dem Leser überlässt.

Zwei weitere Tutorials zum selben Thema mit Code finden Sie unter


Erstellen des BSP-Baums

Wir beginnen mit einem rechteckigen Kerker voller Wandzellen. Wir werden diesen Dungeon rekursiv teilen, bis jeder Sub-Dungeon ungefähr die Größe eines Raums hat. Die Dungeonaufteilung verwendet diese Operation:

  • Wählen Sie eine zufällige Richtung: horizontale oder vertikale Aufteilung
  • Wähle eine zufällige Position (x für vertikal, y für horizontal)
  • Teilen Sie den Dungeon in zwei Sub-Dungeons

Bildbeschreibung hier eingeben

Jetzt haben wir zwei Sub-Dungeons A und B. Wir können dieselbe Operation auf beide anwenden.

Bildbeschreibung hier eingeben

Bei der Auswahl der Spaltposition müssen wir darauf achten, dass wir uns nicht zu nahe an der Kerkergrenze befinden. Wir müssen in der Lage sein, einen Raum in jedem generierten Sub-Dungeon zu platzieren. Wir wiederholen, bis die niedrigsten Sub-Dungeons ungefähr die Größe der Räume haben, die wir erzeugen möchten.

Bildbeschreibung hier eingeben

Den Kerker bauen

Jetzt erstellen wir einen Raum mit zufälliger Größe in jedem Blatt des Baumes. Natürlich muss sich der Raum im entsprechenden Sub-Dungeon befinden. Dank des BSP-Baums können wir keine zwei überlappenden Räume haben.

Bildbeschreibung hier eingeben

Um Korridore zu bauen, durchlaufen wir alle Blätter des Baumes und verbinden jedes Blatt mit seiner Schwester. Wenn die beiden Räume gegenüberliegende Wände haben, können wir einen geraden Korridor benutzen. Ansonsten müssen wir einen Z-förmigen Korridor verwenden.

Bildbeschreibung hier eingeben

Jetzt steigen wir eine Ebene im Baum auf und wiederholen den Vorgang für die Vater-Unterregionen. Jetzt können wir zwei Unterregionen mit einer Verbindung verbinden, entweder zwischen zwei Räumen oder einem Korridor und einem Raum oder zwei Korridoren.

Bildbeschreibung hier eingeben

Wir wiederholen den Vorgang, bis wir die ersten beiden Sub-Dungeons A und B verbunden haben

Bildbeschreibung hier eingeben

Reefaktor
quelle
Es mag nichts wert sein, dass diese Technik niemals Schleifen erzeugt, aber ich bin mir nicht sicher, ob es einen Weg gibt, dies zu umgehen, ohne weitere zufällige Korridore hinzuzufügen. Immer noch sehr gute Antwort, +1
Vality
Dies ist ein vielversprechender Start. Ich muss nur einen Weg finden, um ein paar Schleifen hinzuzufügen, aber ich arbeite lieber an diesem Problem, als den Weg fortzusetzen, auf dem ich mich gerade befinde. Vielen Dank.
user1323245
2
Nett ! Die ID hat mich interessiert, also habe ich einen kleinen Versuch unternommen. Sie müssen vorsichtig sein, wenn Sie zufällige Ergebnisse verwenden, da sonst zu seltsame Ergebnisse folgen. Und ich frage mich, ob die Korridore während der rekursiven Teilung nicht richtig behandelt werden sollten, weil ich keine einfache Möglichkeit sehe, Korridore aus dem Baum heraus zu bauen. Wie auch immer, für alle Interessierten ist Fiddle hier: jsfiddle.net/gamealchemist/xt57zwb8
GameAlchemist
Während ich dies bei wiederholbarer Seed-Prozeduralisierung über große Umgebungen etwas problematisch finde. Es ist wahrscheinlich eine der besten Methoden, die ich je für diese Art von Generation gesehen habe, vorausgesetzt, Sie generieren Ihr gesamtes Level auf einmal. I +1 this
That Homeless Guy
4

Die BSP-Methode ist anscheinend die beliebteste Methode zum Generieren von Dungeons, aber nicht die einzige.

Der Vollständigkeit halber erkläre ich den Generator, der für mich funktioniert hat . Ich muss zugeben, dass ich mich nicht mehr daran erinnere, wo ich darüber gelesen habe, also sage ich nur, dass es nicht meine Erfindung ist (ein alter Artikel von Jamis Buck kommt mir sehr bekannt vor).

Ein Labyrinth mit Räumen

Die Grundidee ist, dass ein Dungeon ein Labyrinth mit Räumen ist. Der erste Schritt für diesen Algorithmus besteht darin, ein Labyrinth zu generieren :

Labyrinth generiert mit einer Variation des Eller-Algorithmus

Der nächste Schritt ist, es sparsam zu machen (Sackgassen entfernen):

Sparsam machen: Sackgassen entfernen

Schritt Nummer 3 besteht darin, einige Schleifen hinzuzufügen ( nicht perfekt zu machen ), aber ich werde das Bild überspringen, weil es kaum wahrnehmbar ist (ich brauchte kein perfektes Labyrinth, also habe ich ein paar Abkürzungen für den Algorithmus zur Labyrinthgenerierung gemacht, also schon hatte Schleifen zu diesem Zeitpunkt).

Dann müssen wir für Schritt 4 isolierte Zellen entfernen:

Isolierte Zellen entfernen

An diesem Punkt sind wir mit den Korridoren fertig und wir sind bereit, Räume hinzuzufügen. Dafür machen wir folgendes:

  1. Generieren Sie eine Reihe von Räumen (Breite und Höhe)
  2. Für jeden Raum durchlaufen wir alle möglichen Standorte und bestimmen den besten Standort.
    • Der beste Standort wird durch Hinzufügen eines Gewichts zu den Bedingungen (z. B. der Nähe zu einem Korridor) berechnet.
  3. Wir platzieren die Räume.

Bisher wird unser Dungeon so aussehen: Zimmer hinzugefügt

Der letzte Schritt ist das Hinzufügen von Dekorationen.

Zeichnen Sie Türen und Zimmernummern

Einige abschließende Gedanken

  • Ich habe eine abgespeckte Version des Eller-Algorithmus verwendet .
  • Unterschiedliche Labyrinthalgorithmen können zu unterschiedlichen Texturen führen. Möglicherweise bevorzugen Sie einen anderen Algorithmus. Das folgende Bild zeigt beispielsweise verschiedene Texturen, die sich aus "Binary Tree" (Diagonal Bias) und einer Variation von "Recursive Division" (Long Corridors) -Algorithmen ergeben: Binärer Baum gegen pseudo-rekursive Division
Roflo
quelle
2
Gutes Zeug. Ich habe nach verschiedenen Möglichkeiten gesucht, um dies zu tun, da die Verwendung verschiedener Algorithmen für verschiedene Level das Spiel noch vielseitiger machen kann.
user1323245