Buscando un buen algoritmo de generación de mapas del mundo [cerrado]


97

Estoy trabajando en un juego similar a Civilization y estoy buscando un buen algoritmo para generar mapas del mundo similares a la Tierra. He experimentado con algunas alternativas, pero todavía no he encontrado un verdadero ganador.

Una opción es generar un mapa de altura utilizando ruido Perlin y agregar agua a un nivel de modo que aproximadamente el 30% del mundo sea tierra. Si bien el ruido de Perlin (o técnicas similares basadas en fractales) se usa con frecuencia para el terreno y es razonablemente realista, no ofrece mucho control sobre el número, el tamaño y la posición de los continentes resultantes, lo que me gustaría tener desde una perspectiva de juego.

Ruido perlin

Una segunda opción es comenzar con una semilla de un mosaico colocada al azar (estoy trabajando en una cuadrícula de mosaicos), determinar el tamaño deseado para el continente y cada turno agregar un mosaico que sea horizontal o verticalmente adyacente al continente existente hasta ha alcanzado el tamaño deseado. Repita para los otros continentes. Esta técnica es parte del algoritmo utilizado en Civilization 4. El problema es que después de colocar los primeros continentes, es posible elegir una ubicación de inicio que esté rodeada por otros continentes y, por lo tanto, no se ajustará al nuevo. Además, tiene una tendencia a generar continentes demasiado juntos, lo que resulta en algo que se parece más a un río que a continentes.

Expansión aleatoria

¿Alguien conoce un buen algoritmo para generar continentes realistas en un mapa basado en cuadrículas mientras se mantiene el control sobre su número y tamaños relativos?


2
No veo por qué debería cerrarse una pregunta natural con más de 90 votos a favor. Votación para reabrir.
John Coleman

Respuestas:


38

Puede seguir el ejemplo de la naturaleza y modificar su segunda idea. Una vez que genere sus continentes (que son todos aproximadamente del mismo tamaño), haga que se muevan y roten aleatoriamente y colisionen y se deformen entre sí y se separen entre sí. (Nota: puede que esto no sea lo más fácil de implementar).

Editar: Aquí hay otra forma de hacerlo, completa con una implementación: Generación de mapas poligonales para juegos .


2
Esta es una gran idea. No sé si tratar de emular las placas tectónicas directamente, pero siempre que cada continente "posea" sus propios mosaicos de tierra (en lugar de actuar simplemente como un generador para una matriz de mapas) y esencialmente se asiente o actúe como su propia placa, no sería tan difícil de implementar. Voy a tener que probar esto ahora :)
nathanchere

@FerretallicA Gracias. Estoy muy tentado de intentarlo yo mismo, cuando tenga más tiempo libre ... :-)
David Johnstone

3
Un truco barato que siempre puede usar es definir en una función matemática lo que define un mapa "bueno", y luego crear diez cambios menores aleatorios y luego usar lo mejor de ellos. Siga haciendo eso y se desviará hacia el tipo de mapa que desea.
dascandy

Puede utilizar una modificación de la agrupación de K-means para determinar a qué "continente" pertenece cada pedazo de tierra. Luego use un diagrama de Voronoi (que debería ser fácil una vez que haya definido los grupos) para determinar los límites de las placas ... para cada segmento de línea en el Voronoi, determinaría un vector de movimiento aleatorio, y debería ser capaz de determinar zonas de terremotos frente a volcánicas zonas, etc. Cada punto de la tierra terminaría entonces con un vector individual basado en su ubicación en relación con los límites de la placa, y debería terminar con una simulación bastante realista para trabajar.
Steve

Estoy usando el método de semilla de una baldosa. ¿Alguna sugerencia sobre cómo agregar terrenos más complejos, como cadenas montañosas, a esto?
A Tyshka

11

Te sugiero que retrocedas y

  1. Piense en lo que hace a los continentes "buenos".
  2. Escribe un algoritmo que pueda diferenciar un buen diseño continental de uno malo.
  3. Refina el algoritmo para que puedas cuantificar qué tan bueno es un buen diseño.

Una vez que tenga eso en su lugar, puede comenzar a implementar un algoritmo que debería tener la forma siguiente:

  • Genera continentes de mierda y luego mejóralos.

Para mejorar, puede probar todo tipo de trucos de optimización estándar, ya sea recocido simulado, programación genética o algo completamente ad hoc , como mover un cuadrado de borde elegido al azar desde cualquier lugar del continente hasta el borde opuesto al centro de masa del continente. Pero la clave es poder escribir un programa que pueda distinguir los continentes buenos de los malos. Comience con continentes dibujados a mano, así como sus continentes de prueba, hasta que obtenga algo que le guste.


