Los rompecabezas son una parte integral del juego para muchos géneros. Ya sea simple o complejo, desarrollar rompecabezas manualmente puede volverse engorroso rápidamente. Este tutorial tiene como objetivo aliviar esa carga y allanar el camino para otros aspectos del diseño más divertidos..
Juntos, vamos a crear un generador para componer rompecabezas simples "anidados" de procedimiento. El tipo de rompecabezas en el que nos centraremos es el tradicional "candado y llave" que se suele repetir como: obtener x elemento para desbloquear y área. Estos tipos de rompecabezas pueden volverse tediosos para los equipos que trabajan en ciertos tipos de juegos, especialmente los rastreadores de mazmorras, espacios de pruebas y juegos de rol en los que se confía más a menudo para el contenido y la exploración..
Al utilizar la generación de procedimientos, nuestro objetivo es crear una función que tome unos pocos parámetros y devuelva un activo más complejo para nuestro juego. La aplicación de este método proporcionará un retorno exponencial en el tiempo del desarrollador sin sacrificar la calidad de juego. La consternación del desarrollador también puede disminuir como un efecto secundario feliz.
Para seguir adelante, deberá estar familiarizado con el lenguaje de programación que elija. Dado que la mayor parte de lo que estamos discutiendo son solo datos y se generalizan en pseudocódigo, cualquier lenguaje de programación orientado a objetos será suficiente.
De hecho, algunos editores de arrastrar y soltar también funcionarán. Si desea crear una demo reproducible del generador mencionado aquí, también necesitará familiarizarse con su biblioteca de juegos preferida..
Vamos a empezar con un vistazo a algunos pseudocódigo. Los bloques de construcción más básicos de nuestro sistema serán las llaves y las habitaciones. En este sistema, a un jugador se le prohíbe entrar a la puerta de una habitación a menos que posea su llave. Así es como se verían esos dos objetos como clases:
Clave de clase Var playerHas; Ubicación var; Función init (setLocation) Ubicación = setLocation; PlayerHas = falso; Función pickUp () this.playerHas = true; Aula de clase Var isLocked; Var AssocKey; Función init () isLocked = true; assocKey = nueva clave (esto); Desbloqueo de funciones () this.isLocked = false; Función can Desbloquear If (this.key.PlayerHas) Return true; De lo contrario Devuelve falso;
Nuestra clase clave solo contiene dos datos en este momento: la ubicación de la clave y si el jugador tiene esa clave en su inventario. Sus dos funciones son la inicialización y la recogida. La inicialización determina los conceptos básicos de una nueva clave, mientras que la recolección es para cuando un jugador interactúa con la clave.
A su vez, nuestra clase de habitación también contiene dos variables: está bloqueado
, que mantiene el estado actual de la cerradura de la habitación, y AssocKey
, que contiene el objeto clave que desbloquea esta sala específica. Contiene una función para la inicialización, una para llamar a desbloquear la puerta y otra para verificar si la puerta se puede abrir en ese momento..
Una sola puerta y una llave son divertidas, pero siempre podemos condimentarlas con la anidación. Implementar esta función nos permitirá crear puertas dentro de las puertas mientras servimos como nuestro generador primario. Para mantener el anidamiento, también necesitaremos agregar algunas variables adicionales a nuestra puerta:
Sala de clase Var isLocked; Var AssocKey; Var parentRoom; Profundidad de var Función init (setParentRoom, setDepth) If (setParentRoom) parentRoom = setParentRoom; Else parentRoom = none; Depth = setDepth; isLocked = true; assocKey = nueva clave (esto); Desbloqueo de funciones () this.isLocked = false; La función puede desbloquear If (this.key.playerHas) Return true; De lo contrario Devuelve falso; Función roomGenerator (depthMax) Array roomsToCheck; Array terminado de habitaciones; Habitación initialRoom.init (ninguno, 0); roomsToCheck.add (initialRoom); While (roomsToCheck! = Empty) If (currentRoom.depth == depthMax) finishedRooms.add (currentRoom); roomsToCheck.remove (currentRoom); Else Room newRoom.init (currentRoom, currentRoom.depth + 1); roomsToCheck.add (newRoom); finishedRooms.add (currentRoom); roomsToCheck.remove (currentRoom);
Este código generador está haciendo lo siguiente:
Tomando en cuenta el parámetro para nuestro rompecabezas generado (específicamente cuántas capas de profundidad debe tener una habitación anidada).
Creación de dos matrices: una para las salas en las que se está comprobando el posible anidamiento y otra para registrar las salas que ya están anidadas.
Crear una sala inicial para contener la escena completa y luego agregarla a la matriz para que podamos verificarla más adelante.
Tomando la habitación en la parte frontal de la matriz para poner a través del bucle.
Verificación de la profundidad de la habitación actual en comparación con la profundidad máxima provista (esto decide si creamos otra habitación para niños o si completamos el proceso).
Establecer una nueva sala y poblarla con la información necesaria de la sala de padres.
Añadiendo la nueva sala a la roomsToCheck
Array y moviendo la habitación anterior a la matriz terminada..
Repetir este proceso hasta completar cada habitación de la matriz..
Ahora podemos tener tantas habitaciones como pueda manejar nuestra máquina, pero todavía necesitamos llaves. La colocación de llaves tiene un gran desafío: la solvencia. Donde sea que coloquemos la clave, debemos asegurarnos de que un jugador pueda acceder a ella. No importa lo excelente que parezca el caché de claves ocultas, si el jugador no puede alcanzarlo, queda atrapado. Para que el jugador continúe a través del rompecabezas, las teclas deben estar disponibles.
El método más simple para garantizar la solvencia en nuestro rompecabezas es utilizar el sistema jerárquico de las relaciones de objetos padre-hijo. Como cada sala reside dentro de otra, esperamos que un jugador tenga acceso al padre de cada sala para llegar a ella. Entonces, siempre que la clave esté sobre la sala en la cadena jerárquica, garantizamos que nuestro jugador puede acceder.
Para agregar la generación de claves a nuestra generación de procedimientos, pondremos el siguiente código en nuestra función principal:
Function roomGenerator (depthMax) Array roomsToCheck; Array terminado de habitaciones; Habitación initialRoom.init (ninguno, 0); roomsToCheck.add (initialRoom); While (roomsToCheck! = Empty) If (currentRoom.depth == depthMax) finishedRooms.add (currentRoom); roomsToCheck.remove (currentRoom); Else Room newRoom.init (currentRoom, currentRoom.depth + 1); roomsToCheck.add (newRoom); finishedRooms.add (currentRoom); roomsToCheck.remove (currentRoom); Array allParentRooms; roomCheck = newRoom; While (roomCheck.parent) allParentRooms.add (roomCheck.parent); roomCheck = roomCheck.parent; Key newKey.init (Random (allParentRooms)); newRoom.Key = newKey; Regreso de habitaciones terminadas; Else finishedRooms.add (currentRoom); roomsToCheck.remove (currentRoom);
Este código adicional ahora producirá una lista de todas las habitaciones que están por encima de su habitación actual en la jerarquía de mapas. Luego elegimos uno de esos al azar y configuramos la ubicación de la llave en esa habitación. Después de eso, asignamos la llave a la habitación que desbloquea..
Cuando se llama, nuestra función de generador ahora creará y devolverá un número determinado de habitaciones con teclas, lo que potencialmente ahorrará horas de tiempo de desarrollo!
Eso envuelve la parte de pseudocódigo de nuestro sencillo generador de rompecabezas, así que ahora vamos a ponerlo en acción.
Construimos nuestra demostración usando JavaScript y la biblioteca Crafty.js para mantenerla lo más liviana posible, lo que nos permite mantener nuestro programa bajo 150 líneas de código. Hay tres componentes principales de nuestra demostración como se describe a continuación:
El jugador puede moverse a lo largo de cada nivel, recoger llaves y desbloquear puertas..
El generador que usaremos para crear un nuevo mapa automáticamente cada vez que se ejecute la demostración..
Una extensión para que nuestro generador se integre con Crafty.js, que nos permite almacenar información de objetos, colisiones y entidades..
El pseudocódigo anterior actúa como una herramienta de explicación, por lo que la implementación del sistema en su propio lenguaje de programación requerirá algunas modificaciones..
Para nuestra demostración, una parte de las clases se simplifican para un uso más eficiente en JavaScript. Esto incluye eliminar ciertas funciones relacionadas con las clases, ya que JavaScript permite un acceso más fácil a las variables dentro de las clases.
Para crear la parte del juego de nuestra demostración, inicializamos Crafty.js, y luego una entidad de jugador. A continuación, le damos a nuestra entidad de jugador los controles básicos de cuatro direcciones y un poco de detección de colisión menor para evitar entrar a las habitaciones cerradas.
Las habitaciones ahora reciben una entidad Crafty, que almacena información sobre su tamaño, ubicación y color para la representación visual. También agregaremos una función de dibujo para permitirnos crear una sala y dibujarla en la pantalla..
Proporcionaremos claves con adiciones similares, incluido el almacenamiento de su entidad, tamaño, ubicación y color. Las teclas también estarán codificadas por colores para que coincidan con las habitaciones que desbloquean. Finalmente, ahora podemos colocar las teclas y crear sus entidades usando una nueva función de dibujo.
Por último, pero no menos importante, desarrollaremos una pequeña función auxiliar que crea y devuelve un valor de color hexadecimal aleatorio para eliminar la carga de elegir colores. A menos que te gusten los colores, por supuesto..
Ahora que tiene su propio generador simple, aquí hay algunas ideas para ampliar nuestros ejemplos:
Conecte el generador para permitir el uso en el lenguaje de programación que elija..
Extienda el generador para incluir la creación de salas de ramificación para una mayor personalización.
Agregue la capacidad de manejar múltiples entradas de habitaciones a nuestro generador para permitir rompecabezas más complejos.
Extienda el generador para permitir la colocación de llaves en ubicaciones más complicadas para mejorar la resolución de problemas de los jugadores. Esto es especialmente interesante cuando se combina con múltiples caminos para jugadores..
Ahora que hemos creado este generador de rompecabezas juntos, use los conceptos mostrados para simplificar su propio ciclo de desarrollo. ¿Qué tareas repetitivas te encuentras haciendo? Lo que más te molesta de crear tu juego?
Lo más probable es que, con un poco de planificación y generación de procedimientos, pueda hacer el proceso significativamente más simple. Esperamos que nuestro generador te permita centrarte en las partes más atractivas de la creación de juegos mientras recortas lo mundano..
Buena suerte, y nos vemos en los comentarios.!