Entendiendo un sprite animado en MSX2 con MSXgl
- MoltS Xalats
- hace 21 horas
- 5 Min. de lectura

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).

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.



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:
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.
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