Algoritmo per la mappa procedurale 2D con percorsi collegati


26

Problema da risolvere: genera una mappa sotterranea 2D casuale per un gioco basato su tessere in cui tutte le stanze sono collegate.

Sto cercando soluzioni migliori di quelle che ho attualmente.

La mia soluzione attuale è che eseguo due algoritmi. Il primo genera la prigione con le sue stanze. Il secondo si assicura che tutte le stanze siano collegate. Sono curioso di sapere quali altre soluzioni possano esistere. Più veloce e / o più facile, ecc. La velocità non è realmente un problema, ma se la velocità può essere ottenuta senza costi reali, allora è una buona cosa. Più importante è che io e gli altri che leggiamo, possiamo imparare diversi modi di affrontare e risolvere il problema.

Di seguito sono riportate le mie attuali implementazioni. Le camere attualmente non hanno uscite o uscite in nessuna delle 2, 3 o 4 direzioni.

Generare le stanze dei sotterranei

Impostazione: imposta la stanza corrente nella stanza in alto a sinistra.

  1. Ottieni un tipo di stanza valido per la stanza (dove il tipo di stanza valido è un tipo senza uscite fuori dal sotterraneo e con uscite che corrispondono alle uscite della stanza sopra e della stanza a sinistra. Devi solo controllare sopra e verso lasciato a causa del passaggio 2 di seguito).
  2. Metti giù la stanza e fai avanzare la coordinata x di un passo. Se la coordinata x supera la larghezza del dungeon, imposta la coordinata x su 0 e avanza di un passo sulla coordinata y. Se la coordinata y supera l'altezza del sotterraneo, abbiamo finito.
  3. Ripeti dal n. 1.

Poi controllo per vedere se tutte le stanze sono collegate Se non sono tutte collegate, eseguo un secondo algoritmo che, in modo non sexy ma decisamente abbastanza buono in termini di layout del sotterraneo, attraversa le stanze e le cambia in modo che tutto finisca essere connesso.

Verifica se tutte le stanze sono collegate

Impostazione: crea una mappa 2D di numeri interi che rappresentano i percorsi e inizializza le voci su un valore "non elaborato" (non ancora attraversato), -1. Impostare un numero intero indice del percorso iniziale che tiene traccia del percorso corrente su 1. Impostare la stanza corrente nella stanza in alto a sinistra aggiungendola a una pila di stanze da controllare.

  1. Se la pila contiene stanze da controllare, aprila imposta l'indice del percorso della stanza sull'indice del percorso corrente. Se la pila non contiene stanze, aumenta l'indice del percorso e prova a ottenere una stanza avanzando colonna per colonna, riga per riga, fino a quando non otteniamo una stanza che non è stata ancora elaborata. Se non è possibile trovare spazio, abbiamo finito.
  2. Controlla se la stanza ha un'uscita a sinistra. Se ha aggiunto la stanza sinistra alla pila se non è già presente.
  3. Ripetere il passaggio 2 per le direzioni verso il basso, a destra e in alto (poiché stiamo usando una pila che significa che le stanze vengono attraversate in senso orario, iniziando dalla direzione superiore).
  4. Ripetere dal passaggio 1.
  5. Se il conteggio degli indici di percorso è maggiore di uno, ci sono stanze disconnesse.

Se ci sono stanze disconnesse, raggruppo le stanze in base all'indice del percorso, ottengo l'indice del percorso più grande e collego tutte le altre stanze a quelle stanze. Questo è un lavoro in corso, ma il mio piano (attuale, "brutale") è quello di passare attraverso ogni stanza in un gruppo di stanze (tranne il primo) per vedere se c'è un percorso orizzontale o verticale al gruppo di stanze del biggeset, e in tal caso, creare un percorso orizzontale / verticale lì iniettando / aggiornando le stanze tra di loro. Risciacqua e ripeti. Brutto, sì, ma è qualcosa che non sarà evidente in termini di modello visivo, quindi funziona in quel senso.


1
Hai verificato "Dungeon Generation" sul wiki del PCG ? Risponde alle tue domande?
congusbongus,

@congusbongus Lettura utile di sicuro. Quel generatore di donjon collegato su quella pagina è fantastico. Grazie.
user1323245

Risposte:


33

Uno degli algoritmi migliori e più utilizzati che ho visto là fuori è la generazione di dungeon utilizzando il partizionamento dello spazio binario.

La migliore spiegazione generale che ho letto è quella contenuta in The Chronicles of Doryen (allegata alla fine per scopi di backup) perché spiega la procedura senza entrare nel codice, lasciando così l'implementazione al lettore.

Altre due esercitazioni sullo stesso argomento, con codice, sono disponibili all'indirizzo


Costruire l'albero BSP

Iniziamo con un sotterraneo rettangolare pieno di celle a muro. Divideremo questo sotterraneo in modo ricorsivo fino a quando ogni sotterraneo avrà approssimativamente le dimensioni di una stanza. La divisione del dungeon utilizza questa operazione:

  • Scegli una direzione casuale: divisione orizzontale o verticale
  • Scegli una posizione casuale (x per verticale, y per orizzontale)
  • Dividi il sotterraneo in due sotterranei

inserisci qui la descrizione dell'immagine

