¿Cómo crear un río realista sin conocer todo el mapa de antemano?

Introducción

Estoy desarrollando un juego en tiempo real que tiene un mapa generado dinámicamente y me gustaría agregar ríos que van desde las montañas hasta el mar.

Breve información sobre el mapa.

En mi juego, cuando un jugador se mueve al borde del mapa generado actualmente, se cargan nuevos fragmentos (piezas pequeñas y cuadradas del mapa) del mapa en el servidor. Si no se encuentran fragmentos para la ubicación solicitada, se generan utilizando la misma semilla que se utiliza en otras partes del mapa. Actualmente, no hay límite en el tamaño del mapa o la cantidad total de fragmentos generados. Estoy usando ruido Perlin para generar el mapa. Lo trato como un mapa de altura, con cada campo que tiene un rango de valores que ocupa, por ejemplo, aguas poco profundas comienza desde -0.12inclusivo y termina en 0exclusivo.

Ya leí sobre cómo hacer que el río se vea realista:

Pregunta

¿Cómo agrego ríos al mapa cuando no sé cómo se ven los mapas completos? Si no sé dónde están las montañas, no puedo ubicar el nacimiento del río. Y si ya tengo alguna parte del mapa generada, no puedo simplemente agregar el río un poco más tarde cuando un jugador se encuentra con una cadena montañosa.

similitudes

Un escenario similar (creo) está en Minecraft. Allí también, el mapa se genera a medida que el jugador se mueve usando una semilla y hay ríos que continúan girando mientras el mapa se genera. Lamentablemente, no conozco la técnica utilizada allí.

Pantallas del juego

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

Carga de fragmentos temporalmente deshabilitada, para mostrar los límites:

ingrese la descripción de la imagen aquí

¿Los fragmentos nuevos toman en consideración los fragmentos adyacentes ya generados?
Solo verificando: si está utilizando ruido para generar terreno, habrá mínimos locales. El agua tenderá a acumularse en estos mínimos si son mínimos en todas las direcciones. El agua también se verterá sobre el borde inferior de dichos mínimos. ¿Es esta una representación justa de cómo lo haces? ¿Distingues entre suelo poroso y no poroso o entre roca y suelo fácilmente erosionable?
@willk Actualmente, no, pero podría ponerlos a disposición durante el proceso de generación. Sin embargo, estoy un poco preocupado por las posibles complicaciones de rendimiento de este tipo. Cuando el jugador se mueve, se carga/genera más de un fragmento.
Está bien, pero cuando dices un trozo, ¿cuál es la resolución dentro de un trozo? Presumiblemente, debe haber alguna gradación entre los trozos o habrá abruptos acantilados o caídas a lo largo de las líneas entre ellos. Creo que necesitamos mucha más claridad sobre su algoritmo para saber cómo responder. ¿Es la imagen de su algoritmo?
PD: ¿es una parte de toda la imagen o es un rectángulo dentro de la imagen? ¿Puedes acercarte a los rectángulos para obtener detalles más finos?
@chasly-reinstateMonica Sí, podría crear lagos o estanques locales, pero no sé cómo crear un río a partir de ellos. No distingo entre suelo poroso y no poroso, ni entre roca y suelo fácilmente erosionable. Por ahora, supongo que el agua puede fluir en todo tipo de suelo. El tamaño de fragmento es configurable, en este momento está configurado en campos de 15x15. El campo único es un cuadrado de 20x20 píxeles visible en la imagen incluida en cuestión y sí, es de mi algoritmo. No hay acantilados ni gradaciones, usar la misma semilla mantiene todo muy bien consistente. La imagen en cuestión cargó alrededor de 3300 campos con 15 fragmentos.
Bueno. Creo que veo el problema. Está asumiendo que el nivel del agua es el mismo en todas partes. Esto no es cierto en terreno real a menos que el terreno sea totalmente poroso. Con rocas no porosas tendrás piscinas aisladas en lo alto de las montañas. Su nivel estará muy por encima del nivel del mar. Lo que necesita encontrar son puntos de venta de estas piscinas más altas. Estos conducirán a estanques más bajos y así sucesivamente hasta el nivel del mar. Esto es lo que da a los ríos. ¿Estoy en el camino correcto?
El seguimiento fue @chasly dijo, lo que podría hacer es generar otro mapa de ruido perlin (quizás más pequeño, menos computación) relacionado con el nivel del agua. Su generador de terreno más alto luego haría referencia a este mapa del nivel del agua para calcular la región exclusiva/interior adecuada.
La última vez que intenté generar mundos, utilicé un método de capas de "campos" de ruido perlin. Como, digamos, campos montañosos/llanos/cavernosos, cuyos valores, si cumplen algunas condiciones, gobernarían la forma del conjunto. Los campos tenían sus propios comportamientos y todos interactuaban entre ellos. Se alentaría a los campos de montaña a seguir caminos que fueran nominalmente lineales o sutilmente serpenteantes. Los campos de montaña también tenderían a gobernar los valores de los campos más bajos. No querrías que se generaran valles donde había una montaña, por lo que los campos montañosos los repelerían magnéticamente y los someterían.
Creo que Minecraft en realidad genera un mapa de bajo detalle en secciones enormes ahora. Entonces podría decidir "hay un río en algún lugar a través de esta área de 128x128" y cuando realmente genera esa área, entonces decide exactamente dónde colocar el río. Además, los ríos de Minecraft en realidad no son ríos, son planos e incluso pueden ir en círculos.
Si su mundo es 2D, es casi seguro que puede permitirse generar una gran cantidad por adelantado, como Dwarf Fortress.
Esta pregunta no tiene nada que ver con la "construcción de mundos", es una pregunta muy transitada en la ingeniería de juegos. Simplemente haga esta pregunta en el excelente sitio de desarrollo de juegos. (O simplemente busque en Google cientos de discusiones al respecto).

