En las entregas anteriores de este tutorial construimos el mundo base, dimos forma a las mecánicas principales e incorporamos un temporizador de UI y música de fondo. Ahora toca la generación del laberinto. Existen muchos algoritmos, pero aquí usaremos un enfoque sencillo con búsqueda en profundidad DFS tipo carve, que consiste en tallar recursivamente caminos aleatorios en una cuadrícula. Nota importante: la implementación carve utilizada requiere que el ancho y el alto de la cuadrícula sean números impares para que el laberinto se renderice correctamente.
Comienza creando un nuevo script dedicado a la generación del laberinto en el editor de escritorio y añádelo a un objeto llamado Maze. Igual que en otros archivos, importa los módulos necesarios desde GameUtils, en particular los elementos Events y GameState, ya que notificaremos el estado del juego cuando el laberinto esté listo y reaccionaremos a los cambios de estado para esculpir los caminos.
Define las propiedades del componente Maze a través de propsDefinition. Expón parámetros para personalizar el laberinto: wallDetailed y wallSimple como assets de muro, dimensiones físicas de los muros con wallWidth 4 y wallHeight 10, tamaño lógico de la rejilla con width y height impares, y referencias a startPosition y finishPosition para posicionar inicio y meta dentro del laberinto. Estas props permiten que el tamaño del laberinto y el tipo de muros sean configurables desde el editor.
Prepara los assets de muro. En el panel de Assets busca Maze Runner y añade los dos muros públicos: uno detallado y otro simple. Convierte cada uno en asset de tu librería con la opción crear asset y configúralos con Motion en animated. Renómbralos como WallDetailed y WallSimple. Luego elimina los objetos temporales del escenario para quedarte solo con los assets en la librería.
En el objeto Maze, asigna los assets a las props wallDetailed y wallSimple, deja wallWidth en 4 y establece width y height del laberinto en 9. Vincula startPosition al GameSpawnPoint y finishPosition al objeto Finish. Así el script podrá reubicar inicio y meta en celdas concretas cuando la rejilla esté construida.
Genera la rejilla del laberinto en memoria. Para ello, calcula el tamaño físico total multiplicando width y height por wallWidth. Determina la posición de arranque para dibujar desde la esquina suroeste: x es la mitad del ancho total, y es la mitad de wallHeight y z es menos la mitad del alto total. Recorre con dos bucles las filas y columnas en pasos de wallWidth creando una celda por posición. Cada celda guarda: referencia al entity del muro cuando se instancie, un tipo de celda que por defecto será W de muro, y las coordenadas x, y, z originales para poder resetear después.
Para aportar variedad visual, rota de forma aleatoria los muros detallados y usa una rotación fija para los muros simples. Crea un contador at_the_races que incrementa cuando comienzas a instanciar un muro y decrementa cuando el spawn finaliza. De esta forma controlas la condición de carrera mientras se van creando entidades de forma asíncrona. Cuando el contador llega a cero, significa que todos los muros han sido creados y puedes considerar la rejilla lista.
Al terminar de instanciar, asigna la rejilla walls a la propiedad interna del componente y emite el evento de cambio de estado usando Events para colocar el juego en estado Ready. En ese mismo momento reubica también las posiciones de inicio y fin dentro del laberinto: startPosition en la celda 1,1 de la rejilla y finishPosition cerca de la esquina opuesta usando las celdas penúltimas por fila y columna, elevando levemente la posición en Y si procede para que sea accesible.
Añade una función preStart que valide que width y height sean impares, y suscríbete al evento gameStateChanged. Cuando el estado cambie a Starting, invoca la función carve con coordenadas de arranque 1,1. Cuando el estado cambie a Finished, invoca resetWalls para restaurar todos los muros a su posición original. Así podrás generar un laberinto aleatorio en cada partida y restaurarlo al finalizar.
Implementa carve con un DFS recursivo clásico sobre la rejilla. Mantén un conjunto visited para no procesar la misma celda dos veces. En cada paso, baraja aleatoriamente las direcciones de movimiento posibles norte, este, sur, oeste y avanza en saltos de dos celdas para crear pasillos, derribando el muro intermedio entre la celda actual y la siguiente. Marca las celdas talladas como P de pasillo y, para simular que el muro desaparece, desplaza temporalmente hacia abajo la entidad del muro de esa celda y del muro intermedio. Repite recursivamente mientras te mantengas dentro de los límites internos de la rejilla para evitar cortar la pared exterior.
La función resetWalls recorre cada celda y, si su tipo es P, vuelve a situar su entidad de muro en la posición x, y, z originales y restaura el tipo a W. Con esto el laberinto vuelve a su estado inicial con todos los muros visibles cuando la partida finaliza.
Si previamente forzaste el paso a Ready en el controlador del juego, elimina esa transición automática del start para que el flujo correcto sea: Loading mientras se instancian los muros, Ready cuando la rejilla está lista, Starting al pulsar el botón de inicio e InGame durante la carrera. Al probar en el editor verás el texto Loading the Maze mientras se construye la rejilla, luego podrás iniciar la partida, ser teletransportado a la celda de inicio y, al alcanzar la meta, el sistema declarará al ganador.
Para dejar el mundo limpio, elimina los muros exteriores y el suelo del área de juego si ya no son necesarios y recoloca la meta para que no sea visible desde el lobby durante la carga del laberinto. Con esto, tu experiencia Maze Runner queda lista, con laberintos que se generan de forma aleatoria en cada partida. En la última parte de la serie añadiremos NPCs contra los que competir dentro del laberinto.
En Q2BSTUDIO desarrollamos soluciones de software a medida y aplicaciones a medida para gaming, industria, retail y más, integrando inteligencia artificial, ciberseguridad, servicios cloud AWS y Azure, servicios inteligencia de negocio y power bi, automatización de procesos y agentes IA. Si buscas llevar tu idea al siguiente nivel, descubre nuestro enfoque integral de desarrollo multiplataforma en software a medida y aplicaciones a medida y explora cómo la ia para empresas puede acelerar tus proyectos con modelos, pipelines y MLOps en servicios de inteligencia artificial. Nuestro equipo puede ayudarte a diseñar arquitecturas robustas, seguras y escalables, optimizando costes y rendimiento en la nube, y dotando a tus soluciones de analítica avanzada con power bi para una toma de decisiones basada en datos.
Palabras clave recomendadas para posicionamiento: aplicaciones a medida, software a medida, inteligencia artificial, ciberseguridad, servicios cloud aws y azure, servicios inteligencia de negocio, ia para empresas, agentes IA, power bi.