Generazione procedurale di un edificio di un'area specifica


15

Io e una squadra stiamo lavorando a un gioco costruttore di fabbriche che dà al giocatore una fabbrica casuale all'inizio del gioco. Per cercare di assicurarsi che vi sia un senso di "equità", idealmente la fabbrica generata casualmente avrebbe un'area entro poche unità di (valore segnaposto) 30.

È relativamente semplice scrivere un generatore di rettangoli casuali di base per soddisfare queste specifiche, ma il nostro obiettivo è che la fabbrica sia più complessa, forse composta da 2, 3 o persino 4 rettangoli che si intersecano, producendo forme più complesse (pensa a L, U e edifici a forma di O).

Ho provato a generare un rettangolo casuale e quindi ad utilizzare l'algebra di base per riempire un secondo rettangolo, ma finora non ho avuto fortuna a implementare più di 2 rettangoli, e anche allora non sono soddisfatto dei risultati per un solo 2 rettangolo .

Alcune informazioni più rilevanti: 2D top down Alcuni dei meccanici sono in stile factorio, quindi le stanze dovrebbero avere una lunghezza e una larghezza ragionevoli per consentire spazio per i macchinari Attualmente in Java e Lua (possono utilizzare librerie integrate da entrambi se necessario)

Grazie in anticipo!

EDIT: Quando dico output "buoni" o "cattivi", un output cattivo sarebbe qualsiasi output che ha spazio inutilizzabile dal lettore. La forma di fabbrica limita la posizione in cui il giocatore può posizionare macchine di fabbrica come nastri trasportatori. Idealmente, la fabbrica non dovrebbe avere aree larghe solo 1-2 blocchi, la forma non dovrebbe essere uno o due grandi rettangoli con una linea di 1-2 blocchi "sospesi" su un lato. Un buon risultato sarebbe dove tutto lo spazio del pavimento è "lavorabile", quindi tutte le aree sono larghe almeno 3-4 blocchi. Un buon risultato non deve sempre essere complesso (1 o 2 rettangoli vanno bene), ma dovrebbe avere una buona probabilità se composto da più di 1-2 rettangoli.

Risposte:


7

È possibile utilizzare i poliomino pre-generati come meta-forme per costruire un assortimento di edifici.

Supponiamo che la distanza minima accettabile sia di 3 blocchi. Quindi la più piccola unità di costruzione accettabile che prenderemo in considerazione è 3x3. Per comodità, ho intenzione di chiamare quella cella e che dà un'area di 9 blocchi. Quindi, prendi l'area iniziale di destinazione e dividila per l'area della cella. Usando il valore iniziale che hai dato, otteniamo 3.333; quindi 3 celle ti darebbero un po 'meno di quanto desideri e 4 celle ti darebbero di più.

Da qui hai un paio di opzioni. Se sei flessibile sulla tua area di partenza, usa il metodo più adatto a te per scegliere il numero di celle che ti dà un importo accettabile (cioè arrotondare al valore più vicino, arrotondare per eccesso, ecc.). Chiamerò questo il conteggio delle cellule.

Quindi, seleziona in modo casuale il poliomino con il numero di celle desiderato. Sostituisci ogni quadrato sul poliomino con una cellula di costruzione e avrai la tua forma finale.

Per illustrare, diciamo che scegliamo di arrotondare per difetto. Ecco tutti i poliomino di dimensione 3 (esclusi rotazioni / ribaltamenti):

inserisci qui la descrizione dell'immagine

Supponiamo di scegliere casualmente la forma a L e applicare una rotazione casuale, il tuo edificio avrebbe il seguente layout:

inserisci qui la descrizione dell'immagine

Un paio di problemi. Innanzitutto, c'è un limite al numero di celle che puoi usare. Wikipedia ti darà tutti i poliomino fino alla taglia 8 ( ottomino ). Include dati di riepilogo fino alla dimensione 12, ma non so se esiste un elenco online per tutti. In secondo luogo, la soluzione precedente funziona esattamente solo per dimensioni di edifici che sono multipli di 9. Esistono un paio di modi per aggirare alcuni di questi problemi:

1) Utilizzare una cella di dimensioni diverse. Ad esempio 3x4, 4x4, ecc.

2) Aggiungi ulteriori celle a un poliomino iniziale. Questo può essere complicato se devi assicurarti che tutte le forme siano ugualmente probabili, ma le probabilità sono per la maggior parte degli scopi di sviluppo del gioco che non hai bisogno di una distribuzione veramente uniforme delle forme degli edifici.

3) Riempi un edificio per renderlo più grande. Tornando all'esempio, se hai usato 3 celle, il tuo edificio avrebbe un'area di 27 quadrati che ti lasciano corto di 3. Potresti quindi scansionare il perimetro per trovare una posizione per incollare un gruppo di quadrati di dimensioni 1x3. Finché il tuo gruppo di makeup è almeno AxB dove A è almeno la distanza minima accettabile, il risultato non violerà il tuo vincolo di distanza minima accettabile. Partendo dall'esempio sopra, ecco un'illustrazione di un possibile risultato:

inserisci qui la descrizione dell'immagine

4) Invece di riempire un edificio troppo piccolo, potresti tagliare un edificio troppo grande. Garantire il rispetto del vincolo di distanza minima accettabile è più complesso dell'opzione di imbottitura, ma ti darebbe più alternative da considerare.

Alcuni altri commenti:

