Hace unos días me llegó, por Twitter creo recordar, la noticia de que había un nuevo concurso, convocado por Radastan en su WEB Bytemaniacos, de programación en juegos en BASIC para uno de los ordenadores de los años 80 más significativos: El Sinclair ZX Spectrum.
Aprovechando unos días libres en el trabajo me planteé hacer algo rápido para presentar a concurso y quitarle el óxido un poco a la cabeza. Lo primero que tenía claro es que el desarrollo pudiese terminarlo rápido porque, si se prolongaba en el tiempo, se quedaría en el olvido como otros muchos proyectos.
Dos semanas antes había ocupado mi tiempo libre en trastear con otro viejo ordenador que tengo de la misma década, el Macintosh SE.
Metiendo juegos al ordenador de la manzana multicolor vi uno que me llamó la atención: el Dead End, un juego programado entre los años 1993 y 1998 por Wolfgang Thaller. Éste es un juego con un planteamiento muy sencillo pero, como muchos juegos de ésta índole que te obligan a pensar fuerte, muy adictivo. Al menos a mí me encantan los juegos tipo puzzle. Se me había pasado por la cabeza hacerlo en ensamblador pero, al ver el concurso, pensé que era una buena idea para aprovechar y hacerlo en BASIC.

El juego es tan sencillo como hacer llegar a nuestro personaje, que se encuentra en el interior de una habitación, hasta la salida de la misma. El problema es que dicha habitación está llena de obstáculos en forma de cajas que necesitamos mover para abrirnos camino. Para poder mover las cajas se tienen que dar dos circunstancias: que el hueco al que queremos desplazar la caja esté libre y que, detrás de nuestro personaje, tengamos hueco para coger impulso.
Ya tenía tres cosas claras: Que quería presentar un juego al concurso, que tenía que tardar poco en hacerlo y, por último, el juego que iba a ser. Ahora había que ponerse manos a la obra.
Antes de continuar, quiero dejar claro que esto no es un curso de programación, simplemente es la experiencia en sí. No voy a explicar cómo he hecho cada cosa. El código está disponible y hay infinidad de cursos en BASIC por la red bastante mejores de lo que yo pueda contar por aquí.
A estas alturas programar directamente en un Spectrum es pesado y se pierde mucho tiempo. Se puede programar en un PC actual y usar herramientas para generar el código. Como el juego a programar era en BASIC las herramientas a utilizar eran de fácil elección: bas2tap, un programa que te genera, a partir de un fichero de texto con el programa en BASIC, otro fichero en formato TAP para cargar en el ordenador con el programa ya generado. Como editor de textos he utilizado el que suelo emplear cuando programo algo y al que estoy acostumbrado: el Sublime Text. Y como emulador para ir probando el juego he usado FUSE para macOS.
Lo primero fue analizar el juego en cuestión, para ello lo cargué en mi Macintosh SE y me dediqué a ver la mecánica, simple como he dicho, y los niveles. Afortunadamente no tuve que jugar los 41 niveles standard con los que cuenta el juego («afortunadamente» por tiempo. Los jugaré), ya que da la opción de cargar el que quieras jugar. Así que los «visité» todos y los fotografié. En la captura superior se puede ver el nivel 3, que lo he incluido en la versión de Spectrum.
La primera decisión que tomo es meter unos diez niveles del original. Lo más complicado, al menos para mí y una vez programado el juego, es diseñar niveles y dotarlos de una dificultad adecuada. Si podía aprovechar los ya creados al menos por esa parte tenía el trabajo hecho.
Empecé por programar el mapeador y tenía que sentar algunas reglas: La disposición en pantalla iba a ser una matriz de 16×11 tiles, de dos caracteres de alto por dos de ancho cada uno. También decidí no adornar la zona de juego con un marco, ya que esto me quitaría un tile horizontal y otro vertical de la zona de juego. También que iba a codificar toda la zona de juego, independientemente del tamaño del nivel. Esto haría que ocupase más memoria pero me complicaría menos a la hora de programar. Los datos de cada pantalla ocupan 176 bytes (Esto es cierto y es falso a la vez. Los datos ocupan eso, pero almacenarlos en BASIC es más pesado y ocupan mucho más). Más dos al final que indican las coordenadas X e Y de inicio del personaje en el nivel correspondiente.
Los datos codificados pueden significar lo siguiente: 0 si no hay nada; 1 si es un muro infranqueable, 2 si es un objeto que podemos empujar y, por último, 3 para la salida del nivel.
En el juego original hay un tipo de bloques que podemos empujar nada más en una dirección marcada en los mismos. Prescindo de ellos. Igualmente decido no permitir que se haga «undo» en el juego. Es algo que no es muy complicado de hacer, pero que suma tiempo. Misión no tardar.
El mapeador lo programé en un ratillo, es algo sencillo y, el principal problema que manejé, fue la velocidad del BASIC del Spectrum al ejecutar el programa. A la velocidad de la máquina se une el hecho de que el BASIC es un lenguaje interpretado. Volcar todos los tiles de la pantalla se vuelve lento. Hay formas de imprimir más rápidas, pero no las consideré adecuadas. Lo primero que volcaba eran letras, las que se corresponden a los gráficos definibles por el usuario. Los gráficos eran un problema que, de momento, prefería no tener en la cabeza. Se me da fatal dibujar.

