¿Cuál es el método más simple para generar un terreno suave para un juego 2D?

23

¿Cuál es el método más simple para generar un terreno suave para un juego 2D como "Moon Buggy" o "Route 960"?

Recibí una respuesta en stackoverflow.com sobre generar una matriz de alturas aleatorias y difuminarlas más tarde. Sí, está bastante bien. Pero sería mejor dar algunos puntos y obtener una curva suave.

astropanico
fuente

Respuestas:

13

Una forma de lograr esto es la siguiente:

  • Cree un punto en el medio de la pantalla, con una altura aleatoria; ahora tiene dos secciones, una a cada lado de este punto
  • Para cada sección, divídala en dos colocando un punto en el medio de esta sección, con una altura aleatoria (a distancia) entre sus dos vecinos.
  • Repite n veces.

Lo que sucede es que el detalle en el escenario se vuelve más fino con cada iteración.

La forma en que maneja los casos límite depende de usted: podría suponer puntos en (0, altura / 2) y (ancho, altura / 2), por ejemplo.

¡Espero que esto ayude!

EDITAR: Aquí hay una imagen que hice para ilustración:

Terraingen

Esta es la misma idea!

Tim Kelsall
fuente
12

Suponiendo que desea un terreno realmente suave, le sugiero que se aleje de las respuestas basadas en el ruido y comprenda de dónde provienen. Una señal de 'ruido' es esencialmente una suma de infinitos sinusoides de amplitudes aleatorias, con la amplitud 'promedio' a una frecuencia dada dada por una función de la frecuencia f . Puede obtener la mayoría de las definiciones comunes de 'ruido' de esta manera. Por ejemplo, el movimiento browniano tiene un 1 / f ^ 2respuesta de frecuencia (es decir, la amplitud promedio en una frecuencia dada es inversamente proporcional al cuadrado de la frecuencia): esto significa que los puntos cercanos tienen una buena correlación entre sí, ya que los componentes de alta frecuencia de la señal son muy amortiguado Por el contrario, el ruido fractal clásico (desplazamiento del punto medio, ruido de Perlin, etc.) tiene una respuesta de frecuencia de 1 / f ; Hay más variación entre los puntos cercanos, pero aún existe bastante correlación. Yendo un paso más allá, el ruido blanco tiene una respuesta de frecuencia constante: no hay correlación en absoluto entre ningún punto.

¿De qué te sirve esto? Bueno, puede obtener una señal suave que todavía tiene un aspecto un poco ruidoso simplemente sumando un puñado de sinusoides pero asegurándose de que tengan una amplitud adecuada en cualquier frecuencia dada. Desea que las frecuencias sean 'aleatorias' para que ninguna de ellas tenga un múltiplo común (de lo contrario, obtendrá un componente periódico de la forma general de sus colinas), por lo que sugeriría algo como el siguiente procedimiento (completo con ejemplo de trabajo):

  1. Elija 4 números (reales) al azar en el rango [1..10]: estas serán las frecuencias de sus ondas sinusoidales. 'Lancé los dados' en random.org y obtuve: f 0 = 1.75, f 1 = 2.96, f 2 = 6.23 yf 3 = 8.07. No hay nada mágico en el número 4 (puede usar más, pero usar menos comenzará a hacer que las ondas sinusoidales individuales sean más obvias) o el rango del 1 al 10 aquí (es solo una forma de asegurarse de que su mayor y menor frecuencias no son demasiado lejos). Puede tener sentido elegir una frecuencia en el rango [1..2] y el resto en el rango [2..10] solo para que tenga una sinusoide 'dominante' conocida.
  2. Para cada una de estas cuatro (o por muchas) frecuencias f i , elija una amplitud a i en algún lugar en el rango entre -C / f i y C / f i para alguna C constante . El valor que elija aquí controla la amplitud general de su onda: por conveniencia, elegí C = 1. Luego necesité números aleatorios en el rango [-1 / 1.75 (= -0.571) .. 1 / 1.75 (= 0.571) ], y de manera similar en los rangos [-0.338 .. 0.338], [-0.161 .. 0.161] y [-0.124 .. 0.124]. Tirando los dados cuatro veces más, obtuve un 0 = -0.143, un 1 = -0.180, un 2 = -0.012, ya 3 = 0.088. (Tenga en cuenta que probablemente esta no sea la mejor manera de hacer este paso, ya que el valor máximo posible de la función es la suma de amplitudes abs ( a 0 ) + abs ( a 1 ) + abs ( a 2 ) + abs ( un 3 ), podría tener más sentido para dividir cada una de sus cuatro unos i los valores de esta suma una vez que los haya generado, y luego se multiplican cada uno por C de modo que usted puede estar seguro de la máxima precisión la función puede alcanzar es C .)
  3. Elija cuatro 'desplazamientos' o i , cada uno en el rango [0..2π] (0..6.28): estos ajustarán los puntos de inicio de sus ondas para que no todas comiencen en 0. Obtuve o 0 = 1.73, o 1 = 4.98, o 2 = 3.17, y o 3 = 4.63.
  4. 'Graficar' la función 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 ) ) - aquí k es otra constante, una que controla el 'estiramiento' horizontal de sus funciones. Tendrá que descubrir qué es esto para su propia aplicación; por conveniencia acabo de elegir k= 1, por lo que mi función general es 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)).

