¿Qué estás buscando?
Engine & platform

Patrones procedimentales que puedes usar con Tilemaps, parte 1

ETHAN BRUINS / UNITY TECHNOLOGIES Contributor
May 29, 2018|10 minutos
Patrones procedimentales que puedes usar con Tilemaps, parte 1
Para tu comodidad, tradujimos esta página mediante traducción automática. No podemos garantizar la precisión ni la confiabilidad del contenido traducido. Si tienes alguna duda sobre la precisión del contenido traducido, consulta la versión oficial en inglés de la página web.

Muchos creadores han utilizado la generación procedimental para añadir algo de diversidad a su juego. Algunas menciones notables incluyen Minecrafto, más recientemente, Enter the Gungeon y Descenders. Esta publicación explica algunos de los algoritmos que puedes usar con Tilemap, introducido como una función 2D en Unity 2017.2, y RuleTile.

Con mapas creados mediante procedimientos, puedes asegurarte de que no haya dos jugadas de tu juego iguales. Puedes utilizar varias entradas, como el tiempo o el nivel actual del jugador, para garantizar que el contenido cambie dinámicamente incluso después de que se haya creado el juego.

¿De qué trata esta entrada del blog?

Echaremos un vistazo a algunos de los métodos más comunes para crear un mundo procedimental y un par de variaciones personalizadas que he creado. A continuación se muestra un ejemplo de lo que podrá crear después de leer este artículo. Tres algoritmos trabajan juntos para crear un mapa, utilizando un Tilemap y un RuleTile:

Introducción al mundo procedimental
Introducción al mundo procedimental

Cuando generamos un mapa con cualquiera de los algoritmos, recibiremos una matriz int que contiene todos los datos nuevos. Luego podemos tomar estos datos y continuar modificándolos o representándolos en un mapa de mosaicos.

Es bueno saberlo antes de seguir leyendo:

La forma de distinguir entre lo que es un mosaico y lo que no lo es es mediante el uso del binario. 1 está encendido y 0 está apagado.

Almacenaremos todos nuestros mapas en una matriz de enteros 2D, que se devuelve al usuario al final de cada función (excepto cuando renderizamos).

Utilizaré la función de matriz GetUpperBound() para obtener la altura y el ancho de cada mapa para que tengamos menos variables en cada función y un código más limpio.

A menudo uso Mathf.FloorToInt(), esto se debe a que el sistema de coordenadas de Tilemap comienza en la parte inferior izquierda y el uso de Mathf.FloorToInt() nos permite redondear los números a un entero.

Todo el código proporcionado en esta publicación de blog está en C#.

Generar matriz

GenerateArray crea una nueva matriz int del tamaño que se le asigna. También podemos decir si la matriz debe estar llena o vacía (1 o 0). Aquí está el código:

Tipo de bloque desconocido "codeBlock", especifique un serializador para él en la propiedad `serializers.types`

Mapa de renderizado

Esta función se utiliza para representar nuestro mapa en el mapa de mosaicos. Recorremos el ancho y la altura del mapa, colocando mosaicos solo si la matriz tiene un 1 en la ubicación que estamos verificando.

Tipo de bloque desconocido "codeBlock", especifique un serializador para él en la propiedad `serializers.types`

Actualizar mapa

Esta función se utiliza únicamente para actualizar el mapa, en lugar de volver a renderizarlo. De esta manera podemos utilizar menos recursos ya que no estamos redibujando cada mosaico y sus datos.

Tipo de bloque desconocido "codeBlock", especifique un serializador para él en la propiedad `serializers.types`

Ruido de perlin

El ruido Perlin se puede utilizar de varias maneras. La primera forma en que podemos usarlo es crear una capa superior para nuestro mapa. Esto es tan simple como obtener un nuevo punto utilizando nuestra posición x actual y una semilla.

Simple

Esta generación adopta la forma más simple de implementar Perlin Noise en la generación de niveles. Podemos usar la función Unity para Perlin Noise para ayudarnos, por lo que no es necesario realizar ninguna programación especial. También nos aseguraremos de tener números enteros para nuestro mapa de mosaicos utilizando la función Mathf.FloorToInt().

Tipo de bloque desconocido "codeBlock", especifique un serializador para él en la propiedad `serializers.types`

