lunes, 25 de abril de 2016

Cómo escribir juegos para el ZX Spectrum. Capítulo 9

Índice de entradas

Esta serie de artículos han sido traducidos a partir del documento "How to Write ZX Spectrum Games" con permiso de su autor, Jonathan Cauldwell, un gran desarrollador de juegos para el Spectrum, os recomiendo visitar su Web donde está el texto original. El documento original, y por tanto esta traducción, tiene © Jonathan Cauldwell y solo puede duplicarse con permiso expreso por escrito de su autor.

Gráficos de fondo

Presentando bloques

Digamos que queremos escribir un sencillo juego de laberinto por pantalla. Tenemos que mostrar las paredes alrededor de las cuales el sprite del jugador debe ser movido, y la mejor manera de hacer esto es crear una tabla de bloques que se transfieren a la pantalla secuencialmente. A medida que avanzamos a través de la tabla encontramos la dirección del bloque gráfico, cálculamos su dirección de pantalla y volcamos el carácter a la pantalla.

Vamos a empezar con la rutina de visualización de caracteres. A diferencia de la rutina que necesitamos para que el sprite se acople a posiciones de caracteres, por suerte es más fácil calcular una dirección de pantalla para una posición de carácter de lo que lo es para píxeles individuales.

Hay 24 posiciones de celdas de caracter verticales y 32 posiciones horizontales en la pantalla del spectrum, por lo que nuestras coordenadas estarán entre (0,0) y (23,31). Las filas 0-7 caen en el primer segmento de pantalla, 8-15 en la sección media de la pantalla, y las posiciones 16-23 en la tercera parte de la pantalla. Tenemos suerte, el byte alto de la dirección de pantalla para cada segmento se incrementa en 8 de un segmento a otro, por lo que tomando el número de celdas verticales y realizando un and 24 inmediatamente obtenemos el desplazamiento del comienzo del segmento de pantalla que debemos abordar allí mismo. Añadir 64 para el inicio de la pantalla del Spectrum y tenemos el byte alto de nuestra dirección. Entonces tenemos que encontrar la celda de carácter correcta dentro de cada segmento, por lo que tomamos de nuevo la coordenada vertical, y esta vez usamos and 7 para determinar cuál de las siete filas estamos tratando de encontrar. Multiplicamos esto por el ancho en caracteres de la pantalla (32) y añadimos el número de celda horizontal para encontrar el byte bajo de la dirección de la pantalla. Un ejemplo adecuado es el siguiente:

; retorna dirección de la celda de carácter en (b, c).

chadd  ld a,b              ; posición vertical.
       and 24              ; ¿qué segmento, 0, 1 o 2?
       add a,64            ; 64*256 = 16384, memoria de pantalla del Spectrum.
       ld d,a              ; este es nuestro byte alto.
       ld a,b              ; ¿cuan es la posición vertical ahora?
       and 7               ; ¿qué fila dentro del segmento?
       rrca                ; multiplcar fila por 32.
       rrca
       rrca
       ld e,a              ; byte bajo.
       ld a,c              ; añadir la coordenada y.
       add a,e             ; mezclar con el byte bajo.
       ld e,a              ; dirección de pantalla en de.

Una vez que tenemos nuestra dirección de pantalla es un proceso sencillo el volcar el carácter a pantalla. Mientras que no estamos cruzando los límites de las celdas de caracteres la siguiente línea de la pantalla siempre caerá 256 bytes después de la de su predecesor, por lo que hay que incrementar el byte alto de dirección para encontrar la siguiente línea.

; Mostrar el caracter hl en (b, c).

char   call chadd          ; encontrar la dirección en pantalla del caracter.
       ld b,8              ; numero del pixel alto.
char0  ld a,(hl)           ; fuente del grafico.
       ld (de),a           ; transferir a la pantalla.
       inc hl              ; siguiente trozo de datos.
       inc d               ; siguiente linea de pixels.
       djnz char0          ; repetir
       ret

En cuanto a la coloración de nuestro bloque, lo hemos cubierto en el capítulo sobre detección de colisiones de atributos sencilla. La rutina atadd nos dará la dirección de un atributo de celda de carácter en (b, c).

Por último, tenemos que decidir qué bloque mostrar en cada celda de pantalla. Podemos pensar que tenemos 3 tipos de bloques para nuestro juego, podríamos usar un bloque de tipo 0 para un espacio, tipo 1 para el muro y tipo 2 para una puerta. Arreglaríamos los gráficos y atributos para cada bloque en tablas separadas en el mismo orden:

blocks equ $

; block 0 = caracter para espacio.

       defb 0,0,0,0,0,0,0,0

; block 1 = muro.

       defb 1,1,1,255,16,16,16,255

; block 2 = puerta.

       defb 6,9,9,14,16,32,80,32

attrs  equ $

; block 0 = espacio.

       defb 71

; block 1 = muro.

       defb 22

; block 2 = puerta.

       defb 70

A medida que avanzamos a través de nuestro tablero de hasta 24 filas y 32 columnas de bloques de laberinto cargamos el número del bloque en el acumulador, y llamamos a las rutinas fblock y fattr a continuación para obtener las direcciones del gráfico de origen y su atributo.

; Encontrar celda del gráfico.

fblock rlca                ; multiplicar el número de bloque por 8.
       rlca
       rlca
       ld e,a              ; despalzar a la dirección del grafico.
       ld d,0              ; sin byte alto.
       ld hl,blocks        ; dirección del bloque de caracteres.
       add hl,de           ; apuntar al bloque.
       ret

; Encontrar celda de atributo.

fattr  ld e,a              ; desplazamiento a la dirección del atributo.
       ld d,0              ; sin byte alto.
       ld hl,attrs         ; dirección del bloque de atributos.
       add hl,de           ; apuntar al bloque.
       ret

Usar este método significa que nuestros datos del laberinto requiere un byte de RAM por cada celda de carácter. Para un área de juego de 32 celdas de ancho y 16 bloques de alto esto significaría que cada pantalla ocupa 512 bytes de memoria. Eso estaría bien para 20 pantallas de plataformas como en el Manic Miner, pero si quieres un centenar o más de pantallas deberías considerar el uso de bloques más grandes de modo que requiera menos bloques cada pantalla. Mediante el uso bloques de celdas de caracteres de 16 x 16 píxeles en lugar de los 8 x 8 en nuestro ejemplo, cada tabla de pantalla requeriría sólo 128 bytes, lo que significa que podremos exprimir mas la memoria del Spectrum.

No hay comentarios:

Publicar un comentario