Qual é o método mais simples para gerar terreno suave para um jogo 2D?

23

Qual é o método mais simples para gerar terrenos suaves para um jogo em 2D como "Moon Buggy" ou "Route 960"?

Eu recebi uma resposta no stackoverflow.com sobre gerar uma matriz de alturas aleatórias e desfocá-las mais tarde. Sim, está tudo bem. Mas seria melhor dar alguns pontos e obter uma curva suave.

astropânico
fonte

Respostas:

13

Uma maneira de conseguir isso é o seguinte:

  • Crie um ponto no meio da tela, com uma altura aleatória; agora você tem duas seções, uma de cada lado deste ponto
  • Para cada seção, divida em duas, colocando um ponto no meio desta seção, com altura aleatória (à distância) entre seus dois vizinhos
  • Repita n vezes.

O que acontece é que os detalhes no cenário ficam mais refinados a cada iteração.

A decisão de como você lida com casos de fronteira é sua: você pode assumir pontos em (0, altura / 2) e (largura, altura / 2), por exemplo.

Espero que isto ajude!

EDIT: Aqui está uma foto que eu fiz para ilustração:

terraingen

Esta é a mesma ideia!

Tim Kelsall
fonte
12

Supondo que você queira um terreno realmente suave, sugiro voltar das respostas baseadas em ruído e entender de onde elas vêm. Um sinal de 'ruído' é essencialmente uma soma de infinitamente numerosos sinusóides de amplitudes aleatórias, com a amplitude 'média' em uma determinada frequência dada por uma função da frequência f . Você pode obter a maioria das definições comuns de 'ruído' dessa maneira. Por exemplo, o movimento browniano tem 1 / f ^ 2resposta em frequência (ou seja, a amplitude média em uma determinada frequência é inversamente proporcional ao quadrado da frequência): isso significa que pontos próximos têm uma boa correlação entre si, uma vez que os componentes de alta frequência do sinal são fortemente amortecido. Por outro lado, o ruído fractal clássico (deslocamento do ponto médio, ruído Perlin, etc.) tem uma resposta de frequência de 1 / f ; há mais variação entre pontos próximos, mas ainda há bastante correlação. Indo um passo adiante, o ruído branco tem uma resposta de frequência constante - não há correlação entre nenhum ponto.

Que bem isso faz você? Bem, você pode obter um sinal suave que ainda parece um pouco barulhento, somando um punhado de sinusóides, mas certificando-se de que eles tenham uma amplitude apropriada em qualquer frequência. Você deseja que as frequências sejam 'aleatórias', para que duas não tenham um múltiplo comum (caso contrário, você obterá um componente periódico para a forma geral de suas colinas); portanto, sugiro algo como o seguinte procedimento (completo com exemplo de trabalho):

  1. Escolha 4 números (reais) aleatoriamente no intervalo [1..10] - essas serão as frequências de suas ondas senoidais. Joguei os dados no random.org e obtive: f 0 = 1,75, f 1 = 2,96, f 2 = 6,23 ef 3 = 8,07. Não há nada mágico no número 4 (você pode usar mais, mas usar menos começará a tornar as ondas senoidais mais óbvias) ou o intervalo de 1 a 10 aqui (é apenas uma maneira de garantir que as suas maiores e menores freqüências não estão muito distantes). Pode fazer sentido escolher uma frequência no intervalo [1..2] e o restante no intervalo [2..10] apenas para que você tenha um sinusóide "dominante" conhecido.
  2. Para cada um destes quatro (ou muitos) no entanto frequências f i , escolher uma amplitude um i algures no intervalo entre -C / f i e C / f i para alguns constante C . O valor que você escolhe aqui controla a amplitude geral da sua onda - por conveniência, escolhi C = 1. Então, eu precisava de números aleatórios no intervalo [-1 / 1,75 (= -0,571) .. 1 / 1,75 (= 0,571) ] e da mesma forma nos intervalos [-0,338 .. 0,338], [-0,161 .. 0,161] e [-0,124 .. 0,124]. Rolando os dados quatro vezes novamente, eu tenho um 0 = -0,143, a 1 = -0,180, um 2 = -0,012, ea 3 = 0,088. (Observe que essa provavelmente não é a melhor maneira de executar esta etapa - pois o valor máximo possível da função é a soma das amplitudes abs ( a 0 ) + abs ( a 1 ) + abs ( a 2 ) + abs ( um 3 ), pode fazer mais sentido para dividir cada uma das suas quatro de i valores por esta soma, uma vez que você gerou-los, e em seguida, multiplicar cada um por C de modo que você pode ter certeza que a máxima precisão a função pode atingir é C .)
  3. Pegar quatro 'compensações' o i , cada um no intervalo [0..2π] (0..6.28) - estes irão ajustar os pontos de partida de suas ondas para que eles não todos começam em 0. Eu tenho o 0 = 1,73, o 1 = 4,98, o 2 = 3,17 e o 3 = 4,63.
  4. 'Plote' a função f (x) = a 0 sin ( f 0 (kx + o 0 ) ) + a 1 sin ( f 0 (kx + o 1 ) ) + a 2 sin ( f 0 (kx + o 0 ) ) + a 3 sin ( f 0 (kx + o 0 ) ) - aqui k é outra constante, que controla o 'alongamento' horizontal de suas funções. Você terá que descobrir o que é isso para seu próprio aplicativo; por conveniência, eu escolhi k= 1 e, portanto, minha função geral é f (x) = -0,143 sin (1,75 ( x + 1,73)) - 0,180 sin (2,96 ( x +4,98)) - 0,012 sin (6,23 ( x +3,17)) + 0,088 sin (8,07 ( x + 4,63)).

