Como posso gerar lagos e rios aleatórios no meu jogo?

19

Eu tenho um jogo de construção de blocos 2D e estou tentando criar lagos e rios gerados aleatoriamente. Analisei o algoritmo de ruído Perlin, mas não consegui gerar resultados aleatórios e agradáveis.

Eu tenho tentado usar a biblioteca de ruído python , mas ela não criou mapas muito aleatoriamente.

Há alguma função de semente que estou faltando nessa biblioteca para torná-la mais aleatória? Que variável eu altero se quiser que seja mais aleatória? Se possível, me dê uma resposta menos técnica, com menos termos matemáticos e mais python.

O mapa é um mapa em mosaico 2D. Aqui estão alguns exemplos da não aleatoriedade do outro algoritmo. O código a seguir foi emitido 3 vezes seguidas. Eu estava randomizando as oitavas e a frequência com algo assim: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 é o código que produziu a saída acima:

"""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
fonte
Mais informações, por favor. Esta pergunta não pode ser respondida no estado atual.
Gustavo Maciel
Adicionei um pouco mais, mas o que você precisa saber.
Julian
Você adicionou boas informações, mas precisamos de um pouco mais. O que é "não muito aleatoriamente"? Qualquer captura de tela para nós ver qual é o resultado fornecido e qual é o resultado desejado? Como você tentou isso? Algum código para você nos mostrar? Qual é o seu contexto? 2D ou 3D? Lado a lado ou poligonal? Desculpe se tudo isso é demais, mas só estou tentando ajudar. O -1 não era meu, se você não der informações, a questão se tornará imprópria para o site e elas serão fechadas. Então, novamente, estou tentando ajudar.
Gustavo Maciel
2
+1, agora é uma boa pergunta :) Eu não sou bom com ruído permanente e toda a geração de procedimentos, mas você está semeando o objeto aleatório? Se não me engano, é random.seed()assim que o tempo do sistema será usado como semente. E em vez de octaves = random.randint(1,500000)*.000001+.5você pode tentar: octaves = random.random() (ele tem o mesmo resultado, você vai ter um número entre 0 e 1, mas seu muito mais possibilidades do que apenas 500000 números.)
Gustavo Maciel
Thanks +1 :) :) Tentei adicionar mais 1 comentário, mas eu não posso #
Julian

Respostas:

7

Bem, ao que parece, você não está semeando o gerador de números aleatórios. Em python, isso pode ser feito facilmente com apenas um random.seed () .

E posso ver também que você está gerando um número entre 1 e 500000 e tornando-o entre 0 e 1. É um método funcional, mas está limitado a apenas 500000 possibilidades. Você é melhor ao usá- random.random()lo já gera um número entre 0 e 1, mas com muito mais possibilidades! Se você ainda precisa de um número entre 0,5 e 1,0, como sugere seu código, basta:(random.random() * 0.5) + 0.5

Seu código final deve ter a seguinte aparência:

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

Isso é tudo!

Gustavo Maciel
fonte
Não estou claro como a semeadura tem algo a ver com isso. Os números aleatórios ainda serão aleatórios se você não inicializar, mas repetirá. O único sintoma de não semear deve ser a mesma sequência aleatória toda vez que você executa o programa (assumindo que a mesma semente é usada toda vez).
Tim Holt
1
Se você estiver obtendo a mesma saída três vezes seguidas, como mencionado na sua pergunta, é muito provável que você não tenha propagado o gerador aleatório. Semeie e veja se isso resolve o problema.
Ashes999
Ah, eu não tinha visto o bit "três vezes seguidas" - estava lendo: "Existe alguma função de semente que estou faltando nessa biblioteca para torná-la mais aleatória"? Sim semeadura de aleatoriedade não repetição :)
Tim Holt
8

Isso não está respondendo à sua pergunta de programação específica, mas considere que criar lagos e rios não é colocar aleatoriamente gotas de água e tiras de água entre eles. É sobre a altura do terreno - sobre depressões (bacias) que se transformam em lagos e água que flui de pontos mais altos para pontos mais baixos.

Se você quer um grande exemplo de criação de lagos e rios que fazem sentido, você pode verificar este post -> http://simblob.blogspot.com/2010/09/polygon-map-generation-part-1.html É uma boa referência para esse tipo de coisa se o seu objetivo for uma hidrografia razoavelmente realista.

Tim Holt
fonte
2

É muito simples: se você estiver obtendo o mesmo mapa três vezes seguidas (ou mais), é porque você não randomizou a semente.

O que isto significa?

Os computadores são inerentemente determinísticos (não aleatórios), portanto simulam a aleatoriedade. Na verdade, é repetidamente aleatório (é por isso que chamamos de "gerador de números pseudo-aleatórios").

Como é que isso funciona?

Ao criar um número aleatório, você tem a opção de atribuir uma "semente". O importante é que, se você sempre usa a mesma semente, sempre obterá a mesma sequência de números aleatórios, na mesma ordem.Sempre. Isso pode ser bom ou ruim.

No seu caso, parece que você não está semeando o gerador aleatório e, por padrão, está obtendo a mesma semente - provavelmente usa algum componente da sua data / hora. Portanto, eu recomendo que você o randomize.

Como Gusatavo mencionou em sua resposta, você precisa chamar random.seed () . Os documentos afirmam que "se X [o parâmetro padrão] for omitido ou None, a hora atual do sistema será usada". Isso deve ser suficiente.

ashes999
fonte