Função de semente aleatória para geração de mapas?

28

Estou procurando uma função para gerar um mapa aleatório baseado em blocos, à medida que os limites visuais do mapa mudam (percorrendo o mapa). Quero que o mapa seja infinitamente grande e tenha uma estrutura semelhante a um labirinto.

No entanto, se o mundo é infinito, voltar para onde um jogador já esteve antes levanta um problema. O jogo deve se lembrar de como tudo era lá atrás.

Então, eu estava pensando - "Como o Minecraft resolve esse problema?" e pensei comigo mesmo que eles deviam estar usando algum tipo de função de número aleatório com uma semente, que pode ir adiante, mas também para trás, e, dessa maneira, re-gerar azulejos antigos exatamente como estavam, mas em novas instâncias.

Quais são seus pensamentos sobre isso?

Mathias Lykkegaard Lorenzen
fonte
Como é que a minha resposta está em +5 e a pergunta está apenas em +2? Esta é uma das melhores perguntas na primeira página agora.
2
Minecraft não armazena simplesmente os pedaços que você já visitou / modificou?
FxIII 5/08/11
@ FXIII: Minecraft deve, porque você pode modificar a paisagem. Se você não puder fazer isso, armazenar os pedaços provavelmente é um desperdício, ou pelo menos uma complicação excessiva.
@ Joe Wreschnig: Ok, ok ... Eu estava com medo de ter perdido algo realmente grande!
FxIII

Respostas:

20

O que você notou é a diferença entre um gerador de números aleatórios e uma função de ruído . Um gerador de números aleatórios cospe um número diferente cada vez que você o chama. Uma função de ruído usa alguns argumentos - digamos, um mapa x e y - e cospe números com propriedades estatísticas aleatórias , mas o mesmo valor para os mesmos argumentos todas as vezes , ou seja, é uma função matemática adequada.

Os dois estão muito relacionados. A função de ruído pode simular um gerador de números aleatórios, passando um valor diferente de cada vez - por exemplo noise(1), noise(2)e assim por diante. E um gerador de números aleatórios, jogado em uma mesa gigante, pode atuar como uma função de ruído. Nos dois casos, porém, você está usando a ferramenta errada para o trabalho.

Minecraft em particular usos Perlin ruído , um tipo de ruído que é barato para computação, e tem uma propriedade desejável de ser contínua em tantas dimensões como você precisa - se você gráfico f(x)para f(x + 1), não haverá nenhuma saltos repentinos. Isso o torna muito útil para muitas coisas, como modulação de textura, nuvens e gases volumétricos e geração de terreno.

Se você está procurando uma implementação para começar a jogar, o gerador de ruído Perlin aprimorado de Ken Perlin é uma das implementações mais simples.


fonte
3
Observe que muitos geradores de números aleatórios usam uma semente e geram o mesmo conjunto de números, dada a mesma semente.
Thedaian
3
@ thedaian: o que não é particularmente útil neste caso, a menos que você queira regenerar todos os números; uma função de ruído permite obter o 500º número sem precisar gerar 499 antes disso.
Dado o algoritmo Perlin Noise, é possível calibrá-lo? Considere que eu quero que o algoritmo tenha maior probabilidade de gerar um pacote de azulejos e, em seguida, um pacote de azulejos espaciais.
Mathias Lykkegaard Lorenzen
3
Você não leu e entendeu os links que dei em seis minutos.
1
Esta resposta teria sido completo com post de Notch: notch.tumblr.com/post/3746989361/terrain-generation-part-1
deceleratedcaviar
3

O modo como o Minecraft controla sua geração é criando uma semente de nível que é usada para propagar toda a geração de números aleatórios para o jogo. Se um pedaço não existir no disco quando for solicitado, ele será gerado usando a função de geração do Notch com base na semente do nível; é então salvo em disco para mais tarde.

Parece que você deseja obter um comportamento semelhante, então esse é um caminho seguro.

Keeblebrox
fonte
2

Como Joe apontou, você está procurando uma função de hash. Geralmente, funções aleatórias são apenas funções de hash semeadas com o último número retornado. Portanto, se Random()retornado Hash(seed)=1234, uma segunda chamada Random()retornará Hash(1234), etc.

Se você está procurando uma função simples de hash para números pseudo-aleatórios, confira MurMurHash . Eu o implementei em C # e posso publicá-lo em algum lugar, se você estiver interessado. Informações mais detalhadas do Perlin Noise, que usa essa função de hash, podem ser encontradas aqui e uma implementação em C # está aqui .

Toda essa informação veio de uma pergunta que fiz há um ano aqui no Stack Overflow. O que você está procurando é chamado geração de conteúdo processual; portanto, se precisar de mais informações, faça uma pesquisa. Feliz geração de terreno!

dlras2
fonte
-1. O hash do ruído Perlin, por assim dizer, não tem nenhuma semelhança com as técnicas usadas no MMH ou outras rotinas de hash criptográfico; esse código C # é um lixo que parece apenas fazer interpolação linear entre valores aleatórios; requer muito mais memória que o ruído Perlin adequado e provavelmente corre mais devagar.
1
@ Joe - Sinto muito, você se sente tão fortemente sobre a sua implementação do Perlin Noise. O Perlin Noise é, por si só, um conceito de transformar uma função hash em uma função de ruído contínuo. Eu tenho gerado muito Perlin Noise de maneira muito eficaz com o MurMurHash. Quanto ao código C #, é um exemplo de como determinar programaticamente o valor de um único ponto no 2D Perlin Noise. Eu nunca o usaria na produção, mas é, na minha opinião, mais fácil de percorrer do que o código que você postou.
dlras2
1
O OP não tinha conhecimento de ruído ou hash, então eu simplesmente tentei fornecer referências na esperança de que eles investigassem mais e decidissem por si mesmos como implementar o que precisavam fazer.
dlras2
"O Perlin Noise é em si um conceito de transformar uma função hash em uma função de ruído contínuo". Não, o ruído Perlin é uma das funções contínuas de ruído inventadas por Ken Perlin (e não a que ele chamou de "ruído simplex"). Nem todas as funções de ruído contínuo são ruído Perlin; nem todas as funções de ruído contínuo são mesmo ruídos gradientes, dos quais o ruído Perlin é um exemplo particular; o que você vinculou não é ruído de gradiente, mas valoriza o ruído.
O código no seu link é "mais fácil de percorrer" porque não é o ruído Perlin; não é tão suave; usa muito mais recursos; em resumo, é mais fácil caminhar porque é mais burro.