jueves, 26 de mayo de 2016

VOLCADO DEL BUFFER CON LDI (I): ORGANIZACIÓN DE LA MEMORIA




Este primer ejemplo va a consistir en realizar un programa que nos maneja (e imprime) a un sprite protagonista que podemos mover con las teclas OPQA y dispara con espacio; seis sprites (cinco de 2x2 caracteres y uno de 3x3) que podríamos llamar enemigos y el disparo.

Si no lo has hecho antes, bájate el código fuente de aquí VOLCADO DEL BUFFER CON LDI.

¿Qué significa el título de esta entrada?
A la hora de mover gráficos por la pantalla del spectrum, la forma más habitual de hacerlo es imprimir el gráfico, borrar el gráfico, mover el gráfico y volverlo a imprimir. Esto es lo que da sensación de movimiento. El problema es que la pantalla del Spectrum se refresca cada cierto tiempo, y si el haz de electrones coincide (que es muy probable) con la zona de tu gráfico cuando estás borrando e imprimiendo, se produce un parpadeo.
Esto te viene muy bien explicado aquí.
En la mayoría de juegos antiguos (digamos antes de 1984) se pueden ver estos molestos parpadeos.
Se crearon técnicas para disimularlos, pero aún así se notaba algo raro en los gráficos.

Una manera de solucionar esto es realizar todas las operaciones necesarias que se hagan en un buffer. Reservamos una zona de la memoria para estos menesteres y cuando hemos acabado con todos los sprites la volcamos a la pantalla real.

El problema de esto es que es mucho más lento que imprimir directamente en la pantalla, ya que hay que mover muchos datos. Por ello, la zona de juego no conviene que sea muy grande.

Para este volcado se podría usar la instrucción LDIR, pero es más rápido usar tantos LDI como caracteres de ancho tenga el buffer.

Todo esto es lo que voy a intentar explicar en esta sección.

Para que veas cómo va la rutina, ensambla el programa ejecutando AENSAMBLA.BAT y ejecútalo en un emulador desde la dirección 24000. Podrás mover a nuestro héroe, disparar y ver a los enemigos.

ORGANIZACIÓN DE LA MEMORIA

A la hora de programar un juego es muy importante organizar bien la memoria para que luego no nos dé problemas. Echa un vistazo en APRINCIPAL.ASM.





  • Al principio del todo aparece un INCLUDE "CONTENIDA.ASM". Como he comentado anteriormente, la memoria contenida llega hasta la dirección 32768 (8000h). Yo uso desde la dirección 24000 (5dc0h). Es cierto que hay más memoria contenida que se puede usar, en concreto desde el buffer de la impresora 23296 (5B00h), pero no suelo usar esas direcciones. Es una manía. Sólo apuré tanto en Knightmare 2ZX, ya que anduve muy justo de memoria. Pero si nos hace falta, podremos tirar de ellas.

  • Después pongo el origen del código en 32768. A partir de aquí va el buffer de la pantalla que lo he llamado PANTVIR. Su tamaño es TAMPAN que si miras al principio de CONTENIDA no es otra cosa que multiplicar le número del columnas por el de filas de nuestro buffer.  


    En este caso, el ancho de pantalla es de 24 caracteres, el alto es de 16, por lo tanto, el tamaño del buffer será 24*16*8=3072 bytes. Si buscas la etiqueta TAMPAN en APRINCIPAL.TXT, verás que tiene el valor C00h que en decimal es 3072. Vamos bien.

  • Al final de la memoria es donde coloco el resto del código que no está en el bucle principal.


    Incluyo las rutinas, los gráficos y las tablas para el control de los sprites.

  • Después va TVOLCADO. Es una tabla que creo en CONTENIDA con la primera dirección del cada línea de la pantalla real para que el volcado del buffer sea más rápido. Reservo 320 bytes.
  • Desde F500h hasta F800h está FONDOS, donde guardo el fondo del buffer que se machaca al pintar el sprite y que se recuperará después de volcar el buffer. Son 768 bytes pero depende del número de sprites que pinte y de su tamaño.
  • De F800h a FA00 están TABCOOR y TABCOO1, donde creo la tabla de direcciones de la primeras primeras líneas del buffer. Así, sabiendo la coordenada Y del sprite es muy rápido hallar la dirección donde imprimirle.
  • Para aprovechar memoria, y ya que de F800h a F900h hay 255 y sólo uso 192 como mucho (es la coordenada Y máxima que puedo usar) meto DATFON. Es una tabla que voy creando para meter los datos de los fondos guardados al imprimir cada sprite. Ocupa 6 bytes por sprite con lo que, en principio, con 60 bytes tenemos de sobra.
  • Lo mismo pasa con con SPIMP. Aprovecho 20 bytes para crear la cola de los sprites que tengo que imprimir. Son 2 bytes por sprite, osea que con 20 me vale
  • A partir de FA00h y hasta el final meto una tabla con los desplazamientos y rotaciones necesarios para mover los gráficos de dos en dos pixels como mínimo. Aunque nos ocupa memoria (unos 1500 bytes), nos ahorra una gran cantidad de tiempo.
  • El stack lo pongo al principio de CONTENIDA en FA00h ya que a partir de F900h sólo uso 192+20=212 bytes, con lo que tengo 43 para manejar la pila. SP siempre lo pongo en memoria NO contenida.

    Todo esto es sólo para comentar la estructuración de la memoria. En sucesivas entregas explicaré para que sirven todas estas tablas y cómo se usan




5 comentarios:

  1. Pufff tío...ésto es nivel demasiado avanzado para mi pero lo 8ntentaremos XD

    ResponderEliminar
  2. Pufff tío...ésto es nivel demasiado avanzado para mi pero lo 8ntentaremos XD

    ResponderEliminar
  3. No te preocupes. Más adelante explicaré cómo funciona todo esto. Por ahora sólo es para que veáis como organizó la memoria. Si pones un poco de interés, seguro que lo acabas entendiendo perfectamente. Si no ves algo claro, pregunta, por supuesto.

    ResponderEliminar
  4. En que archivo estan estas instruciones?:

    INCLUDE "ARUTINAS.ASM"
    INCLUDE "ASPRITES.ASM"
    INCLUDE "ATABLAS.ASM"

    no las pude encontrar.

    ResponderEliminar
  5. Están en APRINCIPAL.ASM al final del archivo donde se termina el bucle principal, sobre la línea 636.
    De todas formas, cuando no encuentres algo del código fuente, pulsa Control+B y te saldrá un cuadro donde puedes poner el término a buscar y te llevará a él.

    ResponderEliminar