1
Eso tiene poco sentido en este contexto. Sería como decir que, para un generador de fractales, deberías hacer un programa que genere fractales de mierda y luego intentar escribir un programa que te diga si lo que tienes es un buen fractal o no. Es mucho más fácil hacerlo "bien" desde el principio. De lo contrario, desviará completamente el enfoque y el alcance del problema.
Nathanchere

1
@FerretallicA Totalmente en desacuerdo. Con los gráficos, puede ser muy útil comenzar por obtener algo, cualquier cosa en la pantalla. Entonces su hemisferio derecho puede empezar a trabajar.
luser droog

11

Escribí algo similar a lo que buscas para un clon automático de Civilization 1 al estilo de un salvapantallas. Para que conste, escribí esto en VB.net, pero como no mencionas nada sobre el idioma o la plataforma en tu pregunta, me quedaré es abstracto.

El "mapa" especifica el número de continentes, la variación del tamaño de los continentes (por ejemplo, 1.0 mantendría todos los continentes con la misma área terrestre aproximada, hasta 0.1 permitiría que los continentes existieran con 1/10 de la masa del continente más grande), área terrestre máxima (como porcentaje) a generar, y el sesgo de la tierra central. Una "semilla" se distribuye aleatoriamente alrededor del mapa para cada continente, ponderada hacia el centro del mapa según el sesgo central (por ejemplo, un sesgo bajo produce continentes distribuidos más similares a la Tierra, donde un sesgo central alto se parecerá más a un sesgo central). Pangea). Luego, para cada iteración de crecimiento, las "semillas" asignan baldosas de tierra de acuerdo con un algoritmo de distribución (más sobre esto más adelante) hasta que se alcanza un área de tierra máxima.

El algoritmo de distribución de tierras puede ser tan preciso como desee, pero encontré resultados más interesantes aplicando varios algoritmos genéticos y tirando los dados. El "Juego de la vida" de Conway es muy fácil de empezar. Deberá agregar ALGUNA lógica globalmente consciente para evitar que cosas como los continentes crezcan entre sí, pero en su mayor parte las cosas se cuidan por sí mismas. El problema que encontré con más enfoques basados ​​en fractales (que fue mi primera inclinación) fue que los resultados parecían demasiado modelados o conducían a demasiados escenarios que requerían reglas de solución de sensación de hacky para obtener un resultado que aún no se sentía lo suficientemente dinámico. Dependiendo del algoritmo que utilice, es posible que desee aplicar una pasada "difusa" sobre el resultado para eliminar elementos como abundantes mosaicos oceánicos de un solo cuadrado y costas a cuadros. En el caso de que se genere algo así como un continente rodeado de varios otros y que no tenga ningún lugar para crecer, reubique la semilla en un nuevo punto en el mapa y continúe con los pasos de crecimiento. Sí, puede significar que a veces terminas con más continentes de los planeados, pero si realmente es algo que firmemente no quieres, entonces otra forma de ayudar a evitarlo es sesgar los algoritmos de crecimiento para que favorezcan el crecimiento en la dirección con menor proximidad a otros. semillas En el peor de los casos (en mi opinión de todos modos), puede marcar una serie como inválida cuando a una semilla no le queda ningún lugar para crecer y generar un nuevo mapa. Solo asegúrese de establecer un número máximo de intentos, de modo que si se especifica algo poco realista (como colocar 50 continentes de peso uniforme en un tablero de 10x10), no pasará una eternidad tratando de encontrar una solución válida.

No puedo dar fe de cómo lo hace Civ, etc., y por supuesto no cubre cosas como el clima, la edad de la tierra, etc., pero jugando con el algoritmo de crecimiento de semillas puedes obtener resultados bastante interesantes que se asemejan a continentes, archipiélagos, etc. utilice el mismo enfoque para producir ríos, cadenas montañosas, etc. de apariencia 'orgánica'.


11

Creé algo similar a tu primera imagen en JavaScript. No es súper sofisticado pero funciona:

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
Implementación muy elegante, me gusta.
nathanchere

Gracias amigo !! Es muy ligero y agradable
Liberateur

9

Generación de mapas poligonales artículo sobre describe paso a paso la generación de mapas sin utilizar polígonos de Voronoi.

Este chico también da todos los códigos fuente. Es Flash (ActionScript 3 / ECMAScript) pero se puede transponer a cualquier otro lenguaje orientado a objetos

O intente utilizar algoritmos implementados en algunos softwares de entorno fractal como TerraJ


5

Solo pensando en el manguito aquí:

