Entenent un sprite animat en MSX2 amb MSXgl
- MoltS Xalats
- 13 hours ago
- 5 min de lectura

Una introducció pas a pas per a neòfits
Programar gràfics en un MSX pot intimidar al principi: VDP, VRAM, sprites, hooks del BIOS…
Però amb MSXgl, moltes d’aquestes complexitats queden encapsulades en funcions clares i coherents.
En aquest article veurem com funciona un sprite animat de 16×16 píxels en MSX2, des del patró en memòria fins a l’animació a pantalla, explicant totes les crides importants sense necessitat de conèixer el maquinari a baix nivell.
El punt de partida: què és un sprite al MSX?
En MSX clàssic:
Un pattern és un dibuix de 8×8 píxels, codificat en 8 bytes
Un sprite de 16×16 està format per 4 patterns de 8×8
L’ordre no és intuïtiu: el VDP espera
Top-Left, Bottom-Left, Top-Right, Bottom-Right
En el nostre exemple, el personatge Sam té:
2 frames d’animació (idle i walk)
2 capes de sprite:
BODY (cos)
DETAIL (contorn o detalls)
En total: 16 patterns (16 × 8 bytes)
Dibuixant Sam: els patterns en memòria
Tots els patterns estan definits en un únic array:
const unsigned char g_DataSprt16_Sam[];
Aquest array no és encara VRAM, sinó RAM normal.
Cada grup de 8 bytes representa un tile 8×8.
Per facilitar la lectura, definim una funció auxiliar:
static const u8* TilePtr(u8 tileIndex)
{
return g_DataSprt16_Sam + ((u16)tileIndex * 8);
}
Així podem dir: “Carrega el tile número 3” sense preocupar-nos d’offsets ni càlculs manuals.
Comprovant que som en MSX2
Abans de fer servir SCREEN 5, cal assegurar-nos que l’ordinador ho suporta:
if(g_MSXVER == 0)
{
Bios_ClearScreen();
Bios_TextPrintSting("MSX2 required");
Bios_GetCharacter();
return;
}
g_MSXVER és una variable global proporcionada per MSXgl
Si és 0, estem en MSX1
Mostrem un missatge en mode text i sortim elegantment
Inicialitzant el mode gràfic (SCREEN 5)
Ara sí, entrem en territori MSX2:
VDP_SetMode(VDP_MODE_SCREEN5);
VDP_SetColor(COLOR_BLACK);
Això configura el VDP en SCREEN 5 (256×212, bitmap).
Per netejar la pantalla fem servir un comandament del VDP, molt més ràpid 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
Omple una gran zona de VRAM amb negre
VDP_CommandWait() assegura que el VDP ha acabat abans de continuar
Activant i configurant els sprites
Els sprites tenen taules pròpies dins la VRAM:
VDP_EnableSprite(TRUE);
VDP_SetSpritePatternTable(0x17000);
VDP_SetSpriteAttributeTable(0x17A00);
Aquí indiquem:
On viuran els patterns de sprite
On viurà la taula d’atributs (posició, forma, color…)
I definim el format global:
VDP_SetSpriteFlag(VDP_SPRITE_SIZE_16 + VDP_SPRITE_SCALE_2);
És a dir:
Sprites de 16×16
Escalats ×2 → visualment 32×32
Carregant els patterns a la VRAM
Ara copiem els dibuixos des de RAM cap a VRAM:
VDP_LoadSpritePattern(TilePtr(...), pat, 1);
Aquesta funció:
copia 1 pattern de 8 bytes
a la posició pat de la Sprite Pattern Table
És important respectar l’ordre del VDP:
Top Left (1) → Bottom Left (2) → Top Right (3) → Bottom Right (4)

Per això el codi carrega els patterns amb molt de compte, frame a frame i capa a capa.
Sincronització: animar sense córrer massa
Per evitar animacions massa ràpides, fem servir un hook del BIOS:
Bios_SetHookCallback(H_TIMI, VBlankHook);
H_TIMI és una interrupció periòdica (50/60 Hz).
Cada cop que salta:
static void VBlankHook()
{
g_VBlank = 1;
}
I al bucle principal:
static void WaitVBlank()
{
while(g_VBlank == 0) {}
g_VBlank = 0;
g_Frame++;
}
Això ens permet:
avançar el temps de manera estable
controlar l’animació amb un simple comptador
Creant Sam amb dues capes de sprite
Creem dos sprites superposats:
VDP_SetSpriteExUniColor(SPR_SAM_BODY, x, y, shape, 0x04);
VDP_SetSpriteExUniColor(SPR_SAM_DETAIL, x, y, shape, 0x0E);
Mateixa posició
Mateixa animació
Colors diferents
Resultat: un sol personatge amb contorn, molt habitual en jocs MSX.



