Í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.
Temporización
El tiempo lo es todo. Un juego se arruina fácilmente si se ejecuta demasiado
rápido o demasiado lento. La mayoría de los juegos de Spectrum se ejecutarán
con demasiada rapidez si lo único que hacen es manipular unos sprites, y necesitan
ser ralentizados.
La instrucción Halt
Medimos la velocidad de un juego de Spectrum por la cantidad de tiempo que tarda
un recorrido completo del bucle principal, incluyendo todos los trabajos realizados
por las rutinas llamadas dentro de este bucle. La forma más sencilla de introducir
un retardo es insertar instrucciones halt, que espera por una
interrupción, en ciertos puntos del bucle principal para que espere hasta una
interrupción. Como el Spectrum genera 50 interrupciones por segundo, esto significa
que el bucle principal que tenga 1, 2 ó 3 de tales pausas se ejecutará a 50,
25 o 17 cuadros por segundo respectivamente, en tanto que el resto de procesamiento
no ocupa más de un cuadro para completarse. En términos generales, no es buena
idea tener el sprite del jugador moviendo más lentamente de 17 cuadros por segundo.
En realidad, la instrucción halt puede ser muy útil. En efecto,
espera a que la línea de exploración del televisión llegue al final de la pantalla.
Esto significa que un buen momento para borrar, mover y volver a mostrar un
sprite es inmediatamente después de un halt, porque la línea
de exploración no va a encontrarse con la imagen y no hay posibilidad de parpadeo.
Si tienes un panel de estado de tu juego en la parte superior de la pantalla,
esto significa que hay aún más tiempo para que la línea de exploración viaje
antes de que alcance la zona de sprites, y a menudo puedes manipular un
par de sprites después de una interrupción sin mucho peligro de parpadeo.
La instrucción halt también se puede utilizar en un bucle para
hacer una pausa durante períodos más largos. El siguiente código hará una pausa
de 100 cincuentavos de segundo (lo que son dos segundos).
ld b,100 ; duración de la pausa. delay halt ; esperar una interrupción. djnz delay ; repetir.
El reloj del Spectrum y la rutina Vsync
Por desgracia, halt es un instrumento sin punta. Siempre espera
a la siguiente interrupción independientemente del tiempo que quede para la
siguiente. Imagina una situación en la que el bucle principal tarda 3/4 del tiempo del
cuadro para hacer su procesamiento la mayor parte del tiempo, pero de vez en
cuando tiene períodos en los que hay un procesamiento adicional que tarda medio tiempo de
cuadro adicional. En estas circunstancias, un halt mantendrá
el juego a la constantes de 50 cuadrod por segundo la mayoría de las veces,
pero cuando el procesamiento adicional entra en acción, la primera interrupción
ha pasado y halt esperará hasta la siguiente, lo que significa
que el juego se ralentiza a 25 cuadros por segundo periódicamente.
Hay una manera de evitar este problema, consiste en contar el número de
cuadros que han transcurrido desde la última iteración del bucle principal.
En el Spectrum, la rutina de servicio de interrupción de la ROM actualiza el
contador de cuadros de 24 bits del Spectrum 50 veces por segundo, y tambien hace
otras cosas. Este contador es almacenado en las variables del sistema en la
dirección 23672, por lo que mediante la comprobación de esta ubicación una vez
en cada iteración del bucle, podemos saber cuántas interrupciones se han producido
desde la última vez que estuvimos en ese mismo punto. Naturalmente, si quieres
escribir tu propia rutina de manejo de interrupción, puedes utilizar o bien en primer
lugar rst 56 para actualizar el reloj, o bien incrementar un contador
de cuadros por ti mismo si deseas utilizar este método.
La siguiente rutina vsync está diseñada para estabilizar un
juego y hacerlo funcionar a un nivel más o menos constantes de 25 cuadros por
segundo:
wait ld hl,pretim ; carga el temporizador anterior. ld a,(23672) ; carga el temporizador actual. sub (hl) ; diferencia entre los dos. cp 2 ; ¿ya han transcurrido dos cuadros? jr nc,wait0 ; sí, no más demora. jp wait wait0 ld a,(23672) ; carga el temporizador actual. ld (hl),a ; guardar su valor como anterior. ret pretim defb 0
En lugar de simplemente esperar en un bucle, se podría realizar alguna procesamiento adicional no esencial. Este es un buen punto en el que poner cualquier efecto de sonido del altavoz. Una buena idea es cuando lo necesites establecer un byte para indicar el tipo de efecto de sonido a reproducir, y a continuación comprobar este octeto en tu rutina vsync y llamar a la rutina correspondiente al efecto de sonido. Tus rutinas de efectos de sonido también necesitarán controles periódicos para ver si el contador de cuadros ha llegado a su fin, y salir cuando lo ha hecho.
Hay otras cosas que tal vez quiera hacer con este tiempo de CPU. Yo a veces renuevo mis sprites en la tabla que los mantienen, cambiando el orden en que
se muestran en cada bucle para ayudar a prevenir el parpadeo.
Semilla de Números Aleatorios
El contador de tramas del Spectrum es útil para otra cosa: se puede utilizar
para inicializar la semilla de los números aleatorios. Utilizando el generador
de números aleatorios propuesto en el capítulo de números aleatorios, podemos
hacer esto:
ld a,(23672) ; temporizador actual. ld (seed),a ; establece primer byte de la semilla de aleatorios.
Esto va bien si estamos trabajando con el hardware real y nos asegurará que un juego no comience con la misma secuencia de números aleatorios cada vez que se juega. Por desgracia, los autores de los emuladores tienen la mala costumbre de cargar automáticamente los archivos de cinta una vez abiertos, una práctica que no sólo hace difícil el desarrollo, da lugar a que la máquina esté siempre en el mismo estado cada vez que el juego se cargue, es decir, los números aleatorios pueden seguir la misma secuencia cada vez que se juega a ese juego. La solución para el programador de juegos es esperar a que se pulse una tecla tan pronto como nuestro juego ha cargado, después de lo cual podemos configurar nuestra semilla. Esto introduce un elemento humano y asegura que el generador de números aleatorios es diferente cada vez.
No hay comentarios:
Publicar un comentario