Elija algunos puntos de partida y asigne a cada uno un tamaño extraído al azar (esperado). Puede mantener un tamaño separado para los continentes planificados y las islas planificadas si lo desea.

Haga un bucle sobre los elementos terrestres y, cuando aún no tengan el tamaño planificado, agregue un cuadrado. Pero la parte divertida es sopesar la posibilidad de que cada elemento vecino sea el indicado. Algo sugerido que podría tener en cuenta:

  1. Distancia a la "otra" tierra más cercana. Más es mejor genera amplios espacios oceánicos. Cuanto más cerca, mejor hace canales estrechos. Tienes que decidir si vas a permitir que los bits se fusionen también.
  2. Distancia de la semilla. Más cerca es mejor significa masas de tierra compactas, más lejos es mejor significa trozos largos
  3. Número de plazas de tierra adyacentes existentes. La ponderación a favor de muchas plazas adyacentes le da una costa suave, y si prefiere unas pocas, obtendrá muchas ensenadas y penínsulas.
  4. ¿Presencia de cuadrados de "recursos" cercanos? Depende de las reglas del juego, de cuándo generas la casilla de recursos y de si quieres que sea más fácil.
  5. ¿Permitirá que los bits se acerquen o se unan a los polos?
  6. ??? no se que mas

Continúe hasta que todas las masas de tierra hayan alcanzado el tamaño planificado o no puedan crecer más por alguna razón.

Tenga en cuenta que modificar el parámetro con estos factores de ponderación le permite ajustar el tipo de mundo generado, que es una característica que me gustó de algunas de las Civs.

De esta forma, necesitará generar terreno en cada bit por separado.


4

Puede probar un algoritmo de cuadrado de diamante o ruido de Perlin para generar algo como un mapa de altura. Luego, asigne valores de rangos a lo que aparece en el mapa. Si su "altura" va de 0 a 100, entonces haga 0 - 20 de agua, 20 - 30 de playa, 30 - 80 de pasto, 80 - 100 montañas. Creo que Notch hizo algo similar a esto en minicraft, pero no soy un experto, solo estoy en una mentalidad de cuadrado de diamante después de finalmente hacerlo funcionar.


3

Creo que puede utilizar el enfoque de estilo de "programación dinámica" aquí.

Primero resuelva los problemas pequeños y combine soluciones de manera inteligente para resolver problemas más grandes.

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" ;)

Será muy bueno echar un vistazo a algunos "Algoritmos de diseño de gráficos"

Puede modificarlos para adaptarlos a su propósito.


3

Tuve una idea para la creación de mapas similar a la respuesta de las placas tectónicas. Fue algo como ésto:

  1. barrer a través de los cuadrados de la cuadrícula dando a cada cuadrado un cuadrado de "tierra" si rnd <= 0.292 (el porcentaje real de tierra seca en el planeta tierra).
  2. Migre cada trozo de tierra un cuadrado hacia su vecino más grande más cercano. Si los vecinos son equidistantes, diríjase hacia el trozo más grande. Si los trozos tienen el mismo tamaño, elija uno al azar.
  3. si dos cuadrados de tierra se tocan, agrúpelos en un trozo, moviendo todos los cuadrados como uno a partir de ahora.
  4. repita desde el paso 2. Deténgase cuando todos los fragmentos estén conectados.

Esto es similar a cómo funciona la gravedad en un espacio 3D. Es bastante complicado. Un algoritmo más simple para sus necesidades funcionaría de la siguiente manera:

  1. Coloque n casillas de tierra iniciales en posiciones x, y aleatorias y distancias aceptables entre sí. Estas son semillas para sus continentes. (Utilice el teorema de Pitágoras para asegurarse de que las semillas tengan una distancia mínima entre ellas y todas las demás).
  2. generar una casilla de tierra a partir de una casilla de tierra existente en una dirección aleatoria, si esa dirección es una casilla de océano.
  3. repita el paso 2. Deténgase cuando los cuadrados de tierra llenen el 30% del tamaño total del mapa.
  4. si los continentes están lo suficientemente cerca unos de otros, coloque puentes terrestres como desee para simular un efecto tipo Panamá.
  5. Coloca islas más pequeñas y aleatorias según lo desees para una apariencia más natural.
  6. por cada cuadrado de "isla" adicional que agregue, corte los mares interiores y los cuadrados de lagos de los continentes utilizando el mismo algoritmo a la inversa. Esto mantendrá el porcentaje de tierra en la cantidad deseada.

Déjame saber cómo funciona esto. Yo nunca lo he probado.

PD. Veo que esto es similar a lo que intentaste. Excepto que coloca todas las semillas a la vez, antes de comenzar, por lo que los continentes estarán lo suficientemente separados y se detendrán cuando el mapa esté lo suficientemente lleno.


