¿Cómo puedo generar lagos y ríos al azar en mi juego?

19

Tengo un juego de construcción de bloques en 2D y estoy tratando de hacer lagos y ríos generados al azar. He examinado el algoritmo de ruido Perlin, pero no pude lograr que genere resultados aleatorios y agradables.

He estado tratando de usar la biblioteca de ruido de Python , pero no creó mapas al azar.

¿Hay alguna función semilla que me falta en esa biblioteca para hacerla más aleatoria? ¿Qué variable cambio si quiero que sea más aleatorio? Si es posible, dame una respuesta menos técnica, con menos matemáticas y más términos de python.

El mapa es un mapa en mosaico 2D. Aquí hay algunos ejemplos de la no aleatoriedad del otro algoritmo. El siguiente código se generó 3 veces seguidas. Estaba aleatorizando las octavas y la frecuencia con algo como esto:freq = 16.0 * random.randint(1, 500000) * 0.000001 + 0.5

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1
1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1
1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1
1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1
1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1
1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1

Este es el código que produjo el resultado anterior:

"""Writes a 256x256 grayscale simplex noise texture file in pgm format
(see http://netpbm.sourceforge.net/doc/pgm.html)
"""
# $Id: 2dtexture.py 21 2008-05-21 07:52:29Z casey.duncan $

import sys
from noise import pnoise2
import random
octaves = random.randint(1, 500000) * 0.000001 + 0.5
freq = 16.0 * octaves
for y in range(30):
    for x in range(40):
        n = int(pnoise2(x/freq, y / freq, 1)*10+3)
        if n>=1:
            n=1
        else:
            n=0
        print n,
    print
Julian
fuente
Más información, por favor. Esta pregunta no se puede responder en su estado actual.
Gustavo Maciel
Agregué un poco más, pero, ¿qué necesitas saber?
Juliano
Agregaste buena información, pero necesitamos un poco más. ¿Qué es "no muy al azar"? Cualquier captura de pantalla para nosotros ve cuál es el resultado dado y cuál es el resultado deseado. Como lo intentaste ¿Algún código para que nos muestres? ¿Cuál es tu contexto? 2D o 3D? Azulejos o poligonales? Lo siento si todo esto es demasiado, pero solo estoy tratando de ayudar. El -1 no era mío, si no das información, la pregunta no será adecuada para el sitio y la cerrarán. De nuevo, estoy tratando de ayudar.
Gustavo Maciel
2
+1, ahora es una buena pregunta :) No soy bueno con el ruido perlin y toda la generación de procedimientos, pero, ¿estás sembrando el objeto aleatorio? Si no me equivoco, es random.seed()así que la hora del sistema se utilizará como semilla. Y en lugar de octaves = random.randint(1,500000)*.000001+.5intentarlo: octaves = random.random() (tiene el mismo resultado, obtendrá un número entre 0 y 1, pero tiene muchas más posibilidades que solo 500000 números).
Gustavo Maciel
Gracias +1 :) :) Intenté hacer más 1 comentario pero no puedo
Julian

Respuestas:

7

Bueno, como parece, no estás sembrando el generador de números aleatorios. En python, se puede hacer fácilmente con solo un random.seed () .

Y también puedo ver que estás generando un número entre 1 y 500000 y haciendo que esté entre 0 y 1. Es un método funcional, pero está limitado a solo 500000 posibilidades. Estás mejor con solo usarlo random.random()ya genera un número entre 0 y 1, ¡pero con muchas más posibilidades! Si todavía necesita un número entre 0.5 y 1.0, como sugiere su código, simplemente puede hacer:(random.random() * 0.5) + 0.5

Su código final debe verse de la siguiente manera:

import sys
from noise import pnoise2
import random
random.seed()
octaves = random.random()
# octaves = (random.random() * 0.5) + 0.5
freq = 16.0 * octaves
for y in range(30):
    for x in range(40):
        n = int(pnoise2(x/freq, y / freq, 1)*10+3)
        if n>=1:
            n=1
        else:
            n=0
        print n,
    print

¡Eso es todo!

Gustavo Maciel
fuente
No estoy claro cómo la siembra tiene algo que ver con eso. Los números aleatorios seguirán siendo aleatorios si no siembras, pero se repetirán. El único síntoma de no sembrar debe ser la misma secuencia aleatoria cada vez que ejecuta el programa (suponiendo que se use la misma semilla cada vez).
Tim Holt
1
Si obtiene la misma salida tres veces seguidas como se menciona en su pregunta, es muy probable porque no ha sembrado el generador aleatorio. Sembrarlo y ver si soluciona el problema.
cenizas999
Ah, no había visto el bit "3 veces seguidas" - estaba leyendo, "¿Hay alguna función semilla que me falta en esa biblioteca para hacerla más aleatoria". Sí, sembrando para aleatoriedad no repetida :)
Tim Holt
8

Esto no responde a su pregunta de programación específica, pero considere que crear lagos y ríos no se trata de colocar al azar gotas de agua y franjas de agua entre ellas. Se trata de la altura del terreno, de las depresiones (cuencas) que se convierten en lagos y el agua que fluye de los puntos más altos a los más bajos.

Si desea un gran ejemplo de creación de lagos y ríos que tengan sentido, puede consultar esta publicación de blog -> http://simblob.blogspot.com/2010/09/polygon-map-generation-part-1.html Es Una buena referencia para este tipo de cosas si su objetivo es una hidrografía razonablemente realista.

Tim Holt
fuente
2

Es muy simple: si obtienes el mismo mapa tres veces seguidas (o más), es porque no aleatorizaste la semilla.

¿Qué significa esto?

Las computadoras son inherentemente deterministas (no aleatorias), por lo que simulan aleatoriedad. En realidad, es repetidamente aleatorio (es por eso que lo llamamos "generador de números pseudoaleatorios").

¿Como funciona esto?

Cuando crea un número aleatorio, tiene la opción de darle una "semilla". Lo importante es que si siempre usa la misma semilla, siempre obtendrá la misma secuencia de números aleatorios, en el mismo orden. Siempre. Esto puede ser bueno o malo.

En su caso, parece que no está sembrando el generador aleatorio y, de forma predeterminada, está obteniendo la misma semilla: probablemente use algún componente de su fecha / hora. Por lo tanto, le recomiendo que lo aleatorice.

Como Gusatavo mencionó en su respuesta, debe llamar a random.seed () . Los documentos indican que "si se omite X [el parámetro predeterminado] o Nonese usa la hora actual del sistema". Esto debería ser suficiente.

cenizas999
fuente