Animació i moviment
Cada frame:
u8 frame = (g_Frame >> 2) % 2;
canviem d’animació cada 4 ticks
alternem entre frame 0 i 1
Actualitzem només el necessari:
VDP_SetSpriteData(spriteId, &sam);
Això escriu:
X
Y
Shape
Sense tocar el color ni recrear el sprite.
Sortida neta
Quan l’usuari prem la tecla ESC, sortim del bucle principal i tanquem el programa de manera ordenada:
Bios_ClearHook(H_TIMI);
Bios_Exit(0);
Aquí passen dues coses importants:
Desenganxem el hook del BIOS
Amb Bios_ClearHook(H_TIMI) evitem deixar el sistema amb una interrupció activa que ja no s’utilitzarà.
Això és fonamental per no provocar comportaments estranys després de sortir del programa.
Sortim del programa amb Bios_Exit(0)
Aquesta crida retorna el control al sistema… però el comportament final depèn del format amb què hàgim compilat el programa.
ROM vs DSK: un detall clau
Si el programa s’ha compilat com una ROM
En prémer ESC, el que observarem és que el programa es torna a carregar, com si féssim un warm reset.
Això és normal: en una ROM no existeix un “sistema operatiu” al qual tornar, així que el MSX reinicia l’execució del cartutx.
Si el programa s’ha compilat com un executable MSX-DOS (DSK)
En aquest cas, en sortir amb Bios_Exit(0) tornarem al prompt del MSX-DOS, exactament com esperaríem en un entorn de línia de comandes.
El mateix codi, per tant, pot tenir comportaments diferents segons si s’executa des de ROM o des de DOS, i això és una característica pròpia i històrica de la plataforma MSX.
Conclusions: i ara què?
En aquest article hem fet una cosa molt concreta… però molt potent: hem agafat un MSX2, un personatge de 16×16 píxels i MSXgl, i l’hem fet moure i animar amb criteri.
Pel camí hem vist que:
Un sprite al MSX no és màgia negra, sinó:
patterns de 8×8 ben ordenats,
una taula d’atributs,
i una mica de disciplina a l’hora de carregar-los.
MSXgl ens permet treballar a un nivell molt més còmode:
sense tocar registres a pèl,
sense assemblador,
i amb codi C llegible, modular i mantenible.
Conceptes clàssics com:
animació per frames,
sincronització amb el temps,
sprites multicapa (cos + detall),
Es poden implementar de manera clara i pedagògica, ideal tant per aprendre com per ensenyar.
Dit d’una altra manera: el MSX continua sent un terreny de joc fantàstic, i MSXgl és una eina excel·lent per explotar-lo avui.
El potencial de MSXgl (vist amb ulls MoltSXalats)
Aquest exemple és petit, però deixa entreveure molt clarament el potencial de MSXgl:
Permet crear codi modern sobre maquinari clàssic.
Facilita fer demos, jocs i experiments sense haver de reescriure mitja VDP spec cada cop.
És ideal per:
articles didàctics,
tallers,
experiments ràpids,
i projectes col·lectius com els que tant ens agraden a la comunitat.
Per a nosaltres, MSXgl és una mena de pont entre el MSX de sempre i la manera actual d’entendre el desenvolupament.
I això no s’acaba aquí…
Aquest article és només un primer pas. A partir d’aquí, el camí natural és seguir creixent:
Afegir scroll
Fer el següent pas lògic: un escenari que es mou mentre Sam camina.
Exactament el que ja vam treballar en altres articles… però ara amb MSXgl i SCREEN 5.
Mapes de tiles i col·lisions
Introduir un mapa, detectar parets, límits i objectes, i començar a parlar de “joc” de veritat.
Comparar enfocaments
Veure com canvia el codi si ho fem:
en SCREEN 2,
en MSX1,
o combinant sprites i fons amb diferents tècniques.
De demo a joc
Convertir aquest exemple en una base reutilitzable:
estructura de projecte,
gestió d’estats,
i bones pràctiques per a futurs desenvolupaments.
En resum
Si has arribat fins aquí, ja no estàs “mirant” MSXgl: l’estàs fent servir.
I això, en l’esperit MoltSXalats, és el més important: provar, entendre, tocar, trencar… i tornar a provar.
Ens veiem al proper article. Amb més codi, més scroll… i segurament més gats 🐾
Clica aquí per a veure l'exemple funcionant.
Pots descarregar el codi d’aquest projecte aquí.
Codi font
Sam Sprite Data





Comentaris