2

En realidad, no he probado esto, pero se inspiró en la respuesta de David Johnstone con respecto a las placas tectónicas. Intenté implementarlo yo mismo en mi antiguo proyecto de Civ y cuando se trataba de manejar colisiones, tenía otra idea. En lugar de generar mosaicos directamente, cada continente consta de nodos. Distribuya la masa a cada nodo y luego genere una serie de continentes "blob" utilizando un enfoque de metaball 2D. La tectónica y la deriva continental serían ridículamente fáciles de "falsificar" simplemente moviendo los nodos. Dependiendo de qué tan complejo desee ir, incluso podría aplicar cosas como corrientes para manejar el movimiento del nodo y generar cadenas montañosas que se correspondan con los límites de las placas superpuestas. Probablemente no agregaría mucho al lado del juego de las cosas,

Una buena explicación de las metabolas si no ha trabajado con ellas antes:

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


2

Esto es lo que estoy pensando, ya que estoy a punto de implementar algo como esto que tengo para un juego en desarrollo. :

El mundo dividido en regiones. dependiendo del tamaño del mundo, determinará cuántas regiones. Para este ejemplo, asumiremos un mundo de tamaño mediano, con 6 regiones. Cada zona de la cuadrícula se divide en 9 zonas de la cuadrícula. esas zonas de la cuadrícula se dividen en 9 cuadrículas cada una. (esto no es para el movimiento de personajes, sino simplemente para la creación de mapas) Las cuadrículas son para biomas, las zonas de cuadrículas son para características terrestres más arqueadas (continente vs océano) y las regiones son para el clima general. Las rejillas se rompen en baldosas.

Generadas aleatoriamente, las regiones reciben conjuntos climáticos lógicos asignados. Las zonas de cuadrícula se asignan aleatoriamente, por ejemplo; océano o tierra. A las cuadrículas se les asignan biomas aleatoriamente con modificadores basados ​​en sus zonas de cuadrícula y el clima, ya sea bosque, desierto, llanuras, glaciares, pantanos o volcánicas. Una vez que se asignan todos esos conceptos básicos, es hora de combinarlos, utilizando una función basada en porcentaje aleatorio que completa los conjuntos de mosaicos. Por ejemplo; si tiene un bioma forestal, junto a un bioma desértico, tiene un algoritmo que disminuye la probabilidad de que una baldosa sea "boscosa" y aumenta que será "desértica". Entonces, aproximadamente a mitad de camino entre ellos, verá una especie de efecto combinado que combina los dos biomas para lograr una transición algo suave entre ellos. La transición de una zona de cuadrícula a la siguiente probablemente requeriría un poco más de trabajo para asegurar formaciones lógicas de masa terrestre, como, por ejemplo, un bioma de una zona de cuadrícula que toca el bioma de otra, en lugar de tener un porcentaje de conmutación simple basado en la proximidad. Por ejemplo, hay 50 mosaicos desde el centro del bioma hasta el borde del bioma, es decir, hay 50 desde el borde que toca hasta el centro del siguiente bioma. Eso, lógicamente, dejaría un cambio del 100% de un bioma al siguiente. Entonces, a medida que los mosaicos se acercan al borde de los dos biomas, el porcentaje se reduce a alrededor del 60% más o menos. Creo que sería imprudente dar demasiada probabilidad de cruzar biomas lejos de la frontera, pero querrá que la frontera esté algo mezclada. Para las zonas de la cuadrícula, el cambio porcentual será mucho más pronunciado. En lugar de que el% baje a alrededor del 60%, solo bajaría a alrededor del 80%. Y luego se tendría que realizar una verificación secundaria para asegurarse de que no haya una baldosa de agua aleatoria en el medio de un bioma terrestre junto al océano sin algo de lógica. Entonces, conecte esa baldosa de agua a la masa del océano para hacer un canal para explicar la baldosa de agua, o elimínela por completo. La tierra en un bioma a base de agua es más fácil de explicar usando afloramientos rocosos y demás.

Oh, un poco tonto, lo siento.


¡Hola! Estaba investigando un poco mientras intentaba generar un mapa para ... y estaba a punto de implementar exactamente lo que describiste. Solo por curiosidad, ¿cómo resultó?
VivienLeger

1

Colocaría el terreno fractal de acuerdo con algún diseño que sepa que "funciona" (por ejemplo, cuadrícula de 2x2, diamante, etc., con cierta fluctuación) pero con una distribución gaussiana que amortigua los picos hacia los bordes de los centros continentales. Coloque el nivel del agua más bajo para que sea principalmente tierra hasta que se acerque a los bordes.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.