Para almacenar los datos de cada nivel descarto usar matrices. Guardo los datos codificados del nivel y, cada vez que necesito volcar a pantalla el nivel, los guardo en un buffer de memoria para actualizarlo con cada movimiento. Es rápido y se hace a la par que se dibuja. Bien podría haberlos volcado a memoria y cargado como un bloque de datos, pero quería hacerlo todo transparente de cara al concurso.
El primer nivel que codifico se corresponde con el primer nivel del juego original para Macintosh.
Lo siguiente que hago es programar el movimiento del personaje. Va a ser carácter a carácter, de 8 en 8 píxeles, que es como imprime naturalmente el BASIC del Spectrum. Además esta parte será el bucle principal del juego.
Las casuísticas que se nos pueden dar en el movimiento son pocas:
- Que el hueco a ocupar esté vacío (tipo 0) y por tanto nuestro personaje se pueda desplazar a él.
- Que se encuentre con un muro (tipo 1) y no pueda desplazarse.
- Que se encuentre con un objeto que podemos desplazar (tipo 2) y, a su vez, se pueden dar tres situaciones:
- Que el hueco al que queremos desplazar esté ocupado por otro objeto o por el muro y no se pueda mover.
- Que el hueco esté libre, pero no tengamos espacio detrás del personaje para tomar impulso y, por tanto, no se puede mover.
- Que tanto el hueco al que queremos desplazar el objeto como el hueco detrás nuestro estén libres y podamos ejecutar el movimiento.
- Por último, que nos encontremos con la salida (tipo 3) y con ello finalicemos el nivel.
Una vez programado el movimiento, cosa que no dio problema alguno, codifiqué un segundo nivel que luego deseché, más sencillo, para ir probando todos los movimientos que se podían dar y testear que no fallaba el motor de movimientos. A la par le di las primeras pinceladas al interface, por llamar de alguna forma a los marcadores de nivel y movimientos, que en un principio iban a ir en la parte superior machacando la primera línea de «muro». También le puse unos sonidillos, no demasiado cargantes (cosa difícil con el beeper del Spectrum), para los pasos del personaje. El motor del juego ya estaba hecho.

