Alla ricerca di un buon algoritmo per la generazione di mappe del mondo [chiuso]


97

Sto lavorando a un gioco simile a Civilization e sto cercando un buon algoritmo per generare mappe del mondo simili alla Terra. Ho sperimentato alcune alternative, ma non ho ancora trovato un vero vincitore.

Un'opzione è generare una mappa di altezza usando il rumore Perlin e aggiungere acqua a un livello in modo che circa il 30% del mondo sia terra. Sebbene il rumore di Perlin (o tecniche simili basate sui frattali) sia spesso utilizzato per il terreno ed è ragionevolmente realistico, non offre molto in termini di controllo sul numero, le dimensioni e la posizione dei continenti risultanti, cosa che vorrei avere da una prospettiva di gioco.

Rumore di Perlin

Una seconda opzione è iniziare con un seme di una tessera posizionato casualmente (sto lavorando su una griglia di tessere), determinare la dimensione desiderata per il continente e ad ogni turno aggiungere una tessera che è orizzontalmente o verticalmente adiacente al continente esistente finché hai raggiunto la dimensione desiderata. Ripeti per gli altri continenti. Questa tecnica fa parte dell'algoritmo utilizzato in Civilization 4. Il problema è che dopo aver posizionato i primi pochi continenti, è possibile scegliere una posizione di partenza circondata da altri continenti e quindi non adatta a quello nuovo. Inoltre, ha la tendenza a generare continenti troppo vicini tra loro, risultando in qualcosa che assomiglia più a un fiume che a continenti.

Espansione casuale

Qualcuno conosce un buon algoritmo per generare continenti realistici su una mappa basata su griglia mantenendo il controllo sul loro numero e dimensioni relative?


2
Non vedo perché una domanda naturale con più di 90 voti positivi dovrebbe essere chiusa. Votazioni per riaprire.
John Coleman

Risposte:


38

Potresti prendere spunto dalla natura e modificare la tua seconda idea. Una volta generati i tuoi continenti (che sono tutti della stessa dimensione), falli muovere e ruotare in modo casuale, scontrarsi e deformarsi l'un l'altro e allontanarsi l'uno dall'altro. (Nota: questa potrebbe non essere la cosa più semplice da implementare.)

Modifica: ecco un altro modo per farlo, completo di un'implementazione: Polygonal Map Generation for Games .


2
Questa è una grande idea. Non so come cercare di emulare le placche tettoniche a titolo definitivo, ma fintanto che ogni continente "possiede" le proprie tessere di terra (invece di agire semplicemente come un generatore per un array di mappe) e essenzialmente si siede o agisce come la propria piastra, non sarebbe così difficile da implementare. Dovrò provarlo ora :)
nathanchere

@ FerretallicA Thanks. Sono molto tentato di provare io stesso - quando avrò più tempo libero ... :-)
David Johnstone

3
Un trucco economico che puoi sempre usare è definire in una funzione matematica ciò che definisce una mappa "buona", quindi creare dieci modifiche minori casuali e quindi utilizzare le migliori. Continua a farlo e andrà alla deriva verso il tipo di mappa che desideri.
dascandy

È possibile utilizzare una modifica del raggruppamento K-means per determinare a quale "continente" apparteneva ogni singolo pezzo di terra. Quindi usa un diagramma di Voronoi (che dovrebbe essere facile una volta definiti i cluster) per determinare i confini delle placche ... per ogni segmento di linea nel Voronoi dovresti determinare un vettore di movimento casuale e dovresti essere in grado di determinare le zone di terremoto rispetto a quelle vulcaniche zone, ecc. Ogni punto di terra finirebbe con un vettore individuale basato sulla sua posizione in relazione ai confini della placca e dovrebbe finire con una simulazione abbastanza realistica su cui lavorare.
Steve il

Sto usando il metodo seme di una tessera. Qualche suggerimento su come aggiungere a questo terreno più complesso come le catene montuose?
A Tyshka

11

Ti suggerirei di eseguire il backup e

  1. Pensa a ciò che rende i continenti "buoni".
  2. Scrivi un algoritmo in grado di distinguere un buon layout continentale da uno cattivo.
  3. Perfeziona l'algoritmo in modo da poter quantificare quanto è buono un buon layout.

Una volta installato, puoi iniziare a implementare un algoritmo che dovrebbe avere la forma seguente:

  • Genera continenti schifosi e poi migliorali.

