Algoritmo del percorso più lungo per la generazione di labirinti roguelike


10

Ho una semplice mappa basata su griglia composta da stanze, come questa (A = ingresso, B = uscita):

   0 1 2 3
  #########
0 # B # #####
  #########
1 # ### #
  #########
2 # # #
  # # #
3 # # #
  #########
4 # ### #
  #########
5 ### A #
  ### #
6 ### #
  #########

E sono bloccato cercando di creare un algoritmo adatto per creare un percorso di porte tra le stanze, in modo tale che il giocatore debba esplorare la maggior parte della mappa prima di trovare l'uscita.

In altre parole, sto cercando di trovare il percorso più lungo possibile da A a B .

(Sono consapevole che questo problema può essere risolto per i grafici aciclici; tuttavia, in questo caso possono esserci dei cicli.)

MODIFICA: Un altro esempio in cui le stanze sono collegate tramite un allagamento e l'uscita viene scelta come stanza più lontana dall'ingresso:

   0 1 2 3
  #########
0 # B # #
  # # - #####
1 # | # #
  ### # #
2 ### # #
  ### - # - ###
3 # | ###
  # - #######
4 #A | #
  # # #
5 # # #
  # # #
6 # # #
  #########

Si noti che il percorso verso l'uscita non è affatto il percorso più lungo possibile.


Se costringi il giocatore a percorrere il percorso più lungo possibile, stai effettivamente costruendo un percorso rettilineo che finge di essere complesso. Questo non va bene.
o0 '.

Non è male (è la base del genere sparatutto su rotaia, ad esempio), ma devi essere consapevole che lo stai facendo e progettare il resto del tuo gioco per lavorare bene con esso.

È anche più facile controllare il ritmo del gioco quando i livelli sono per lo più lineari. Permette di aggiungere, ad esempio, una stanza di recupero dopo una stanza dei mostri particolarmente difficile. Se non ci fosse un percorso principale, la distribuzione di sfide e premi sarebbe casuale.
Utente non trovato il

Risposte:


11

Penso che lo farai nel modo sbagliato. Il percorso massimo in un grafico con cicli è tecnicamente indefinito perché è infinito se il ciclo si trova tra l'inizio e la fine. Probabilmente ci sono modi intelligenti per estendere / limitare la definizione del percorso massimo, ma non penso che sia l'approccio migliore qui.

Non stai cercando di modellare un percorso lungo reale (ad esempio un robot che cerca di esplorare quanta più area possibile in una mappa). Stai solo cercando di convincere il giocatore a esplorare molte stanze.

Quindi, fai in modo che il giocatore trovi l'uscita proporzionale alla percentuale della mappa esplorata finora . Supponiamo che ci siano X stanze su un livello e che il personaggio del giocatore abbia esplorato Y. La prossima volta che il personaggio entra in una stanza, posiziona l'uscita lì con probabilità f (Y, X). Un banale esempio di f potrebbe essere (Y * Y) / (X * X) - ad es. Per 10 camere, c'è una probabilità del 100% l'uscita nell'ultima stanza, l'81% delle probabilità è nell'ultima stanza - e solo un Probabilità dell'1% nella prima stanza.

Puoi modificare l'equazione nel modo desiderato per far sembrare il gioco giusto, e forse anche dare al giocatore alcune abilità per renderlo più probabile da generare. La parte fondamentale è, non generare l'uscita fino a quando il personaggio non entra nella stanza. Questo metodo è anche immune alla conoscenza da parte dei giocatori dell'algoritmo di generazione del dungeon; anche se il giocatore ha strani schemi di movimento come il salto del cavaliere in NetHack o il teletrasporto, dovranno esplorare più stanze per trovare l'uscita.

Se devi generare staticamente l'uscita, puoi usare la stessa idea con un personaggio virtuale. Immagina un riempimento inondazione a partire dalla posizione del personaggio, muovendosi una volta ogni cella per ogni iterazione. L'ultima stanza da riempire è la stanza a cui appartiene l'uscita (in effetti, l'ultima cella da riempire è la cella in cui è più lontana dal giocatore). Tuttavia, in questo caso il giocatore ha più informazioni sull'uscita - se sono sulla sinistra, molto probabilmente sulla destra - e se possono teletrasportarsi, potrebbero effettivamente arrivare più velocemente di una normale passeggiata casuale.

Alla fine, ho appena finito un roguelike in cui l'uscita è stata generata dall'altro lato della mappa dal personaggio del giocatore, e poi ho vagato a caso. Alcuni oggetti nel sotterraneo lo hanno reso visibile sulla mappa, a scapito di avere fame più velocemente. Non ho fatto alcuna analisi, ma mi è sembrato di dover esplorare più della mappa per trovarla e ha dato ai livelli un aspetto unico.


