top of page

Entendiendo un sprite animado en MSX2 con MSXgl

  • Foto del escritor: MoltS Xalats
    MoltS Xalats
  • hace 21 horas
  • 5 Min. de lectura
Sam
Sam

Una introducción paso a paso para neófitos

 

Programar gráficos en un MSX puede intimidar al principio: VDP, VRAM, sprites, hooks del BIOS…

 

Pero con MSXgl, muchas de estas complejidades quedan encapsuladas en funciones claras y coherentes.

 

En este artículo veremos cómo funciona un sprite animado de 16×16 píxeles en MSX2, desde el patrón en memoria hasta la animación en pantalla, explicando todas las llamadas importantes sin necesidad de conocer el hardware a bajo nivel.


El punto de partida: ¿qué es un sprite en MSX?

 

En el MSX clásico:


  • Un pattern es un dibujo de 8×8 píxeles, codificado en 8 bytes.

  • Un sprite de 16×16 está formado por 4 patterns de 8×8.

  • El orden no es intuitivo: el VDP espera


Top-Left, Bottom-Left, Top-Right, Bottom-Right.

 

En nuestro ejemplo, el personaje Sam tiene:


  • 2 frames de animación (idle y walk).

  • 2 capas de sprite:

    • BODY (cuerpo)

    • DETAIL (contorno o detalles)

 

En total: 16 patterns (16 × 8 bytes).


Dibujando a Sam: los patterns en memoria

 

Todos los patterns están definidos en un único array:


const unsigned char g_DataSprt16_Sam[];


Este array todavía no es VRAM, sino memoria RAM normal.

Cada grupo de 8 bytes representa un tile de 8×8.

 

Para facilitar la lectura, definimos una función auxiliar:


static const u8* TilePtr(u8 tileIndex)

{

    return g_DataSprt16_Sam + ((u16)tileIndex * 8);

}


Así podemos decir: “Carga el tile número 3” sin preocuparnos de offsets ni cálculos manuales.


Comprobando que estamos en MSX2


Antes de usar SCREEN 5, debemos asegurarnos de que el ordenador lo soporta:


if(g_MSXVER == 0)

{

    Bios_ClearScreen();

    Bios_TextPrintSting("MSX2 required");

    Bios_GetCharacter();

    return;

}


  • g_MSXVER es una variable global proporcionada por MSXgl.

  • Si vale 0, estamos en MSX1.

  • Mostramos un mensaje en modo texto y salimos de forma elegante.

 

Inicializando el modo gráfico (SCREEN 5)

 

Ahora sí, entramos en territorio MSX2:


VDP_SetMode(VDP_MODE_SCREEN5);

VDP_SetColor(COLOR_BLACK);


Esto configura el VDP en SCREEN 5 (256×212, bitmap).

 

Para limpiar la pantalla usamos un comando del VDP, mucho más rápido que pintar píxel a píxel:


VDP_CommandHMMV(0, 0, 256, 1024, COLOR_MERGE(COLOR_BLACK, COLOR_BLACK));

VDP_CommandWait();


  • HMMV = High-speed Move, Fill

  • Rellena una gran zona de VRAM con negro.

  • VDP_CommandWait() asegura que el VDP ha terminado antes de continuar.

 

Activando y configurando los sprites

 

Los sprites tienen tablas propias dentro de la VRAM:


VDP_EnableSprite(TRUE);

VDP_SetSpritePatternTable(0x17000);

VDP_SetSpriteAttributeTable(0x17A00);


Aquí indicamos:

  • Dónde vivirán los patterns de sprite.

  • Dónde vivirá la tabla de atributos (posición, forma, color…).

 

Y definimos el formato global:


VDP_SetSpriteFlag(VDP_SPRITE_SIZE_16 + VDP_SPRITE_SCALE_2);


Es decir:


  • Sprites de 16×16.

  • Escalados ×2 → visualmente 32×32.

     

Cargando los patterns en la VRAM

 

Ahora copiamos los dibujos desde RAM a VRAM:


VDP_LoadSpritePattern(TilePtr(...), pat, 1);


Esta función:


  • Copia 1 pattern de 8 bytes.

  • En la posición pat de la Sprite Pattern Table.

 

Es importante respetar el orden del VDP:

 

Top-Left (1) → Bottom-Left (2) → Top-Right (3) → Bottom-Right (4).

 


Sam idle pattern
Sam idle pattern

Por eso el código carga los patterns con cuidado, frame a frame y capa a capa.


Sincronización: animar sin ir demasiado rápido

 

Para evitar animaciones excesivamente rápidas, usamos un hook del BIOS:


Bios_SetHookCallback(H_TIMI, VBlankHook);


H_TIMI es una interrupción periódica (50/60 Hz).


Cada vez que salta:


static void VBlankHook()

{

    g_VBlank = 1;

}


Y en el bucle principal:


static void WaitVBlank()

{

    while(g_VBlank == 0) {}

    g_VBlank = 0;

    g_Frame++;

}


Esto nos permite:


  • Avanzar el tiempo de forma estable.

  • Controlar la animación con un simple contador.

     

Creando a Sam con dos capas de sprite

 

Creamos dos sprites superpuestos:


VDP_SetSpriteExUniColor(SPR_SAM_BODY,   x, y, shape, 0x04);