Per migliorare puoi provare tutti i tipi di trucchi di ottimizzazione standard, che si tratti di ricottura simulata, programmazione genetica o qualcosa di completamente ad hoc , come spostare un quadrato di bordo scelto a caso da qualsiasi punto del continente al bordo opposto al centro di massa del continente. Ma la chiave è essere in grado di scrivere un programma in grado di distinguere i continenti buoni da quelli cattivi. Inizia con i continenti disegnati a mano così come i continenti di prova, finché non ottieni qualcosa che ti piace.


1
Non ha molto senso in questo contesto. Sarebbe come dire che, per un generatore di frattali, dovresti creare un programma che generi frattali scadenti, quindi provare a scrivere un programma che ti dica se quello che hai è un buon frattale o no. Molto più facile farlo "bene" dall'inizio. Altrimenti si distorce completamente l'attenzione e la portata del problema.
nathanchere

1
@ FerretallicA Assolutamente in disaccordo. Con la grafica, può essere molto utile iniziare ottenendo qualcosa, qualsiasi cosa sullo schermo. Quindi il tuo cervello destro può iniziare a lavorare.
luser droog

11

Ho scritto qualcosa di simile a quello che cerchi per un clone automatico in stile salvaschermo di Civilization 1. Per la cronaca l'ho scritto su VB.net ma dato che nella tua domanda non dici nulla sulla lingua o sulla piattaforma lo terrò è astratto.

La "mappa" specifica il numero di continenti, la varianza delle dimensioni dei continenti (es. 1.0 manterrebbe tutti i continenti con la stessa area terrestre approssimativa, fino a 0.1 consentirebbe ai continenti di esistere con 1/10 della massa del continente più grande), area terrestre massima (in percentuale) per generare e il bias della terra centrale. Un "seme" viene distribuito in modo casuale intorno alla mappa per ogni continente, pesato verso il centro della mappa secondo il bias centrale (ad esempio un bias basso produce continenti distribuiti più simili alla Terra, dove un bias centrale alto assomiglierà più a un Pangea). Quindi, per ogni iterazione di crescita, i "semi" assegnano le tessere terreno secondo un algoritmo di distribuzione (ne parleremo più avanti) fino a quando non viene raggiunta una superficie massima.

L'algoritmo di distribuzione della terra può essere preciso quanto vuoi, ma ho trovato risultati più interessanti applicando vari algoritmi genetici e tirando i dadi. "Game of Life" di Conway è davvero facile con cui iniziare. Dovrai aggiungere ALCUNA logica globalmente consapevole per evitare che cose come i continenti crescano l'una nell'altra, ma per la maggior parte le cose si prendono cura di se stesse. Il problema che ho riscontrato con più approcci basati sui frattali (che era la mia prima inclinazione) era che i risultati sembravano troppo modellati o portavano a troppi scenari che richiedevano regole di soluzione alternativa per ottenere un risultato che ancora non sembrava abbastanza dinamico. A seconda dell'algoritmo che usi, potresti voler applicare un passaggio di "sfocatura" sul risultato per eliminare cose come abbondanti tessere oceaniche di un unico quadrato e coste a scacchi. Nel caso in cui qualcosa come un continente venga generato circondato da molti altri e non abbia più un posto dove crescere, riposiziona il seme in un nuovo punto sulla mappa e continua la crescita. Sì, può significare che a volte ti ritrovi con più continenti del previsto, ma se è davvero qualcosa che non vuoi fermamente, un altro modo per evitarlo è influenzare gli algoritmi di crescita in modo che favoriscano la crescita nella direzione con la minore vicinanza agli altri semi. Nel peggiore dei casi (secondo me comunque), puoi contrassegnare una serie come non valida quando un seme non è rimasto da nessuna parte per crescere e generare una nuova mappa. Assicurati solo di impostare un numero massimo di tentativi in ​​modo che se viene specificato qualcosa di irrealistico (come montare 50 continenti a parità di peso su una scheda 10x10) non passa un'eternità a cercare una soluzione valida.

Non posso garantire come Civ ecc., E ovviamente non copre cose come il clima, l'età della terra ecc. Ma giocando con l'algoritmo di crescita dei semi puoi ottenere risultati piuttosto interessanti che assomigliano a continenti, arcipelaghi ecc. utilizzare lo stesso approccio per produrre fiumi, catene montuose, ecc. dall'aspetto "organico".