Aqui está o resultado do meu exemplo de execução, conforme plotado no Wolfram Alpha - observe que ele corrige o tamanho de seus gráficos para fins de exibição, mas você deve ter bastante controle sobre o alongamento horizontal e vertical do resultado através das constantes mencionadas acima :

Sinusóide aleatória simples

Steven Stadnicki
fonte
10

O algoritmo de deslocamento do ponto médio pode gerar um belo terreno 2D.

exemplo de terreno

Existem diferenças sutis entre o deslocamento do ponto médio e o que @tykel está sugerindo. O algoritmo de Tykel subdivide o horizonte e escolhe uma nova altura. Isso cria um terreno onde os picos são espaçados uniformemente. Os seres humanos são ótimos em escolher regularidades, portanto o terreno gerado parecerá gerado, não natural.

O poder do ponto médio vem da escolha do ponto médio e do deslocamento ao longo do normal dessa linha. Isso faz com que os picos variem para cima e para baixo, bem como de um lado para o outro. O terreno resultante é fractal, e os humanos percebem os fractais como naturais.

O deslocamento aleatório da altura pode resultar em um terreno de descida se você inserir mais alguns parâmetros (deslocamento horizontal, inclinação máxima, etc.). Isso destaca outro dos pontos fortes do MPD; é muito simples de ajustar. Dois parâmetros, solavanco e nível de detalhe.

deft_code
fonte
7

Você pode usar as funções de ruído para gerar alturas aleatórias. O mais simples deles é o ruído de valor, que funciona exatamente como a sua descrição: você gera algumas alturas inteiras aleatórias e depois interpola as alturas entre elas. O método de interpolação mais frequentemente usado é o mapeamento cúbico da curva S:

Suponha que você tenha altura h0no ponto x0e altura h1no ponto x1. Para obter a altura em qualquer ponto x( x0<=x<=x1), use

t = (x-x0)/(x1-x0); // map to [0,1] range
t = t*t*(3 - 2*t); // map to cubic S-shaped curve
h = h0+t*h1;

As alturas obtidas dessa maneira serão suaves, aleatórias, mas não realmente interessantes. Para melhorar seu terreno, você pode usar ruído fractal . Funciona assim: suponha que você tenha gerado uma função h(x)que retorna a altura em uma determinada coordenada (usando o método acima). Esta função possui uma frequência, determinada pela frequência das alturas originais do intergerador. Para criar um fractal, você combina funções com várias frequências:

fbm(x)=h(x) + 0.5*h(2*x) + 0.25*h(4*x) + 0.125*h(8*x);

Neste exemplo, eu combino quatro frequências - original, dupla, 4 vezes e 8 vezes original, com frequências mais altas com menos peso. Teoricamente, os fractais vão até o infinito, mas na prática apenas alguns termos são necessários. O fbmna fórmula significa movimento browniano fracionário - este é o nome dessa função.

Esta é uma técnica poderosa. Você pode tocar com multiplicador de frequência, com pesos de frequências diferentes ou adicionar algumas funções para distorcer o ruído. Por exemplo, para obter uma sensação mais "estriada", h(x)pode ser alterado para 1-abs(h(x))(supondo -1<=h(x)<=1)

No entanto, enquanto tudo isso é bom, essa técnica tem uma limitação séria. Com uma abordagem baseada na "altura da linha", você nunca pode ter "saliências" no terreno. E eu imagino que eles sejam um recurso muito bom para ter em um jogo parecido com o "Moon Buggy".

Adicionar saliências agradáveis ​​é uma tarefa difícil. Uma coisa em que consigo pensar - você pode começar com uma "linha de altura" fractal e "separá-la" em uma série de splines ou curvas mais escuras. Então a linha do terreno será definida por vários "pontos-chave". Aplique alguma instabilidade a esses pontos-chave - isso resultará em deformação aleatória do terreno, provavelmente formando algumas formas interessantes. No entanto, auto-interseções de terreno podem se tornar um problema com essa abordagem, especialmente com grandes quantidades de tremulação.

deixa pra lá
fonte
4

Existem dois métodos populares para gerar mapas de altura do terreno.

Algumas respostas fornecidas aqui já são baseadas no algoritmo Diamond-square, mas o conhecimento do nome facilita a busca de mais informações. O ruído Perlin também tem outros usos, por isso é bom verificar de qualquer maneira.

msell
fonte
O OP está falando de paisagens 2D em estilo mario, mas ainda são bons links.
tenpn
1

Minha idéia seria criar uma função de ruído suavizado. Primeiro com um método intNoise (int) que retorna um int "aleatório", mas que depende da entrada. Se você usar a mesma entrada duas vezes, o resultado será o mesmo.

Em seguida, use um método de suavização para criar um floatNoise (float) que usa os dois números inteiros ao redor da entrada para criar um valor aleatório.

Em seguida, use a posição X como entrada e Y como saída. O resultado será uma curva suavizada, mas com altura aleatória.

XGouchet
fonte