VDP_SetSpriteExUniColor(SPR_SAM_DETAIL, x, y, shape, 0x0E);


  • Misma posición.

  • Misma animación.

  • Colores distintos.

 

Resultado: un solo personaje con contorno, muy habitual en juegos de MSX.


Body
Body

Detail
Detail

Body + Detail
Body + Detail

Animación y movimiento


En cada frame:


u8 frame = (g_Frame >> 2) % 2;


  • Cambiamos de animación cada 4 ticks.

  • Alternamos entre frame 0 y frame 1.

 

Actualizamos solo lo necesario:


VDP_SetSpriteData(spriteId, &sam);


Esto escribe:


  • X

  • Y

  • Shape

 

Sin tocar el color ni recrear el sprite.

 

Salida limpia

 

Cuando el usuario pulsa la tecla ESC, salimos del bucle principal y cerramos el programa de forma ordenada:


Bios_ClearHook(H_TIMI);

Bios_Exit(0);


Aquí ocurren dos cosas importantes:

 

  1. Desenganchamos el hook del BIOS

 

Con Bios_ClearHook(H_TIMI) evitamos dejar el sistema con una interrupción activa que ya no se utilizará.


Esto es fundamental para no provocar comportamientos extraños tras salir del programa.

 

  1. Salimos del programa con Bios_Exit(0)

 

Esta llamada devuelve el control al sistema… pero el comportamiento final depende del formato con el que hayamos compilado el programa.


ROM vs DSK: un detalle clave


  • Si el programa se ha compilado como una ROM:


Al pulsar ESC, lo que observaremos es que el programa se vuelve a cargar, como si hiciéramos un warm reset.


Esto es normal: en una ROM no existe un “sistema operativo” al que volver, así que el MSX reinicia la ejecución del cartucho.


  • Si el programa se ha compilado como un ejecutable MSX-DOS (DSK):


En este caso, al salir con Bios_Exit(0) volveremos al prompt de MSX-DOS, exactamente como esperaríamos en un entorno de línea de comandos.

 

El mismo código, por tanto, puede tener comportamientos distintos según si se ejecuta desde ROM o desde DOS, y esto es una característica propia e histórica de la plataforma MSX.

 

Conclusiones: ¿y ahora qué?

 

En este artículo hemos hecho algo muy concreto… pero muy potente:

 

Hemos tomado un MSX2, un personaje de 16×16 píxeles y MSXgl, y lo hemos hecho mover y animar con criterio.

 

Por el camino hemos visto que:


  • Un sprite en MSX no es magia negra, sino:


    • patterns de 8×8 bien ordenados,

    • una tabla de atributos,

    • y un poco de disciplina a la hora de cargarlos.


  • MSXgl nos permite trabajar a un nivel mucho más cómodo:


    • sin tocar registros a pelo,

    • sin ensamblador,

    • y con código C legible, modular y mantenible.


  • Conceptos clásicos como:


    • animación por frames,

    • sincronización con el tiempo,

    • sprites multicapa (cuerpo + detalle),


Se pueden implementar de forma clara y pedagógica, ideal tanto para aprender como para enseñar.

 

Dicho de otra manera: el MSX sigue siendo un terreno de juego fantástico, y MSXgl es una herramienta excelente para sacarle partido hoy.

 

El potencial de MSXgl (visto con ojos MoltSXalats)

 

Este ejemplo es pequeño, pero deja entrever muy claramente el potencial de MSXgl:


  • Permite crear código moderno sobre hardware clásico.

  • Facilita hacer demos, juegos y experimentos sin tener que reescribir media especificación del VDP cada vez.

  • Es ideal para:


    • artículos didácticos,

    • talleres,

    • experimentos rápidos,

    • y proyectos colectivos como los que tanto nos gustan en la comunidad.

 

Para nosotros, MSXgl es una especie de puente entre el MSX de siempre y la forma actual de entender el desarrollo.

 

Y esto no termina aquí…

 

Este artículo es solo un primer paso. A partir de aquí, el camino natural es seguir creciendo:


  • Añadir scroll


Dar el siguiente paso lógico: un escenario que se mueve mientras Sam camina.

Exactamente lo que ya trabajamos en otros artículos… pero ahora con MSXgl y SCREEN 5.


  • Mapas de tiles y colisiones


Introducir un mapa, detectar paredes, límites y objetos, y empezar a hablar de “juego” de verdad.


  • Comparar enfoques


Ver cómo cambia el código si lo hacemos:


  • en SCREEN 2,

  • en MSX1,

  • o combinando sprites y fondos con distintas técnicas.

 

  • De demo a juego


Convertir este ejemplo en una base reutilizable:


  • estructura de proyecto,

  • gestión de estados,

  • y buenas prácticas para futuros desarrollos.

 

En resumen

 

Si has llegado hasta aquí, ya no estás “mirando” MSXgl: lo estás usando.

 

Y eso, en el espíritu MoltSXalats, es lo más importante: probar, entender, tocar, romper… y volver a probar.

 

Nos vemos en el próximo artículo.


Con más código, más scroll… y seguramente más gatos 🐾


Pulsa aquí para ver el ejemplo funcionando.

Puedes descargar el código de este proyecto aquí.


Codigo fuente



Sam Sprite Data




 
 
 

Comentarios


Envíanos un mensaje y dinos lo que piensas

¡Gracias por tu mensaje!

© 2035 Creado por Tren de ideas con Wix.com

bottom of page