Cómo organizar una mazmorra
Vamos con la segunda parte.
Ya he insistido mucho en esto, pero lo volveré a hacer: es muy importante que algunas ideas las dejemos claras desde el principio, y que seamos lo suficientemente organizados como para que en caso de tener que añadir nuevos detalles no sea tan difícil hacerlo, eso sí, sin que lo que tuviéramos antes deje de funcionar.
El motor que vamos a hacer será capaz de leer de unos ficheros toda la información necesaria para construir la mazmorra. En un principio vamos a preparar ese motor para que tenga lo mínimo indispensable, pero dejaremos los ficheros preparados para que se puedan utilizar en el caso de que más adelante añadamos funcionalidades nuevas (cosa que, espero, haremos).
La explicación que viene ahora puede ser un poco confusa en un principio, reconozco que no es fácil ya que es meter, de golpe, mucha información, pero espero que al final las ideas queden claras. Podríamos comparar nuestra mazmorra con un juego de Lego (o de Tente o de lo que más rabia os dé): tendremos un montón de piezas, las baldosas, que nos permitirán ir construyendo habitaciones; al juntar estas habitaciones nos encontraremos con una mazmorra completa. Si juntamos varias mazmorras tendremos el mundo.
Tendremos un fichero para cada baldosa. Inicialmente serán muy simplonas ya que no nos preocupa eso, pero más adelante se podrían usar archivos de programas 3D completos, ya que OpenGL nos da herramientas para importarlos. Por decirlo así, lo que tendremos en esos archivos será la descripción del modelo en 3D, es decir, las coordenadas de cada vértice, qué colores y texturas estamos usando. En el caso de los enemigos encontraremos además unos valores mínimos y máximos para sus atributos (fuerza, vida y demás, según el reglamento que usemos), lo que permitirá que los combates no sean exactamente iguales en cada ocasión.
Tendremos un fichero, después, para cada habitación. En él daremos bastante información, empezando por su tamaño en X e Y ("cinco baldosas de largo por siete de ancho"), siguiendo por una descripción del mapeado tal cual vimos en el anterior artículo y añadiendo además la información necesaria para las peculiaridades de cada una de ellas (con qué habitación conecta cada puerta, cuántos enemigos hay, de qué tipo son y dónde están, disposición y contenido de los cofres y trampas...).
Por último tendremos un fichero para la mazmorra. Principalmente encontraremos el listado completo de las baldosas que vamos a utilizar, los objetivos de la mazmorra, la primera habitación a visitar...
La clave de este sistema está en que con cada paso "hacia arriba" que damos, las propiedades que describimos en los ficheros son más generales: las baldosas describen algo muy específico, sólo se aplica a ellas mismas. Las mazmorras, en cambio, son muchísimo más generales, describen las características comunes a todas las habitaciones que las componen. Esta idea es muy importante porque a la hora de decidir qué vamos a poner en cada tipo de archivo vamos a tener que tenerlo muy en cuenta: ¿va a utilizarse algo en más de una habitación? Quizá fuera importante ponerlo en el archivo de mazmorra.
Un ejemplo claro podría ser el de un cofre: la baldosa que lo representa es un archivo que contiene el "dibujo" de un cofre, puede ser utilizada en todas las mazmorras porque no tiene más secreto que ése. El archivo de la mazmorra contendrá una "llamada" a ese fichero del cofre, pero únicamente para decir que en algún lugar vamos a encontrarlo: es en la habitación donde vayamos a encontrar el cofre donde pondremos qué tesoros o trampas tiene. ¿Por qué? Sencillo: podemos reutilizar el dibujo del cofre en tres habitaciones, pero sólo en una de ellas querremos que tenga dentro una cota de malla; al ser el "contenido del cofre" algo específico de cada habitación, sólo diremos su valor ahí.
Como dar el listado de baldosas
Como ya adelantamos en la anterior lección, en cada mazmorra vamos a tener unos
tipos de baldosas. Cada tipo de baldosa tendrá unas propiedades comunes, y podrá tener un número variable de "baldosas dentro del tipo". El ejemplo ya lo pusimos el otro día: podemos tener el tipo "suelo" (baldosas por las que podemos andar sin problema alguno) y dentro de éste las baldosas de arena, gravilla... Podemos tener en cambio el tipo "trampa" y sólo tener una baldosa (un foso).
Lo importante pues es ponernos a pensar qué tipos son los que debemos de poner seguro, cuales van a ser los "tipos básicos" que utilizaremos de momento. Ya tendremos tiempo de añadir luego tipos raros, especiales, en primer lugar deberíamos preocuparnos por trabajar bien los cimientos de nuestro juego.
Además de esto tenemos que pensar cómo vamos a dar el listado de las baldosas en el archivo mazmorra, de forma que nos permita coger un número variable de cada tipo de baldosa en cada mazmorra, o no dar ninguna si fuera el caso, dejando además preparado el programa para que cuando vayamos añadiendo más tipos de baldosas funcione igual.
Os voy a decir los tipos de baldosas que yo considero básicos, los que no pueden faltar. Más adelante ya incluiremos los tipos que sean necesarios, pero por ahora estos serán suficientes:
Baldosa "0": una baldosa vacía. No tiene archivo para describirla, no tiene representación en el juego, es simplemente un espacio en blanco. Puede parecer una chorrada que exista, pero resulta una de las más útiles a la hora de dibujar la mazmorra: los archivos de habitaciones nos darán unas resoluciones para una habitación cuadrada, pero poniendo "espacios en blanco" podremos dibujar pasillos en zig-zag sin problemas, dándole mucha más vidilla. Y esa es sólo una de las muchas aplicaciones, claro está.
Suelos: superficies sobre las que el protagonista podrá caminar heróicamente. Simplemente nos dejan andar por ellas, no modifican la velocidad, no hacen daño ni nada parecido.
Paredes orientadas arriba a la izquierda: Las paredes que se encontrarán situadas a la izquierda en la pantalla.
Paredes orientadas arriba a la derecha: Lo mismo pero a la derecha. ¿Por qué separarlas? Sencillo, con unas podremos caminar en ciertas direcciones y con las otras en otras distintas. Este dibujo lo va a ilustrar:
Aunque no esté exactamente en isométrica se ve bien la idea: podemos caminar en tres de las cuatro direcciones posibles (hacia abajo tanto izquierda como derecha y arriba a la derecha), sin embargo en la dirección restante no podemos pues nos chocaríamos contra la pared. En el caso de la pared a la derecha la situación es la misma pero variando esa dirección.
Vemos que no tendremos ninguna baldosa para las paredes de abajo a la izquierda y a la derecha, esto sucede así porque en la perspectiva que hemos elegido sólo entorpecerían el campo de visión, así que, simplemente, no se ven, cuando el personaje vaya a desplazarse comprobaremos que no se meta en una "baldosa 0" o que no intente pasarse de los límites y eso será suficiente, si bien podríamos crear un tipo "paredes de abajo a la izquierda" y derecha. La decisión es nuestra.
Esquinas interiores 1 (y 2): estas baldosas son un caso especial de pared, se puede avanzar en dos direcciones únicamente. Hay que distinguirlas de las esquinas "hacia fuera", que se pueden construir con baldosas de pared normales. Para aclarar esto vamos a utilizar de nuevo un dibujo:
(con las esquinas interiores a la derecha sería lo mismo pero al revés)
Puertas "arriba a la izquierda": y, análogamente, arriba a la derecha y abajo a la izquierda y derecha. Son baldosas muy similares a las de las paredes, pero si podemos abrir la puerta nos llevarán a otra habitación. En este caso sí es necesario hacer las baldosas de la parte de abajo para que podamos verlas.
Con este listado podríamos construir las habitaciones básicas dándoles el aspecto que deseáramos, aunque no hubiera efectos especiales.
Ahora queda la siguiente duda: ¿cómo listamos las baldosas? Sabemos que va a estar la baldosa 0 siempre, pero ¿qué sucede con las demás? En una mazmorra de hielo (cuyos suelos resbalarán) no tendría por qué haber ninguna baldosa de suelo "normal", ¿cómo hacemos para listar algunas y no todas las baldosas? Además tenemos que decir cuántas baldosas de cada tipo hay, pues el motor no sabe distinguir entre una baldosa de pared y otra de suelo por sí mismo (para él toda geometría es exactamente igual, somos nosotros los que decidimos que tal o cual cosa se puede atravesar o no).
La solución podría ser la siguiente: el motor va a consultar en orden los tipos de baldosas que hayamos definido, y se encontrará con un caracter y, quizá, un número. El caracter le informará de si estamos en una de estas tres posibilidades:
1) Tenemos baldosas de este tipo. Un número seguiría al caracter informando de cuántas tenemos.
2) No tenemos baldosas de este tipo, pero todavía quedan otras por leerse.
3) No hay más baldosas en este archivo, ya hemos acabado de listarlas.
A la primera le seguiría el nombre del archivo (o archivos) con las baldosas de ese tipo. A la segunda le seguiría el caracter del siguiente tipo de baldosas (de la que habrá o no más). A la tercera, en cambio, le seguirá el resto de la información de la mazmorra. Al terminar el listado completo de los tipos siempre pondremos el caracter 3.
¿Qué se consigue con esto? Imaginemos que en la primera versión de nuestro motor tenemos cinco tipos de baldosas. Los listamos como sea necesario para esta mazmorra y al final ponemos el caracter 3. Pasado un tiempo modificamos el motor y le añadimos un sexto tipo, cuando vayamos a leer las mazmorras antiguas podremos hacerlo sin ningún problema, pues al terminar de leer el quinto tipo nos encontraremos con el caracter 3 y se saltará el buscar un sexto (o séptimo, u octavo...) tipo. Podremos reutilizar los mapas antiguos sin problemas.
El último detalle a comentar en este artículo es el número variable de baldosas en cada tipo. Como ya hemos comentado, podremos tener distintos diseños para un mismo tipo de baldosas, lo que nos permitirá darle un poco de vidilla al mapeado (por ejemplo, imaginemos que tenemos una baldosa de tipo suelo que representa piedras, si tenemos tres diseños podemos hacer que el mapeado no parezca una trama repetida. Darle un aspecto algo más aleatorio, vamos, más realista).
Cuando leamos las baldosas iremos almacenando además de las propias baldosas la cantidad de cada tipo que tenemos. La idea es que el motor pueda identificar rápidamente de qué tipo es cada número identificativo dentro de un mapa.
Ejemplo tonto: pongamos que hay 4 tipos de baldosas, la 0, el suelo, pared izquierda y pared derecha. En una mazmorra tenemos 1 baldosa dentro de cada tipo, por lo que sabemos que si encontramos en un mapeado los siguientes números serán...
0: baldosa vacía
1: baldosa suelo
2: baldosa pared izda
3: baldosa pared dcha
Ahora miramos otra mazmorra, en ésta tenemos M baldosas de suelo, N baldosas de pared izquierda y P baldosas de pared derecha. Sabremos que en un mapeado los números serán...
0: baldosa vacía
1 a la M: baldosa suelo
(M+1) a la (M+N): baldosa pared izda
(M+N+1) a la (M+N+P): baldosa pared dcha
Poniendo valores, si por ejemplo M=3, N=2 y P=4, sabremos que los identificadores siguientes representan...
0: baldosa vacía
1 a la 3: baldosa suelo
4 a la 5: baldosa pared izda
6 a la 9: baldosa pared dcha
Por tanto, almacenando estos valores en memoria podremos consultar rápidamente si un valor está en un tipo u otro, independientemente de cuántos diseños de cada tipo de baldosa usemos en nuestra mazmorra actual. El 8 representará una pared a la derecha, el 2 un suelo.
Bien, de nuevo veo que ya se ha alargado mucho así que por ahora paramos aquí. Sé que en este artículo las ideas son más raras, es posible que esté explicado de forma muy confusa, así que os pido que toda pregunta que tengais no os la guardéis. Siento no haber entrado todavía en detalles más interesantes ni en cómo leeremos los tipos de enemigos y demás, aunque ya os podéis hacer una idea de cómo va a ir el asunto basándonos en esto mismo. De nuevo os insisto en que toda duda, sugerencia o pregunta sea dicha, que después de todo yo también quiero ver si me he equivocado en el planteamiento o no.