Páginas

13 febrero 2017

Sprites MSX · La OAM

Cuando tengamos definidos una serie de patrones de Sprites, podemos visualizarlos desde el lenguaje Basic con la instrucción PUT SPRITE, pero otra forma que podemos utilizar, sobretodo si trabajamos en Ensamblador o con C, se basa en escribir en una zona concreta de la VRAM llamada Object Attribute Memory (OAM).

En esta tabla se guarda la información de visualización de los planos de Sprites. Utiliza 4 Bytes para cada uno de los 32 planos disponibles, dispuestos en orden consecutivo y podemos definir la siguiente información:
  1. Coordenada Y
  2. Coordenada X
  3. Número de patrón.
  4. Color + EC (bit 7 Early Clock)
En los modos gráficos G1, G2 y MC (screen 1, 2 y 3), del TMS9918, esta se encuentra en la posición 1B00h, mientras que en los modos gráficos del V9938 esta tabla se ubicará en diferentes posiciones de la VRAM (ver Tabla 1).

Modo VRAM
G1,G2 y MC 1B00h
G3 1E00h
G4 y G5 7600h
G6 y G7 FA00h
Tabla 1. Tabla de Atributos de Sprite (OAM).

En los nuevos modos gráficos del V9938, el valor de color no se utiliza, ya que se necesita 16 bytes por plano de Sprite. Para ello se dispone de una extensión de la OAM. Como en los sprites del TMS9918, además de la información de color, también se incluye un bit para el Early Clock, otro para la combinación de colores (OR) y uno más para la colisión de Sprites (ver post: sprites del V9938). Esta tabla se encuentra en diferentes posiciones de la VRAM, dependiendo del modo de pantalla (ver tabla 2).

Modo VRAM
G3 1C00h
G4 y G5 7400h
G6 y G7 F800h
Tabla 2. Tabla de atributos de colores de Sprite.

Un detalle a tener en cuenta, es que cuando trabajemos con Sprites de 16x16, al asignar el número de patrón a un plano, tendremos que multiplicar su valor por 4, ya que es la forma interna de trabajar del VDP. Esto es debido a que se componen de 4 sprites de 8x8.

Si programamos en ensamblador, la BIOS del MSX contiene funciones que nos pueden facilitar algunas tareas. La función CALATR (0087h), nos devolverá en HL la dirección de la VRAM donde se encuentra la información del OAM, del número de plano indicado en A. Además, se ajusta al modo de pantalla que estemos utilizando, independientemente de la generación de MSX que se trate.

En el desarrollo de juegos. la visualización de Sprites se puede trabajar de varias formas: Podemos tocar los Sprites directamente en la VRAM cuando se requiera, como haríamos en Basic con Put Sprite, o se puede crear un buffer en RAM, que volcaremos a la VRAM en la interrupción de VBlank. Esta segunda puede ser la mejor opción si utilizamos muchos Sprites, sobretodo por que el acceso a RAM siempre será más fácil y rápido que a la VRAM.

Desde Basic también puede ser útil acceder directamente a la OAM con VPOKE, para casos que solo tengamos que modificar un parámetro de un plano de Sprite, como por ejemplo si queremos que se desplace horizontalmente solo necesitaríamos tocar el valor para la coordenada X.


Ejemplos 

Acceso a la OAM desde Basic:
10 REM EJEMPLO ACCESO AL OAM
20 SCREEN 1,2:REM screen 1 con sprites de 16x16
30 IX=BASE(8)::REM OAM para screen 1,2 y 3
40 PAT=BASE(9):REM tabla de patrones de sprite
50 FOR BC=PAT TO PAT+(2*32):VPOKE BC,255:NEXT
60 REM PUTSPRITE 0,(100,80),1,0
61 VPOKE IX,80:REM coordenada Y
62 VPOKE IX+1,100:REM coordenada X
63 VPOKE IX+2,0:REM n patron * 4 en sprites de 16
64 VPOKE IX+3,1:REM color negro
70 REM PUTSPRITE 1,(200,110),8,1
71 VPOKE IX+4,110:REM coordenada Y
72 VPOKE IX+5,200:REM coordenada X
73 VPOKE IX+6,(1*4):REM n patron * 4 en sprites de 16
74 VPOKE IX+7,8:REM color rojo
Descargar ejemplo 1: OAME.BAS


Referencias:

8 comentarios:

joanra dijo...

Muy buen artículo, me hiciste recordar las tardes que pasaba peleándome con los sprites y el BASIC de MSX. ¿Esta técnica que comentas es la que usaban en los juegos de cartucho... tipo Salamander de Konami?

Juan Morales dijo...