Solo perché potresti usare tutti i possibili poliomino di una determinata dimensione non significa che dovresti. Se alcuni di loro non sono divertenti, rompi il tuo tema, sono offensivi per il tuo pubblico (modelli di svastica) o causano qualche altro problema, eliminali. Inoltre, è possibile ponderare la routine di selezione se alcuni motivi sono interessanti, ma troppo strani per apparire di routine. Infine, potresti utilizzare questa soluzione in combinazione con la tua attuale strategia. Forse il 70% delle volte si generano edifici rettangolari e il 30% delle volte si utilizza l'approccio del poliomino. O forse inizi con un edificio rettangolare e incolla un piccolo poliomino all'esterno.


16

Un modo semplice per creare un generatore procedurale è:

  1. Costruisci a caso le cose
  2. Esegui una funzione che controlla se l'output è buono
  3. Se l'output non è buono, andare al passaggio 1

Anche se ci vogliono migliaia di cicli per completare, i generatori più semplici riescono bene con questo approccio. Il vantaggio è che non c'è molta intelligenza richiesta nel generatore, e dal momento che verificare se qualcosa di buono è molto più facile che costruire qualcosa che è buono al 100% delle volte, questo approccio è molto semplice.

Hai elencato alcune misure oggettive sul fatto che un risultato sia buono; dovrebbe bastare per creare un generatore veloce e sporco. Posiziona i rettangoli in modo casuale all'interno di un'area e rifiuta l'output se, ad esempio, ci sono aree larghe solo 1-2 blocchi.

Inizia con questo, migliora e ottimizza in seguito.


Grazie! Ricordo di averlo considerato, ma il pensiero che ci fosse una possibilità per diversi secondi + tempo di caricamento mi fermò. Ora mi rendo conto di quanto sia incredibilmente piccola questa possibilità. Dovrò provarlo, ma potrei aspettare di vedere se qualcuno ha prima una soluzione più diretta.
user2129189

@ user2129189 Quando il generatore è in funzione, è comunque possibile modificare i suoi intervalli di numeri casuali per evitare di generare layout che difficilmente supereranno il test. È anche possibile parallelizzare questo algoritmo di generazione di tentativi ed errori su più core facendo in modo che ciascun core generi un layout alla volta.
Philipp,

3
Io stesso non sono un fan dei metodi di generazione di rifiuto e ripetizione. Sono abbastanza veloci quando il tuo generatore sta facendo solo una cosa semplice, ma per i livelli di gioco di solito iniziamo a stratificare più funzionalità e passaggi di generazione per rendere le mappe più ricche. A quel punto, la probabilità di colpire una mappa praticabile è il prodotto della probabilità che ogni passaggio abbia successo, che può ridursi rapidamente. Questo non è solo un problema accademico: ho parlato con gli sviluppatori che hanno dovuto implementare un sistema di cache dei semi buono / cattivo per evitare tempi di generazione in eccesso, quando un generatore a singolo passaggio corretto per costruzione sarebbe stato più facile.
DMGregory

@DMGregory sì, posso sicuramente vederlo. Un generatore casuale di base funzionerebbe come il 99% delle volte in pochi passaggi per il mio caso, ma se voglio aggiungere più complessità in seguito, potrebbe rallentare in modo significativo. Qualcuno sa di eventuali applicazioni di programmazione / gioco della vita reale del modello ipotesi e check-like?
user2129189,

Forse ci possono essere livelli di funzioni e controlli di generazioni, avendo cura di abbinare la formulazione delle condizioni all'attuale livello di generazione. In questo modo, non è necessario rigenerare l'intero livello solo a causa dell'errore riscontrato posizionando un articolo in modo leggermente errato.
Pysis,

7

Data una limitazione di "tutte le aree sono larghe almeno 3-4 blocchi", la prima idea che mi viene in mente è simile alla seguente:

  1. scegline uno tra 3x3, 3x4, 4x3 o 4x4
  2. posizionare un blocco di quelle dimensioni al centro della griglia
  3. scegli una direzione (su, sinistra, destra, giù)
  4. prova a posizionare un blocco 3x3 accanto a blocchi precedentemente posizionati in quella direzione
  5. in caso di successo, con qualche probabilità, prova ad espandere il blocco in un blocco 4x3 in una delle direzioni che non hai semplicemente scelto
  6. con una certa probabilità, sposta un al bordo casuale dei blocchi riempiti
  7. ripetere i passaggi da 3 a 6 fino a quando l'area è abbastanza grande

L'idea di base è che, dato che si desidera che tutte le aree abbiano almeno una determinata dimensione, lavorare solo in aree di quelle dimensioni. Più in generale, se vuoi che qualcosa sia vero per tutti gli output generati, vedi se può essere reso vero per tutti gli output parzialmente generati.


4
Semplificherei le cose partendo sempre da un blocco 3x3, quindi aggiungendo blocchi 3x1 in posizioni casuali in cui ogni quadrato è adiacente a uno esistente. Aggiungendo a un blocco 3x3, ci sono quattro possibili posizioni. Tutti ti danno un blocco 3x4, con sei posizioni possibili per il prossimo. Da lì diventa più complicato, ma non così male.
JollyJoker,

0

Considera di utilizzare i booleani NOT e UNION e di sceglierli in modo casuale.

  1. Posiziona un rettangolo casuale.
  2. Posiziona un secondo rettangolo casuale.
  3. Scegli casualmente se UNIONli o SOTTRANO il secondo dal primo.
  4. Ripetere l'operazione per un numero di rettangoli. Tuttavia, solo due o tre potrebbero dare risultati abbastanza ragionevoli.

Quindi, calcolerei l'area e la ridimensionerei su o giù per abbinare più da vicino la dimensione approssimativa che stai cercando, e quindi testerei che non ci sono dimensioni inferiori a una quantità minima richiesta.


La tua idea di ridimensionamento per ottenere l'area desiderata è in realtà abbastanza intelligente. Potrei implementare qualcosa di silenzioso un po 'come questo.
user2129189
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.