Respuestas (4)

El problema es irresoluble según lo solicitado. Puedes terminar generando un río que el jugador rastrea hasta la cima de una colina menor en medio de un desierto.

Hay algunas alternativas que pueden hacer que esto funcione:

LOD y física:

Puede submuestrear y supermuestrear el ruido perlin para crear mapas de resolución múltiple. Si sus mosaicos tienen 1 mosaico por 1 metro, puede crear el mapa completo a un nivel más manejable, digamos 1 mosaico por 1 km, calcular puntos de resorte realistas y un camino de río accidentado, y luego subdividir, para decir 1 mosaico por 100 m - en ese nivel, sabe dónde fluye el río con una precisión de 10 cuadros, determina dónde fluye el río a lo largo de ese camino y luego dónde fluye el río a través de esos cuadros más pequeños recursivamente, etc., hasta llegar a su nivel de detalle completo.

Es mejor precalcular esto y almacenarlo, si es posible. Todavía puede ejecutar esto a pedido, pero no es trivial codificarlo.

LOD y 1D perlin

Como arriba, en su mapa de baja resolución, encuentre el punto alto de donde vendría un manantial, encuentre el punto más cercano al nivel del mar, dibuje una línea recta. Ahora usa el ruido perlin 1D para hacer que el viento del río sea perpendicular a la línea.

Esto es mucho más fácil de codificar: puede tener algunos artefactos poco realistas, pero para un juego de fichas 2D como este es poco probable que los notes.

Fíngelo

Tiene 2 estilos de ríos. Uno que va "cuesta arriba", otro que va "cuesta abajo". Cree mosaicos para mostrar el río que sale de un manantial y se convierte en un río completo, y uno que muestre un río completo que desemboca en una pequeña característica subterránea.

Si el valor del ruido perlin para un área costera es un valor muy preciso, genera un río "cuesta arriba". Esto viaja al punto de borde más alto en el mosaico que no bordea un mosaico explorado, que luego, cuando se carga el siguiente mosaico, va al siguiente punto más alto. Si detecta que se ha ido a un máximo local (no hay un punto más alto) o que ya se exploraron todas las casillas vecinas, retroceda hacia el medio, coloque una ficha que muestre el río saliendo de una cueva o un manantial o algo bajo tierra, así que el usuario no ve el río que comienza en la cima de una pequeña colina.

Si el valor de ruido perlin para una montaña es un valor muy preciso, genera un río "cuesta abajo", sigue hasta el otro borde más bajo de un mosaico inexplorado, y si llega a un mínimo local, o un trozo sin vecinos inexplorados , pon un mosaico en el que se muestre el río desapareciendo bajo tierra.

Esto suele ser lo suficientemente bueno para un juego 2D basado en mosaicos.

2 (o más) canales perlin

Actualmente, está ejecutando el generador perlin una vez por mosaico, para dar un valor único. Sugeriría ejecutarlo varias veces por mosaico (con diferentes semillas, por supuesto, y generalmente diferentes factores de escala). El uso de esos valores múltiples para llenar los mosaicos, en lugar de solo uno;

Esto puede ayudar a romper la expectativa de que el haya está al lado de las llanuras, las llanuras suelen estar al lado del bosque, los bosques suelen estar al lado de las montañas, etc.

Si lo ejecuta dos veces, sugeriría humedad y elevación. Si lo ejecuta 3 veces, sugeriría el tamaño de la característica (arena/roca, hielo/nieve o estéril -> pradera -> matorral -> árboles), humedad (desierto -> fértil -> río -> pantano) y elevación (agua -> llanuras -> colinas -> montañas). 4 veces tal vez incluiría una temperatura también.

En lugar de enfocarse en correr su río "cuesta abajo", intente correrlo donde la humedad esté dentro de un rango de contorno particular. Si bien el río no fluirá cuesta abajo de manera "realista", en un juego de mosaicos como el que está mostrando, la elevación está oscurecida, es mejor asegurarse de que los árboles crezcan cerca de los ríos, los ríos no están bordeados por el desierto y la tierra cerca de los ríos es tierras de cultivo fértiles.