Ora abbiamo due sotterranei A e B. Possiamo applicare la stessa operazione a entrambi.

inserisci qui la descrizione dell'immagine

Quando si sceglie la posizione di divisione, dobbiamo fare attenzione a non essere troppo vicini al bordo del sotterraneo. Dobbiamo essere in grado di posizionare una stanza all'interno di ogni sotterraneo generato. Ripetiamo fino a quando i sotterranei più bassi hanno approssimativamente le dimensioni delle stanze che vogliamo generare.

inserisci qui la descrizione dell'immagine

Costruire la prigione

Ora creiamo una stanza con dimensioni casuali in ogni foglia dell'albero. Naturalmente, la stanza deve essere contenuta all'interno del sotterraneo corrispondente. Grazie all'albero BSP, non possiamo avere due stanze sovrapposte.

inserisci qui la descrizione dell'immagine

Per costruire corridoi, attraversiamo tutte le foglie dell'albero, collegando ogni foglia a sua sorella. Se le due stanze hanno pareti faccia a faccia, possiamo usare un corridoio dritto. Altrimenti dobbiamo usare un corridoio a forma di Z.

inserisci qui la descrizione dell'immagine

Ora saliamo di un livello nell'albero e ripetiamo il processo per le sottoregioni padre. Ora, possiamo collegare due sottoregioni con un collegamento tra due stanze o un corridoio e una stanza o due corridoi.

inserisci qui la descrizione dell'immagine

Ripetiamo il processo fino a quando non abbiamo collegato i primi due sotterranei A e B

inserisci qui la descrizione dell'immagine


Potrebbe non valere nulla che questa tecnica non creerà mai loop, tuttavia non sono sicuro che ci sia un modo per aggirare questo senza aggiungere altri corridoi casuali. Risposta ancora molto buona, +1
Valità,

Questo è un inizio promettente. Devo solo trovare un modo per aggiungere alcuni loop ad esso, ma preferisco lavorare su quel problema piuttosto che continuare lungo il percorso in cui mi trovo attualmente. Grazie.
user1323245

2
Bello ! Ero interessato dall'id, quindi ho fatto un piccolo tentativo. Devi fare attenzione quando usi risultati casuali altrimenti seguiranno strani. E mi chiedo se i corridoi non debbano essere gestiti proprio durante la divisione ricorsiva, perché non vedo un modo semplice per costruire corridoi fuori dall'albero. Comunque per chiunque sia interessato al violino è qui: jsfiddle.net/gamealchemist/xt57zwb8
GameAlchemist

Mentre lo trovo alquanto problematico nella proceduralizzazione seed ripetibile su grandi ambienti. È probabilmente uno dei migliori metodi che abbia mai visto per questo tipo di generazione, a condizione che tu stia generando tutto il tuo livello in una volta. I +1 questo
Quel senzatetto,

4

Il metodo BSP è apparentemente il metodo più popolare per generare dungeon, ma non è l'unico.

Per completezza spiegherò il generatore che ha funzionato per me . Devo ammettere che non ricordo dove ho letto di questo, quindi dirò solo che non è una mia invenzione (un vecchio articolo di Jamis Buck sembra molto familiare).

Un labirinto con stanze

L'idea di base è che un sotterraneo è un labirinto con stanze, una specie di. Quindi il primo passo per questo algoritmo è generare un labirinto :

Labirinto generato con una variante dell'algoritmo Eller

Il prossimo passo è renderlo sparso (rimuovere i vicoli ciechi):

Rendi sparso: rimuovi i vicoli ciechi

Il passaggio numero 3 è aggiungere alcuni loop (renderlo non perfetto ) ma salterò l'immagine perché è appena percettibile (non avevo bisogno di un labirinto perfetto, quindi ho preso alcune scorciatoie sull'algoritmo di generazione del labirinto, quindi già a questo punto aveva dei loop).

Quindi, per il passaggio 4, dobbiamo rimuovere le celle isolate:

Rimuovi celle isolate

A questo punto abbiamo finito con i corridoi e siamo pronti per aggiungere stanze. Per questo facciamo quanto segue:

  1. Genera una serie di stanze (larghezza e altezza)
  2. Per ogni stanza passiamo in rassegna tutte le posizioni possibili e decidiamo la posizione migliore.
    • La posizione migliore viene calcolata aggiungendo un peso alle condizioni (come l'adiacenza a un corridoio).
  3. Posizioniamo le stanze.

Finora, il nostro dungeon sarà simile a questo: Stanze aggiunte

L'ultimo passo è aggiungere decorazioni.

Disegna le porte e i numeri delle stanze

Alcuni pensieri finali

  • Ho usato una versione ridotta di Eller Algorithm .
  • Diversi algoritmi di labirinto possono comportare trame diverse. Potresti preferire un altro algoritmo. Ad esempio, l'immagine seguente mostra diverse trame risultanti da "Albero binario" (diagonale diagonale) e una variante degli algoritmi "Divisione ricorsiva" (corridoi lunghi): Albero binario vs divisione pseudo-ricorsiva

2
Roba buona. Ho ben cercato diversi modi per farlo, dal momento che l'utilizzo di algoritmi diversi per livelli diversi può rendere il gioco ancora più versatile.
user1323245
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.