11

Ho creato qualcosa di simile alla tua prima immagine in JavaScript. Non è super sofisticato ma funziona:

http://jsfiddle.net/AyexeM/zMZ9y/

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<style type="text/css">
    #stage{
        font-family: Courier New, monospace;
    }
    span{
        display: none;
    }
    .tile{
        float:left;
        height:10px;
        width:10px;
    }
    .water{
        background-color: #55F;
    }
    .earth{
        background-color: #273;
    }
</style>
</head>

<body>


<div id="stage">

</div>

<script type="text/javascript">

var tileArray = new Array();
var probabilityModifier = 0;
var mapWidth=135;
var mapheight=65;
var tileSize=10;

var landMassAmount=2; // scale of 1 to 5
var landMassSize=3; // scale of 1 to 5


$('#stage').css('width',(mapWidth*tileSize)+'px');


for (var i = 0; i < mapWidth*mapheight; i++) {

    var probability = 0;
    var probabilityModifier = 0;

    if (i<(mapWidth*2)||i%mapWidth<2||i%mapWidth>(mapWidth-3)||i>(mapWidth*mapheight)-((mapWidth*2)+1)){

        // make the edges of the map water
        probability=0;
    }
    else {

        probability = 15 + landMassAmount;

        if (i>(mapWidth*2)+2){

            // Conform the tile upwards and to the left to its surroundings 
            var conformity =
                (tileArray[i-mapWidth-1]==(tileArray[i-(mapWidth*2)-1]))+
                (tileArray[i-mapWidth-1]==(tileArray[i-mapWidth]))+
                (tileArray[i-mapWidth-1]==(tileArray[i-1]))+
                (tileArray[i-mapWidth-1]==(tileArray[i-mapWidth-2]));

            if (conformity<2)
            {
                tileArray[i-mapWidth-1]=!tileArray[i-mapWidth-1];
            }
        }

        // get the probability of what type of tile this would be based on its surroundings 
        probabilityModifier = (tileArray[i-1]+tileArray[i-mapWidth]+tileArray[i-mapWidth+1])*(19+(landMassSize*1.4));
    }

    rndm=(Math.random()*101);
    tileArray[i]=(rndm<(probability+probabilityModifier));

}

for (var i = 0; i < tileArray.length; i++) {
    if (tileArray[i]){
        $('#stage').append('<div class="tile earth '+i+'"> </div>');
    }
    else{
        $('#stage').append('<div class="tile water '+i+'"> </div>');
    }
}

</script>

</body>
</html>

3
Realizzazione molto elegante, mi piace.
nathanchere

Grazie ragazzo !! È molto leggero e piacevole
Liberateur

9

L' articolo sulla generazione di mappe poligonali descrive la generazione di mappe passo dopo passo senza selezionare i poligoni di Voronoi.

Questo ragazzo fornisce anche tutti i codici sorgente. È Flash (ActionScript 3 / ECMAScript) ma è trasponibile in qualsiasi altro linguaggio orientato agli oggetti

Oppure prova a utilizzare algoritmi implementati in alcuni software di ambiente frattale come TerraJ


5

Sto solo pensando a braccio qui:

Scegli alcuni punti di partenza e assegna a ciascuno una dimensione disegnata a caso (sperata). Se lo desideri, puoi mantenere un disegno di dimensioni separato per i continenti pianificati e le isole pianificate.

Fai un giro sugli elementi del terreno e, dove non sono ancora della dimensione pianificata, aggiungi un quadrato. Ma la parte divertente sta valutando la possibilità che ogni elemento adiacente sia l'unico. Qualche cosa suggerita che potrebbe prendere in considerazione:

  1. Distanza dalla terra "altra" più vicina. Inoltre è meglio genera ampi spazi oceanici. Più vicino è meglio crea canali stretti. Devi decidere se lasciare che anche i bit si uniscano.
  2. Distanza dal seme. Più vicino è meglio significa masse terrestri compatte, più lontano è meglio significa frammenti lunghi
  3. Numero di quadrati di terreno esistenti adiacenti. Ponderare a favore di molte piazze adiacenti ti dà una costa liscia, preferendo poche ti dà molte insenature e penisole.
  4. Presenza di piazze "risorse" nelle vicinanze? Dipende dalle regole del gioco, da quando generi il quadrato delle risorse e se vuoi renderlo facile.
  5. Consentirai ai bit di avvicinarsi o unirsi ai poli?
  6. ??? non so cos'altro