Así es como se ve representado en un mapa de mosaicos:

Generación de mapas
Generación de mapas
Suavizado

También podemos tomar esta función y suavizarla. Establezca intervalos para registrar la altura de Perlin y luego suavice entre los puntos. Esta función termina siendo un poco más avanzada, ya que tenemos que tener en cuenta Listas de números enteros para nuestros intervalos.

Tipo de bloque desconocido "codeBlock", especifique un serializador para él en la propiedad `serializers.types`

Para la primera parte de esta función, primero verificamos si el intervalo es mayor que uno. Si es así entonces generamos el ruido. Hacemos esto a intervalos para permitir la suavización. La siguiente parte es trabajar suavizando los puntos.

Tipo de bloque desconocido "codeBlock", especifique un serializador para él en la propiedad `serializers.types`

El suavizado se realiza mediante los siguientes pasos:

- Obtener la posición actual y la última posición

- Obtener la diferencia entre las dos posiciones, la información clave que queremos es la diferencia en el eje y

- A continuación, determinamos cuánto debemos cambiar el impacto, esto se hace dividiendo la diferencia de y por la variable de intervalo.

Ahora podemos empezar a establecer las posiciones. Trabajaremos hasta llegar a cero.

Cuando lleguemos a 0 en el eje y, agregaremos el cambio de altura a la altura actual y repetiremos el proceso para la siguiente posición x.

Una vez que hayamos realizado todas las posiciones entre la última posición y la posición actual, pasaremos al siguiente punto.

Si el intervalo es menor que uno, simplemente usamos la función anterior para hacer el trabajo por nosotros.

Tipo de bloque desconocido "codeBlock", especifique un serializador para él en la propiedad `serializers.types`

Veamos cómo se ve renderizado:

Suavizado
Suavizado
Paseo aleatorio
Paseo aleatorio superior

La forma en que funciona este algoritmo es lanzando una moneda. Entonces obtenemos uno de dos resultados. Si el resultado es cara, nos movemos un bloque hacia arriba, si el resultado es cruz, nos movemos un bloque hacia abajo. Esto crea cierta altura en nuestro nivel al movernos siempre hacia arriba o hacia abajo. La única desventaja de este algoritmo es que parece muy cuadrado. Veamos cómo funciona.

Tipo de bloque desconocido "codeBlock", especifique un serializador para él en la propiedad `serializers.types`

Esta generación nos da una altura más suave en comparación con la generación de ruido Perlin.

Paseo aleatorio superior alisado

Esta generación nos da una altura más suave en comparación con la generación de ruido Perlin.

Esta variación de Random Walk permite un acabado mucho más suave que la versión anterior. Podemos hacer esto agregando dos nuevas variables a nuestra función:

  • La primera variable se utiliza para determinar cuánto tiempo hemos mantenido nuestra altura actual. Este es un número entero y se restablece cuando cambiamos la altura.
  • La segunda variable es una entrada para la función y se utiliza como nuestro ancho de sección mínimo para la altura. Esto tendrá más sentido cuando hayas visto la función.

Ahora sabemos qué necesitamos agregar. Echemos un vistazo a la función:

Tipo de bloque desconocido "codeBlock", especifique un serializador para él en la propiedad `serializers.types`

Como puedes ver en el gif a continuación, el suavizado del algoritmo de caminata aleatoria permite algunas piezas planas agradables dentro del nivel.

Lanzar una moneda
Conclusión

Espero que esto te haya inspirado a comenzar a utilizar algún tipo de generación procedimental en tus proyectos. Si desea obtener más información sobre la generación de mapas mediante procedimientos, consulte Procedural Generation Wiki o Roguebasin.com, que son dos excelentes recursos.

Puedes estar atento a la próxima publicación de la serie para ver cómo podemos usar la generación de procedimientos para crear sistemas de cuevas.

Si creas algo interesante usando generación procedimental, ¡no dudes en enviarme un mensaje en Twitter o dejar un comentario a continuación!

Generación procedimental 2D en Unite Berlin

¿Quieres saber más y obtener una demostración en vivo? También hablaré sobre patrones procedimentales para usar con mapas de mosaicos en Unite Berlin, en el mini teatro de la sala de exposiciones el 20 de junio. ¡Estaré por aquí después de la charla si quieres charlar un rato en persona!