Seleccioné el resto de niveles a incluir, hasta un total de diez. La elección de la cifra había sido establecida al inicio. Pero tuve suerte de encontrar diez niveles. La mayoría de los originales ocupan más de los 16×11 tiles y no me servían sin adaptarlos. Alguno de los niveles seleccionados los roté, ya que en la versión de Macintosh tenían más alto que ancho y tal cual no entraban, pero sí girándolos.
De haber sido más niveles y con más número de tiles diferentes, habría usado un programa como Tiled para codificarlos. Pero como no era así los codifiqué a mano, con una imagen del nivel en un lado de la pantalla y en el otro la ventana del código. Es un poco arcaico, pero fue rápido.
Una de las tareas que más me divirtió fue probar cada uno de los diez niveles para comprobar que se podían terminar. Algunos de ellos me costaron muchos intentos. Un par de ellos no fui capaz y no creo que se pudiesen terminar, por algún error en el diseño, así que los retoqué ligeramente para que pudiesen finalizarse.

Llegados a este punto quedaba por programar el menú del juego (por primera vez no lo he hice al inicio del desarrollo 😀 ) y el salto al siguiente nivel al finalizar el actual.
Y envié el programa a Fede y a Javi, para que le pegaran un vistazo. No quería enseñar nada hasta no tenerlo hecho, que tengo el Git lleno de proyectos a medio empezar, más que a medio terminar.
Y aquí se lió. Yo había hecho un par de gráficos muy básicos. La salida del nivel estaba compuesta con cuatro gráficos predefinidos del juego de caracteres de la ROM. Para los gráficos del juego pensé utilizar los caracteres redefinibles por el usuario (UDG) El muro era algo… bueno, mejor lo enseño. No estaban todos, pero los que hay se las traen.

Y Javi me devolvió lo siguiente a los pocos minutos:

Así que me tocó programar de nuevo parte del motor, ya que mi idea inicial era que cada carácter de los cuatro que componen cada tile fueran del mismo color. Ya saben: sarna con gusto no pica. Algo parecido pasó con Sokoban cuando lo hicimos. El juego era un truño visualmente, hasta que Javi metió mano con los gráficos.

Programo el menú de inicio y el cambio de nivel. Decido que se puede jugar cualquier nivel en cualquier orden, sin necesidad de jugar los anteriores. Además, cuando terminemos el nivel 10, saltaremos al 1.

Igual que antes, envío el juego y me vuelve a responder Javi con lo siguiente sobre el menú:

Más cambios a realizar…
El juego estaba finalizado y mejorado con los consejos de Fede y Javi. Dos días y, calculo, unas diez horas de trabajo. Realmente lo más laborioso, en mi opinión siempre lo es, es dar el acabado al juego, retocar detalles, pequeños ajustes que diferencian mucho las cosas. Es en lo que más tiempo empleo. Al final ha quedado un juego sencillo para un concurso que me ha hecho pasar un buen rato programando. Casi he tardado más en escribir ésta entrada que en programar el juego.
Si has llegado hasta aquí, con el tocho que he escrito, enhorabuena y gracias. Tienes mucha paciencia.
Os dejo una galería con los niveles del juego y las diferentes pantallas de menú e info:
Dead End_ Menu
Referencias:
- La página del concurso de programación en BASIC 2020 de Bytemaniacos y descarga del juego.
- Dead End para Macintosh, con vídeo incluido, en Macintosh Repository.
- Dead End en Macintosh Garden.
- Dead End_ en Compiler Software, nuestra WEB con las cositas que hacemos.
- Dos entradas en este blog sobre el Macintosh SE: Sobre crear floppys y sobre instalar el sistema operativo.
- bas2tap, Como utilizarlo y descarga en el Wiki de Speccy.org.
- Tiled, para crear mapeados con tiles.
- Comentario sobre Dead End_ en El mundo del Spectrum.
- Comentario sobre Dead End_ en Ready and Play.
- Comentario sobre Dead End_ en Planeta Sinclair. (En portugués)
- Vídeo comentando Dead End_ de Javi Ortiz, el Spectrumero, a partir de 1h y 12m.