Continua fino a quando tutte le masse di terra hanno raggiunto le dimensioni pianificate o non possono più crescere per qualche motivo.

Si noti che modificare il parametro su questi fattori di ponderazione consente di regolare il tipo di mondo generato, che è una caratteristica che mi è piaciuta di alcune Civ.

In questo modo dovrai generare il terreno su ogni bit separatamente.


4

Potresti provare un algoritmo del quadrato del diamante o il rumore del perlin per generare qualcosa come una mappa di altezza. Quindi, assegna i valori degli intervalli a ciò che viene visualizzato sulla mappa. Se la tua "altezza" va da 0 a 100, fai 0 - 20 acqua, 20 - 30 spiaggia, 30 - 80 erba, 80 - 100 montagne. Penso che notch abbia fatto qualcosa di simile a questo in minicraft, ma non sono un esperto, sono solo in una mentalità quadrata dopo aver finalmente fatto funzionare.


3

Penso che tu possa usare l'approccio in stile "programmazione dinamica" qui.

Risolvi prima i piccoli problemi e combina le soluzioni in modo intelligente per risolvere i problemi più grandi.

A1= [elliptical rectangular random ... ]// list of continents with area A1 approx. 
A2= [elliptical rectangular random ... ]// list of continents with area A2 approx.
A3= [elliptical rectangular random ... ]// list of continents with area A3 approx.
...
An= [elliptical rectangular random ... ]// list of continents with area An approx.

// note that elliptical is approximately elliptical in shape and same for the other shapes.

Choose one/more randomly from each of the lists (An).

Now you have control over number and area of continents.

You can use genetic algorithm for positioning them 
as you see "fit" ;)

Sarà molto utile dare un'occhiata ad alcuni "algoritmi di layout grafico"

Puoi modificarli per adattarli al tuo scopo.


3

Ho avuto un'idea per la creazione di mappe simile alla risposta delle placche tettoniche. È andata più o meno così:

  1. spazzare i quadrati della griglia dando a ogni quadrato un quadrato "terra" se rnd <= 0,292 (la percentuale effettiva di terraferma sul pianeta terra).
  2. Migra ogni pezzo di terra di una casella verso il suo vicino più grande. Se i vicini sono equidistanti, vai verso il pezzo più grande. Se i pezzi hanno la stessa dimensione, scegline uno a caso.
  3. se due caselle di terra si toccano, raggruppale in un blocco, muovendo tutte le caselle come una sola volta.
  4. ripetere dal passaggio 2. Fermarsi quando tutti i blocchi sono collegati.

Questo è simile a come funziona la gravità in uno spazio 3D. È piuttosto complicato. Un algoritmo più semplice per le tue esigenze funzionerebbe come segue:

  1. Inserisci n caselle di terra iniziali in posizioni x, y casuali e distanze accettabili l'una dall'altra. Questi sono semi per i tuoi continenti. (Usa il teorema di Pitagora per assicurarti che i semi abbiano una distanza minima tra loro e tutti gli altri.)
  2. genera una casella terra da una casella terra esistente in una direzione casuale, se quella direzione è una casella oceano.
  3. ripetere il passaggio 2. Fermarsi quando le caselle di terra riempiono il 30% della dimensione totale della mappa.
  4. se i continenti sono abbastanza vicini tra loro, rilascia i ponti di terra come desideri per simulare un effetto di tipo Panama.
  5. Inserisci isole più piccole e casuali come desideri per un aspetto più naturale.
  6. per ogni quadrato "isola" in più che aggiungi, ritaglia i mari interni e i quadrati dei laghi dai continenti usando lo stesso algoritmo al contrario. Ciò manterrà la percentuale di terreno all'importo desiderato.

Fammi sapere come funziona. Non l'ho mai provato da solo.

PS. Vedo che è simile a quello che hai provato. Tranne che imposta tutti i semi in una volta, prima di iniziare, quindi i continenti saranno abbastanza distanti e si fermeranno quando la mappa sarà sufficientemente piena.


2

