Í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