La generazione dinamica sembra una buona idea, purché il giocatore non se ne accorga. Altrimenti penso che si sentirebbero abbastanza ingannati. Adoro l'idea dell'inondazione, comunque.
Utente non trovato il

2
Bene, la tua intera proposta è in qualche modo imbrogliare il giocatore. Non incolparmi per aver perfezionato la matematica in modo da non richiedere un modello mondiale. ;) Ma puoi usare i trucchi di progettazione per renderlo più appetibile - ad esempio, l'uscita viene posizionata a priori, ma una chiave richiesta per usarla viene generata nel metodo che ho descritto o posizionata su un mostro che si genera solo dopo aver esplorato X stanze / uccidere X mostri, o aprire la porta richiede di premere X interruttori, uno in ogni stanza, ecc ...

Ho provato un approccio alluvione. Fa un buon lavoro nel collegare ogni stanza e produce rami corti, ma in realtà non produce il percorso più lungo possibile verso l'uscita anche se l'uscita è l'ultimo nodo visitato (o, nella mia implementazione, il più lontano). (esempio aggiunto alla mia domanda)
Utente non trovato il

Sono tutto per labirinti chiave / switch-based, però. Sembra semplicemente più facile implementare quel genere di cose con gli alberi, perché se hai due rami, puoi rilevare quale ramo conduce all'uscita, bloccarlo e mettere la chiave nell'altro ramo.
Utente non trovato il

Ma ammetto che mi sbagliavo nel pensare che si trattasse di un problema di pathfinding da "A a B". Mi rendo conto che ha più senso trovare l'uscita come risultato dell'algoritmo piuttosto che come obiettivo.
Utente non trovato il

6

Una possibile alternativa sarebbe quella di creare un albero di spanning (massimo?) Usando Prim / Kruskal (per eliminare i cicli) e applicare un algoritmo di percorso più lungo tradizionale sull'albero di spanning.

Tuttavia, sono preoccupato che l'algoritmo spanning tree tenderà a creare rami senza uscita, costringendo il giocatore a tornare indietro costantemente.

EDIT: risultato dell'utilizzo di un algoritmo basato su Kruskal e del posizionamento dell'uscita alla fine del ramo più lungo:

   0 1 2 3
  #########
0 #A | #
  # ##### - #
1 # # #
  ### #
2 ### #
  ### #
3 ### #
  ### - #####
4 # | #
  # - ##### - #
5 # ### #
  # - #######
6 # # B #
  # # - #
7 # | #
  #########

1
Avrei suggerito anche Primm :-), +1, penso che anche il backtrack sia una parte importante di molti giochi ... controlla diablo 2.
Mr.Gando,

2

Ecco qualcosa con cui giocherellare:

Connect each room with a door to another room.
N = 0.75*TotalNumberOfRooms
Until (pathSize > N) {
  Use A* pathing to get a path from A to B. (G being size of room, or # of monsters)
  if (pathSize < N) remove a connection/door
  if (noPath) choose a different door/connection
  if (room.doors < 1) choose a different door/connection
}

Rimuoverei le porte a caso lungo il percorso, altrimenti finirai con 1 porta all'uscita e tonnellate di porte all'inizio.

Penso che questo O(n^2)non sia eccezionale per le mappe di grandi dimensioni.


Una soluzione molto elegante in linea di principio. La prossima volta dovrei provare a pensare a qualcosa del genere prima di optare per tecniche contorte.
Utente non trovato il

Beh, elegante forse, ma sarà un maiale da processore. O (n ^ 2) non si ridimensionerà bene con mappe di grandi dimensioni.
Stephen Furlani,


1

Credo che tu abbia già ottime risposte, ma ecco i miei $ 0,02 di soluzione teorica al problema.

Quello che vuoi NON è il percorso più lungo, ma il percorso più lungo più breve. Vuoi la stanza più lontana, dato che stai considerando il percorso più breve per la stanza. Questo probabilmente sembra confuso, ma è molto facile da calcolare.

  1. Inizia dalla tua stanza iniziale. Segna ciascuno dei suoi vicini 1. Sono a distanza 1 dalla stanza di partenza.
  2. Per ogni stanza contrassegnata con 1, visita ciascuno dei vicini UNMARKED e contrassegnali 2. Sono 2 a distanza dall'inizio.
  3. Continua fino a quando non hai coperto tutte le stanze. La stanza con il numero massimo è più lontana dall'inizio.

Il calcolo di un percorso effettivamente più lungo (non impiegherà troppo tempo per dire 10 stanze) non funzionerà perché non puoi fare in modo che il giocatore faccia il percorso più lungo. Quindi mettere l'entrata e l'uscita in due stanze più lontane l'una dall'altra è la soluzione migliore. Per trovare questo, calcola la stanza più lontana da una stanza casuale. Quindi, da quella stanza, trova la stanza più lontana. Questo si chiama trovare il diametro di un grafico, per favore Google.

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.