In realtà non l'ho provato, ma è stato ispirato dalla risposta di David Johnstone riguardo alle placche tettoniche. Ho provato a implementarlo da solo nel mio vecchio progetto Civ e quando si è trattato di gestire le collisioni ho avuto un'altra idea. Invece di generare direttamente le tessere, ogni continente è costituito da nodi. Distribuire la massa a ciascun nodo quindi generare una serie di continenti "blob" utilizzando un approccio metaball 2D. La tettonica e la deriva dei continenti sarebbero ridicolmente facili da "falsificare" semplicemente spostando i nodi. A seconda di quanto complesso vuoi andare, potresti persino applicare cose come le correnti per gestire il movimento dei nodi e generare catene montuose che corrispondono ai confini delle placche sovrapposti. Probabilmente non aggiungerebbe molto al lato del gameplay delle cose,

Una buona spiegazione delle metaball se non hai mai lavorato con loro prima:

http://www.gamedev.net/page/resources/_//feature/fprogramming/exploring-metaballs-and-isosurfaces-in-2d-r2556


2

Ecco cosa sto pensando, visto che sto per implementare qualcosa di simile che ho per un gioco in fase di sviluppo. :

Il mondo diviso in regioni. a seconda delle dimensioni del mondo, determinerà quante regioni. Per questo esempio, supponiamo un mondo di medie dimensioni, con 6 regioni. Ogni zona della griglia si divide in 9 zone della griglia. quelle zone della griglia si suddividono in 9 griglie ciascuna. (questo non è per il movimento dei personaggi, ma semplicemente per la creazione di mappe) Le griglie sono per i biomi, le zone della griglia sono per le caratteristiche del terreno ad arco, (continente vs oceano) e le regioni sono per il clima generale. Le griglie si scompongono in piastrelle.

Generate casualmente, alle regioni vengono assegnati insiemi climatici logici. Ad esempio, le zone della griglia vengono assegnate in modo casuale; oceano o terra. Le griglie vengono assegnate ai biomi in modo casuale con modificatori in base alle zone della griglia e al clima, che sono foreste, deserti, pianure, glaciali, paludi o vulcanici. Una volta assegnate tutte queste basi, è il momento di unirle insieme, utilizzando una funzione basata su percentuale casuale che riempie i set di tessere. Per esempio; se hai un bioma della foresta, accanto a un bioma del deserto, hai un algoritmo che riduce la probabilità che una tessera sia "boscosa" e aumenta che sarà "deserta". Quindi, a circa metà strada tra di loro, vedrai una sorta di effetto misto che combina i due biomi per ottenere una transizione piuttosto fluida tra di loro. La transizione da una zona della griglia all'altra richiederebbe probabilmente un po 'più di lavoro per assicurare formazioni di massa terrestre logica, come, ad esempio, un bioma da una zona della griglia che tocca il bioma da un altro, invece di avere una semplice percentuale di commutazione basata sulla vicinanza. Ad esempio, ci sono 50 tessere dal centro del bioma al bordo del bioma, il che significa che ci sono 50 tessere dal bordo che tocca al centro del bioma successivo. Ciò lascerebbe logicamente un cambiamento del 100% da un bioma all'altro. Quindi, man mano che le tessere si avvicinano al confine dei due biomi, la percentuale si restringe a circa il 60% circa. Non sarebbe saggio dare troppe probabilità di attraversare i biomi lontano dal confine, ma vorrai che il confine sia in qualche modo mescolato. Per le zone della griglia, la variazione percentuale sarà molto più pronunciata. Invece della percentuale che scende a circa il 60%, scenderà solo a circa l'80%. E dovrebbe quindi essere eseguito un controllo secondario per assicurarsi che non ci sia una tessera acqua casuale nel mezzo di un bioma terrestre vicino all'oceano senza una logica. Quindi, collega quella tessera acqua alla massa oceanica per creare un canale per spiegare la tessera acqua, o rimuovila del tutto. La terra in un bioma a base acquosa è più facile da spiegare usando affioramenti rocciosi e simili.

Oh, un po 'stupido, scusa.


Ehilà! Stavo facendo delle ricerche mentre cercavo di generare una mappa per .. e stavo per implementare esattamente ciò che hai descritto. Solo per curiosità come è andata a finire?
VivienLeger

1

Posizionerei il terreno frattale secondo un layout che sai "funziona" (es. Griglia 2x2, rombi, ecc., Con un po 'di jitter) ma con una distribuzione gaussiana che smorza i picchi verso i bordi dei centri del continente. Posiziona il livello dell'acqua più in basso in modo che sia principalmente terra finché non ti avvicini ai bordi.

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.