Si bien esta respuesta es admirable, la pregunta y la respuesta deben trasladarse al sitio de gamedev. Esto no está relacionado con la "construcción del mundo".

¿Cómo agrego ríos al mapa cuando no sé cómo se ven los mapas completos? Si no sé dónde están las montañas, no puedo ubicar el nacimiento del río. Y si ya tengo alguna parte del mapa generada, no puedo simplemente agregar el río un poco más tarde cuando un jugador se encuentra con una cadena montañosa.

No puedes hacerlo completamente dentro de un trozo. Si está al borde de un trozo y parece haber un mínimo local, tiene dos opciones.

  1. Extiende el terreno de forma invisible alrededor del mínimo hasta que encuentres el perímetro de ese mínimo en el trozo aún sin explorar. No es necesario que complete todo el fragmento nuevo porque para entonces sabrá hacia dónde drenará la piscina. Esto estará de vuelta en el fragmento actual o en algún lugar, aún incompleto, en el fragmento aún no explorado. En otras palabras, tienes que extenderte más allá de lo visible/explorado. Podrías llamar a esto programación por si acaso .

  2. Disponer de un algoritmo determinista que se ocupe específicamente de esta eventualidad. Es decir, cierre deliberadamente cualquier salida posible hacia el nuevo trozo. Efectivamente has construido una presa. Es casi seguro que esto conducirá a artefactos de aspecto falso.

Tenga en cuenta que el uso de mínimos locales de esta manera (suponiendo un terreno no permeable) permitirá que el grano sea tan fino como desee. Esto incluso podría permitirle mostrar manantiales y otras pequeñas fuentes del río.

Hace algunos años escribí un algoritmo para un juego de rol que funcionaba de manera similar.
Piensa en "Buscaminas". Cuando descubres un cuadrado de montaña, hay un x% de probabilidad de que haya agua. Pero esa probabilidad de influencia cuadrada de que el trozo junto a él sea una montaña. Que influyen en la apariencia del agua. Para cada mapa puede imponer fuentes de agua. El mapa se inicia desde un rango de 0-100 y se elige un número. Es la cantidad de fuentes de agua. Cuanto menos sombreado esté el mapa, mayor será la probabilidad de que aparezca agua.

Ahora, para ayudarte, la naturaleza vino con esta ingeniosa cosa que los arroyos aparecen y luego se filtran, se agrietan y desaparecen. Hoy en día, con la tecnología moderna, podemos rastrear de dónde viene, pero en la fase de "descubrimiento", una fuente puede mostrarse como 3 o 4 arroyos diferentes. Entonces, no es necesario que sean una línea continua desde la fuente descubierta hasta "algún lugar". Puede terminar después de 4 o 5 trozos.

Por lo tanto, puede terminar con los fragmentos generados por el agua cuando el jugador se encuentre con un fragmento "seco".
O

Crea un cambio divertido en tu mapa. Con el tiempo (movimiento del jugador), los trozos secos se convirtieron en húmedos cuando el generador intenta unir el "charco" de agua más grande (si es más bajo). El generador también podría tener la probabilidad de crear un arroyo, por lo que no irá en la línea más recta.

Recuerda que tu jugador actúa como un humano típico. Entonces podrían descubrir la fuente del río, podría fluir hacia regiones no descubiertas, pero solo por el divorcio y su presencia cambian la forma en que fluye el agua.

El algoritmo más simple es que los ríos se "ajusten" a un valle de montaña siempre que un río existente se encuentre dentro de un umbral de distancia (y tal vez en un ángulo) de un valle que cumpla con los requisitos mínimos.

Digamos que tienes un río generado por cualquier algoritmo que estés usando. Todavía no existe una fuente y termina en la "niebla de guerra" en su mapa. Pero el jugador se mueve para revelar eso, y usas el algoritmo para generar nuevamente las piezas que faltan.

Suponiendo que su algo ocasionalmente genera montañas, si se crean montañas/valles dentro de n unidades desde el "final" del río y en cualquier ángulo menos profundo que +/-45 grados de la tangente del río, entonces genere un camino de río desde ese Señale el valle de la montaña y coloque un glaciar allí.

Si el punto final del río está más lejos que n unidades, comience a generar su ruta y si esa ruta se encuentra dentro de las n unidades del valle, haga lo anterior.

Sería necesario generar montañas primero y luego superponer el río en la parte superior de dicho mapa.

Incluso podría lograr permitir que se conecte a varias montañas/valles si hay múltiples sitios potenciales, y esto le daría afluentes que alimentan un río principal con destino al mar.

Por supuesto, esto se basa en un esquema de generación de mapas de dos partes, donde se generan la mayoría de las características del mapa y los ríos se "pintan" encima de eso. Funcionaría para Minecraft, por ejemplo, que creo que hace esto. Si tu juego fuera más sofisticado y usara la elevación para determinar los caminos de los ríos, esto sería inviable.