Acabo dee leer el artículo, muy interesante, estoy poniendo en pantalla sprites 16x16 en screen 2 con vpoke, mi pregunta: que ventajas tengo con el put sprite? velocidad?

mvac7/303bcn dijo...

Hola Juan!
No lo he probado, pero supongo que ha de ser más rápido. La instrucción PUT SPRITE hace muchas cosas detrás, como calcular la posición de la VRAM, escribir los cuatros atributos de un sprite y también realiza el calculo del número de patrón (para sprites de 16x16) y acepta valores negativos de la coordenada X, realizando el cálculo de posición y modificando el bit de Early Clock. Si solo necesitamos modificar la posición de un sprite solo tendremos que ejecutar dos VPOKEs (o uno si solo varia una coordenada), pero si trabajamos con pocos sprites quizás la diferencia no se aprecie. Sera cuestión de hacer un test! :)

Juan Morales dijo...

Gracias.No se nota la diferencia de velocidad, he hecho varias comprobaciones y la velocidad es la misma, me quedo con put sprite. Ya que estamos otra cuestión quetiene que ver poco con el artículo pero No se donde preguntar: He empezado a redefinir caracteres en screen1, pero como se detecta el obstáculo de un title manejando un sprite, en este.modo no funciona el.point para detectar el color, con el vpeek estoy muy verde y lo que he encontrado en revistas creo que es oara detectar caráctercon carácter en screen0, if vpeek (32*x+y)=nnumero de caracter...

mvac7/303bcn dijo...

Hola Juan.
Si, esa es la técnica, pero tendrías que dividir las coordenadas del sprite por 8 y apuntar a la tabla de la VRAM donde están los nombres de patrones (que es como lo suelen llamar en algunos manuales, aunque también se les conoce como tiles o caracteres), usando la instrucción BASE(), que para screen 1 es la 5. Quedaría de esta forma:

1000 HL = BASE(5) + (y/8)*32 + (x/8)
1010 A = VPEEK(HL)

Juan Morales dijo...

No lo pillo, podrias ponerme.un ejemplo cortito en el que el sprite toque al title? Sería de.gran ayuda, no quiero copiar listados, me gusta saber porqué suceden las cosas en el.programa, porque ese 32 serán las columnas de screen1? La varable Hl donde me.lleva? Si eltitle con que que tropieza elsprite es el número 200, como lo haría? Gracias de nuevo, pero me encanta pelearme con el msx y es mi.aficcion programar, me encanta, pero aunque hayan libros en Internet, con ejemplos entiendo mejor el.porqué de lo que sucede en pantalla. Un saludo.

mvac7/303bcn dijo...

Sobre el 32: Si, son el total de columnas. En esa linea se calcula HL que se corresponde con la dirección de la VRAM donde se encuentra el valor del tile que hay en las coordenadas (x,y) que le pases. Has de tener en cuenta que los sprites su posición se encuentra en la esquina superior izquierda y en tu motor de juego tendrás que programar para que controle el volumen de los sprites que uses, ya que no necesariamente un sprite ha de ocupar 16x16 puntos.

Para el caso de un sprite de 16x16 tendrías que mirar cada vez que mueves el sprite, que la forma del sprite no toque determinados tiles (preferiblemente un rango de tiles continuos que consideres sólidos). Para ello tendrías que consultar la rutina anterior para controlar los cuatro lados del sprite (x,y; x+16,y; x,y+16; x+16,y+16), para que el sprite solo se mueva si no se encuentra el obstáculo.

Por ejemplo, para el caso de que leyéramos del joystick la dirección derecha:
Notas: Tenemos las coordenadas de nuestro sprite en sx y sy. A partir del tile 200 se consideran sólidos.

100 REM mover a la derecha
110 x=sx+16:y=sy:GOSUB 1000
120 IF A<200 THEN x=x+1

999 REM GetTileByCoordinates
1000 HL = BASE(5) + (y/8)*32 + (x/8)
1010 A = VPEEK(HL)
1020 RETURN

Juan Morales dijo...

Ya he conseguido, con tu ayuda claro, hacer pruebas de sprites tocando tiles en screen1, y funciona, he colocado un marcador arriba donde está el valor de a, marcandome en número de carácter por el que pasa, también el valor de hl, que marca la situación del sprite en el mapa,digamos que algunas veces falla, tienes que hacer otro run para que el sprite detecte los caracteres sobre todo los que están solos, y tambien la variable a detecta el caracter enp antalla aunque no se vea, si están agrupados no da este fallo, al.ejecutar otra vez el programa todo bien, también hago un clear y pongo con't y funciona bien. De todas formas mil gracias, seguiré con 8x8 hasta que tenga soltura y ya entraremos en sprites 16x16.