Aquí está el resultado de mi ejecución de ejemplo, como se trazó en Wolfram Alpha: tenga en cuenta que corrige el tamaño de sus gráficos para fines de visualización, pero que debe tener mucho control sobre el estiramiento horizontal y vertical del resultado a través de las constantes que mencioné anteriormente :

Sinusoide aleatorio simple

Steven Stadnicki
fuente
10

El algoritmo de desplazamiento del punto medio puede generar un hermoso terreno 2D.

ejemplo de terreno

Hay diferencias sutiles entre el desplazamiento del punto medio y lo que sugiere @tykel. El algoritmo de Tykel subdivide el horizonte y elige una nueva altura. Esto crea un terreno donde los picos están uniformemente espaciados. Los humanos son excelentes para elegir regularidades, por lo que el terreno generado parecerá generado, no natural.

El poder del punto medio proviene de elegir el punto medio y luego desplazarse a lo largo de la normal de esa línea. Esto hace que los picos varíen hacia arriba y hacia abajo, así como de lado a lado. El terreno resultante es fractal, y los humanos perciben los fractales como naturales.

El desplazamiento de altura aleatorio podría resultar en un terreno de descenso si agregara un par de parámetros más (desplazamiento horizontal, pendiente máxima, etc.). Esto destaca otra de las fortalezas de MPD; Es muy sencillo de sintonizar. Dos parámetros, irregularidad y nivel de detalle.

deft_code
fuente
7

Puede usar funciones de ruido para generar alturas aleatorias. El más simple de ellos es el ruido de valor, que funciona exactamente como su descripción: genera algunas alturas enteras aleatorias y luego interpola alturas entre ellas. El método de interpolación más utilizado es el mapeo cúbico de la curva S:

Suponga que tiene altura h0en el punto x0y altura h1en el punto x1. Luego, para obtener la altura en cualquier punto x( x0<=x<=x1), usa

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;

Las alturas obtenidas de esta manera serán suaves, aleatorias, pero no realmente interesantes. Para mejorar su terreno, puede usar el ruido fractal . Funciona así: suponga que ha generado una función h(x)que devuelve la altura en una coordenada dada (utilizando el método anterior). Esta función tiene una frecuencia, determinada por la frecuencia de las alturas del número entero original. Para crear un fractal, combina las funciones con varias frecuencias:

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

En este ejemplo, combino cuatro frecuencias: original, doble, 4 veces y 8 veces original, con frecuencias más altas con menos peso. Teóricamente, los fractales llegan hasta el infinito, pero en la práctica solo se requieren unos pocos términos. El fbmen la fórmula representa el movimiento browniano fraccional; este es el nombre de esta función.

Esta es una técnica poderosa. Puede jugar con multiplicador de frecuencia, con pesos de diferentes frecuencias, o agregar algunas funciones para distorsionar el ruido. Por ejemplo, para obtener una sensación más "rugosa", h(x)se puede cambiar a 1-abs(h(x))(suponiendo -1<=h(x)<=1)

Sin embargo, si bien todo esto es bueno, esta técnica tiene una seria limitación. Con un enfoque basado en la "altura", nunca puede tener "voladizos" del terreno. E imagino que son una característica muy agradable para tener en un juego tipo "Moon Buggy".

Agregar buenos voladizos es una tarea difícil. Una cosa en la que puedo pensar es que puedes comenzar con una "línea de altura" fractal y "teselarla" en una serie de splines o curvas bezier. Luego, la línea del terreno se definirá por varios "puntos clave". Aplique un poco de jitter a estos puntos clave: esto dará como resultado una deformación aleatoria del terreno, probablemente formando algunas formas interesantes. Sin embargo, las auto intersecciones del terreno pueden convertirse en un problema con este enfoque, especialmente con grandes cantidades de fluctuación.

No importa
fuente
4

Hay dos métodos populares para generar mapas de altura del terreno.

Algunas respuestas que se dan aquí ya se basan en el algoritmo del Diamante cuadrado, pero conocer el nombre facilita la búsqueda de más información. El ruido Perlin también tiene otros usos, por lo que es bueno verificarlo de todos modos.

msell
fuente
El OP está hablando de paisajes 2D de estilo mario, pero estos son buenos enlaces.
Tenpn
1

Mi idea sería crear una función de ruido suavizado. Primero con un método intNoise (int) que devuelve un int "aleatorio", pero que depende de la entrada. Si usa la misma entrada dos veces, el resultado será el mismo.

Luego use un método de suavizado para hacer un floatNoise (float) que usa los dos enteros alrededor de la entrada para construir un valor aleatorio.

Luego use la posición X como entrada y la Y como salida. El resultado será una curva suavizada pero con una altura aleatoria.

XGouchet
fuente