En el desarrollo de videojuegos siempre han existido recursos y triquiñuelas de diseño con las que agilizar tareas repetitivas que de otra forma serían un coñazo de implementar. En en el icónico Asteroids, las rocas estelares que salían de las esquinas lo hacían de forma aleatoria aunque siguieran un patrón continuado de velocidad y trayectoria que se amoldaba a una serie de parámetros para que tuviéramos alguna posibilidad de destruirlos o esquivarlos. Aunque iguales conceptualmente, los movimientos que debíamos efectuar en cada partida eran completamente diferentes.
La cadencia con la que se generan los asteroides es progresiva, aunque su forma y trayectoria es totalmente aleatoria. Un entorno caótico que a su vez está totalmente controlado.
Si bien este ejemplo es peregrino de cojones, sirve como buen punto de partida para hacernos una idea aproximada de lo que supone no regirse por un guión completamente rígido para así poder sorprender al jugador constantemente sin arriesgar con ello el propio equilibrio interno del sistema. Esta filosofía tiene su reflejo en los métodos de programación y diseño que se utilizan durante el desarrollo.
Programación por procedimientos for dummies
También mal denominada ‘procedural’, hace referencia a un paradigma de programación para lenguajes de alto nivel en el que, a grandes rasgos, lo que se pretende es generar una serie de resultados a partir de una serie de entradas (lo que viene a ser un procedimiento) y utilizarlo para generar sistemas complejos de juego a partir de una serie de normas en vez de realizar cálculos y especificar el resultado que queremos de forma individual con el consiguiente gasto computacional, por lo que si se va a realizar una misma tarea cinco veces, mejor crear una sola expresión que se repita tantas veces como haga falta en vez de calcular las cinco operaciones por separado. El resultado, aunque no lo sepamos con exactitud, al menos será ‘válido’.
Ojo a los programadores de la sala, no me estoy refiriendo a programación funcional ni ninguna zarandaja técnica, sino al hecho de que puede resultar mucho más útil definir una serie de reglas rígidas para la generación de un programa con la intención de que, aunque el resultado sea cada vez diferente, se sustente en una serie de normas que le den consistencia a una supuesta (y agradecida en muchos casos) incertidumbre lúdica. Eso sí, no hay que confundir aleatorio con procedural. Me explico.
Un ejemplo práctico. Supongamos que en el videojuego que estamos creando pretendemos que nuestro héroe cruce un enorme y frondoso bosque en busca del castillo donde se encuentra la princesa de marras, pero para ello tenemos que derrotar antes al ogro sandunguero que posee la llave de su celda oculto en algún lugar del escenario. Según la idea que tengamos en mente podemos hacer dos cosas a la hora de implementar la idea:
– Desarrollo rígido: Cogemos y modelamos el puñetero bosque a mano, colocando cada arbusto, cada piedrecita y cada ñordo de cabra en unas coordenadas concretas del mapa independientemente de si estamos hablando de un entorno tridimensional desarrollado en Unity que en un tileset pixelado con algún Maker de andar por casa. Nos curramos un laberinto de la hostia echando más horas que un reloj y ubicamos en un punto del mapa el castillo y en otro al ogro.
– Desarrollo funcional: Nos sentamos un rato y pensamos en un algoritmo de generación de terrenos a partir de una matriz que interconecte un camino aleatorio rodeado de árboles hasta alcanzar tanto al ogro como al castillo, ubicándolos en dos lugares al azar del mapa a partir de una serie de normas que aseguren que existe una ruta transitable entre ambos puntos y el lugar de inicio. Tan solo tenemos que definir el tamaño del bosque y nuestro algoritmo hace el resto, con el aliciente de que podemos reutilizarlo para crear tantos bosques diferentes como nos de la gana o, como estarán empezando a suponer los lectores, crear un Minecraft, un Faster than Light… o un Spelunky.
La generación procedural necesita de una serie de valores de entrada que modifiquen la magnitud de las variables que se van a utilizar, de forma que siguiendo con el ejemplo, podríamos definir un valor de entrada de 1 a 10 que calibre el grado de ‘frondosidad’ del bosque. Y es a partir de entonces cuando surge la magia, pues de forma sabia se puede mezclar lo aleatorio, lo definido y lo moldeable para crear sistemas complejos sobre los que interactuar. ¿Hay alguien que no estuviera ya pensando en la generación de mundos del mencionado Minecraft?
Spelunky y la generación pseudo-aleatoria
Derek Yu es un tipo listo que no inventó la pólvora pero se las ideó para crear escopetas. El Spelunky que conocemos a día de hoy es un remake HD de la primera versión del juego que creó, utilizando Game Maker (ojo ahí), en 2008 para PC como freeware. Esto lo saben todos los sabihondillos, pero lo que no está tan en boca de todos es el hecho de que el desarrollador adaptó la idea vista en Spelunker, un videojuego para máquinas de 8 bits y salones arcade lanzado en 1983 que también recibió, además de varias secuelas, un remake con gráficos renovados en 2008.
De aquel juego se llevó la idea del espeleólogo descendiendo por peligrosas cavernas, las lianas y el hecho de que podemos hacernos daño si caemos desde mucha altura, las bombas, las gemas y demás objetos preciosos o el fantasma que aparece cuando pasamos demasiado tiempo en una misma zona. Lo que Derek Yu se sacó del sobaco fue un inteligentísimo sistema de generación de escenarios y una profundidad en el desarrollo del juego como pocas veces se ha visto. Un plataformas con el sambenito de ‘roguelike’ tan de moda está en los últimos tiempos en donde, por incongruente que parezca, la experiencia es tan aleatoria como milimétricamente planificada. Atención.
Como habrán comprobado los que ya han echado un buen puñado de horas al juego, en los niveles de Spelunky hay una serie de normas básicas que se cumple a rajatabla: siempre hay una vía libre entre la puerta de entrada y la de salida. Da igual que existan caminos sin salida, que aparezca un ídolo, el cofre especial para abrir con llave o una tienda donde comprar ítems; el camino debe existir.
Los niveles están compuestos por una matriz de 4×4 en la que se genera un camino fijo desde el nivel de entrada, situado en algún punto de la primera fila, hasta la última ubicada en la inferior. El siguiente mapa está generado a partir del código fuente del título original de 2008, pero su planteamiento es extensible al del remake:
Cada elemento de esa matriz es un bloque que a su vez está dividido en una cuadrícula de 10×8 elementos de un tileset. Existen cuatro tipos diferentes de bloques:
-
0: Es un bloque que no pertenece a la ruta de solución entre la entrada y la salida.
-
1: Es un bloque con salidas a la izquierda y a la derecha. Por defecto, el bloque donde se ubica la entrada es de este tipo.
-
2: Es un bloque con salidas izquierda, derecha e inferior.
-
3: Es un bloque con salidas izquierda, derecha y superior. El que hay encima suya siempre será de tipo 2.
No es complicado comprender el sistema. Para simplificar la mecánica, digamos que la generación de cada bloque se produce con la tirada de un dado de 5 caras: si sale un 1 o un 2, se genera el camino de solución hacia la izquierda, si sale un 3 o un 4, se genera el camino hacia la derecha, mientras que si sale un 5, la solución es hacia abajo. Si se llega a uno de los bordes laterales del escenario, automáticamente será un 5 también. Existen algunas restricciones más para dar coherencia al mapa final, pero se sobreentiende cómo va, ¿no?
A su vez, los elementos de la cuadrícula de cada bloque también tienen una serie de normas, de forma que aunque mantengan cada uno de ellos una estructura similar, las pepitas, los bloques desplazables, ítems y enemigos se colocarán de forma diferente cada vez siguiendo un sistema de distribuciones parecido al del párrafo anterior.
Con esto, Derek Yu consiguió que cada partida a su juego fuera completamente diferente, aunque gracias a la cantidad de condicionantes rígidos tenidos en cuenta, hay una serie de elementos comunes que siempre estarán ahí, ya sea la chica o el cofre con la llave, por citar alguna cosa sin destripar los enfermizos secretos que alberga el juego y que no tienen cabida en este texto sesudo, rico y para toda la familia.
¿Y qué pasa con todo esto?
Pues que con un poco de ingenio podemos conseguir, además de un considerable ahorro de cómputo y recursos, que nuestro videojuego sea la pera limonera para el jugador y expanda hasta el infinito y más allá su ciclo de vida. El hecho de que muchos videojuegos independientes lo utilicen es precisamente para estirar un desarrollo corto mediante muchas iteraciones consecutivas donde la curva de aprendizaje y la mejora paulatina en nuestros resultados sean la mayor compensación para el jugador.
Este tipo de programación tiene unas raíces mucho más locas que llevan al extremo el uso de semillas de generación como es el caso de Dwarf Fortress, que a partir de una cadena de entrada es capaz de construir de la nada un mundo con cientos de años de antigüedad, una orografía moldeada por el paso de los siglos y unos accidentes naturales consecuentes con su entorno, todo ello en un vomitivo y enternecedor ASCII, eso sí. También está lo que sucedió con The Elder Scrolls II: Daggerfall, que tan libre fue la creación de un entorno de miles de kilómetros cuadrados utilizando un sistema de generación pseudo-aleatorio que no había cojones de pasarse el juego de la cantidad de bugs que tenía.
La generación procedural es difícil de plantear pero mucho más barata y optimizable que una implementación manual, por no hablar de que abre una puerta que por desgracia cada vez está más cerrada en el desarrollo contemporáneo de videojuegos: la capacidad de sorprender. Si sabemos cuándo va salir ese zombie de la ventana o qué tipo de nave enemiga nos va a atacar en el siguiente punto, la situación se solventa mediante el ensayo y error, dejando a un lado la capacidad intrínseca del jugador para superar los desafíos a partir del conocimiento acumulado y su capacidad de deducción y previsión.
Fuentes
Imagen de cabecera | ma5h
Source Code de Spelunky (GM8) | http://spelunkyworld.com/original.html
Spelunky Generator Lessons | http://tinysubversions.com/spelunkyGen/
Entrada durilla para no programadores, pero más que justificada al hablar del trasfondo que se busca con este modo de generar escenarios. Sorprender. Olé ELROSSO
Le estuve pegando al juego original después de que me descubrieras su existencia en Twitter y ahí lo tengo en el escritorio para cuando me canso de UnEpic :-)
He intentado ser lo menos técnico posible, que si me llego a meter en temas de cálculos fractales o algoritmos GPAN para números pseudo-aleatorios acabamos todos epilépticos y en posición fetal.
Gran entrada!! Te falto mencionar nuestro querido Isaac
Sí señor, ese es otro gran ejemplo de generación muy parecido al usado por Spelunky, aunque algo menos complejo a la hora de conectar los escenarios. Al final es lo mismo: buen gameplay + repetir varias veces + desbloqueables y secretos.
Fantástica entrada!! Como programador no se me ocurre otra manera más sencilla de explicarlo.
Enhorabuena! :)
Solo como curiosidad, la programación procedural vale tanto para definir un nivel aleatorio como para geometría/comportamientos o lo que sea.
Muy agradecido :). Por haber, hay texturas para videojuegos generadas proceduralmente o sistemas de música procedural capaz de generarse de forma infinita a partir de seeds de entrada. He intentado centrarme en el ámbito del mapeado y diseño de videojuegos, pero es extensible a mil cosas más.
Sos un groso, pero no he entendido nada
Rosso, sos grosso.
No tenia ni idea de la existencia de Expelunker si sabia de la version free, que por cierto la musica me parece mil veces mejor a la version HD, y me parece que ha quedado bastante claro el tema. Buen articulo Rosso.
ElGRoSSo
Me gusta
Me lo he leído por encima pero ha sido intererante, sobre todo la parte de la generación pseudo-aleatoria de Spelunsky, siempre me había preguntado como se programaban los niveles aleatoriamente y que el resultado final tuviese sentido.
«Nos sentamos un rato y pensamos en un algoritmo de generación de terrenos a partir de una matriz que interconecte un camino aleatorio»
Cuando he llegado a este punto me he dado cuenta de que este era el artículo que llevaba queriendo leer desde hace años. Y no sé porqué, sospechaba que tenías que ser tú el que lo escribiera. Enhorabuena maestro!
Ahora que me has señalado algunos caminos, volveré a mi idolatrado DIV a ver si puedo sacar algo de provecho de todo esto ;)
¡Hombre, igual ya toca jubilar el DIV! Que el Castle of Dr. Malvado y el Fostiator ya se han quedado un poco old-gen :-P. El lenguaje de scripting del Game Maker Studio es una maravilla y también es un lenguaje de alto-alto nivel, no tan pseudocódigo como DIV pero por ahí.
Respecto a lo de sacar el sistema de diseño de videojuegos por mera observación sin oler código es la mejor forma de ejercitar las neuronas. Primero se empieza viendo cómo cada fantasma del Pac-Man tiene un comportamiento diferente y ya luego es un no parar de comerse la sesera por puro placer.
Me voy a colar en este comentario, porque así mato dos pájaros de un tiro (2x combo!)
En primer lugar, reitero las felicitaciones por exponer de forma simple un tema tan complejo, y además comentar que Squidi, de http://www.squidi.net/three/ lleva muchas entradas dedicadas a algoritmos de generación de mundos jugables en su serie «300 mecánicas de juego» (ya va por las 200), su sitio web es toda una mina de oro en la que un aspirante a desarrollador de videojuegos se puede perder horas y horas :-) mención especial a su última entrada, generación procedural de mazmorras: http://www.squidi.net/three/entry.php?id=203
Por otra parte, y esto va para hujiko, si estás acostumbrado al div, estoy de acuerdo con ElRoSSo en que es hora de cambiar, pero si te asusta salir de las aguas del div, métele mano al Bennugd, que viene a ser la evolución del div (tras pasar por fenix), y es muy sencillo (yo he hecho algunas cosillas con él, un editor de pixel art para la gp32 wiz), tienes más info en http://www.bennugd.org/es
Vaya pedazo de artículos los de Squidi, compañero. Apuntadísimos porque no los conocía. Lo de Bennu me provoca ardores de pensar en volver por aquello después de tantos años con saltos y transformaciones de la idea original de DIV. Indagaré a ver en qué estado está el proyecto.
Me ha parecido un artículo interesantísimo! Muchas veces me pregunto -sin ser programador- como se hacen estas cosas en los videojuegos, gracias por aportar luz al tema :)
Al final, el programador no hace más que trasladar a código una idea esbozada sobre una libreta. No son magos, tan solo escribas, eso sí, de cuya ortografía depende que el resultado final sea legible y útil, por lo que su labor es tan importante como la del que hace el diseño previo. Y si ambas cosas las hace una misma persona, DESPIPORRE.
Buen artículo, muy divulgativo. Lo cierto es que hace unos años no me acercaba a los juegos basados en generación aleatoria de componentes ni con un palo (excepto Diablo II y algún otro) porque consideraba que era más difícil crear una curva de dificultad ajustada y ofrecer una experiencia de juego compacta. Sigo pensando que algo de razón tenía, pero después de probar FTL, Isaac, Spelunky, Dredmor y demás roguelikes user-friendly, se ha convertido en uno de mis géneros favoritos. A ver si un día (o año) de éstos doy el paso con Nethack.
Ah y no sabía que el código de Spelunky estaba publicado, perfecto :D. Estoy casi decidido a lanzarme a la piscina con C++ (más SDL) por ser muy demandado en el mercado laboral, pero si finalmente opto por GameMaker me será muy útil.
Has matado a siete juntaletras de los de por aquí.
A mí me has hecho feliz.
Guau, vaya pedazo de articulo. No se mueve mucho en la trayectoria que se mueve el blog, pero la verdad es que explica bastante bien como hacer una creacion pseudoaletaoria pero que funcione. Ojala los videojuegos sigan esta tendencia de creacion aleatoria, aunque tambien esta bien tener un escenario comun y conocido al que volver no? De todas formas enhorabuena por el articulo. Normalmente pensamos que un videojuego casi se hace solo pero ay mucho trabajo y mucho desarrollo detras, y no es como pintar cuadros precisamente xd. Enhorabuena!
Increible entrada, guardada a favoritos, a veces jugueteo con Game Maker y por poco conocimiento soy de los que construyen todo pixel por pixel, algun dia me metere de lleno y vere como funciona realmente, los mundos aleatorios enamoran y son verdaderamente muy adictivos.
Buen articulo, muy interesante. Ahora enseñadnos a programar!!
xD
Pedazo de articulo se ha marcado el amigo Rosso, Chapeau!
Genial entrada. Como PsicoCooper, yo también desconocía el Spelunker y el Spelunky gratuito original…
Soy uno de esos que se han subido al carro de este juego tarde y, lo reconozco, a base de ver una y otra vez la ventanita de Steam informándome de que ciertos componentes de El Pixel Ilustre y otrxs ilustres gameros y gameras le daban muy fuerte. Ahora lo tengo en PSVita y Steam y es droja dura… precisamente uno de los motivos es lo que explicas por aquí.
A mi me ha parecido suficientemente equilibrado en lo técnico como para resultar interesante a quienes jugamos pero programamos jueguicos.
Impecablemente escrito y muy interesante
«pero NO programamos jueguicos» quería decir
Una preguntilla que me obsesiona mucho:
Que pros y contras tendría el minecraft si estubiera programado con otro lenguaje que no sea java ??? (mandenme un mensaje por facebook si pueden)
Not bad.
HOLA GUAPOS: http://www.gamerdic.es/termino/procedimental
Hala, háblenme como se debe.