Création de jeux sous MSX : Affichage de sprites.
Je vous sentais pressé d'afficher quelque chose sur l'écran ... héhéhéhé. Et bien, affichons des sprites !
Implémentation :
Pour rappel , un sprite est une image qui possède une transparence et qui peut être déplacée dans l'écran.
Nous allons, pour faire apparaitre ces sprites, implémenter les fonctions suivantes :
void setup_sprites(char spritesize, char zoom); : Va initialiser le type de sprite que l'on veut : de taille 8*8 ou 16*16, zoomé ou non ...
Hé oui, nous avons quasiment déja tout ce qu'il faut pour afficher des sprites !! Etonnant non ?!
Ouvrez le fichier video.c et ajouter la méthode suivante :
/* Définit les attribut général des sprites */
/* spritesize : SPRITE8X8
SPRITE16X16
zoom : SPRITE_NO_ZOOM
SPRITE_ZOOM 1 */
/**/
void setup_sprites(char spritesize, char zoom){
__asm
ld b,#0x00
ld a,4(ix)
and #0x0f
cp #0x08
jr z,$1
set 1,b ; --- si 16x16 allume bit 1
$1:
ld a,5(ix)
cp #0x00
jr z, $2
set 0,b ; --- si sprite zoomé => allume bit 0
$2:
ld hl,#0xf3e0 ;
ld a,(hl)
and #0xfc
or b
ld (hl),a
call 0x007e ; --- Change le registre
ld a,#0x01
ld hl,#0xfcaf
ld (hl),a
call 0x0069 ; --- reset la table des attributs de sprites
__endasm;
}
Alors sans entrer dans les détails, on va mettre certains bit de registre vidéo à 1 ou à 0 pour dire que les sprites font 8*8 ou 16*16 ou si ils sont zoomé ou non.
On modifie le video.h ainsi :
#ifndef ___MSXVIDEO_H___
#define ___MSXVIDEO_H___
#define SPRITE8X8 8
#define SPRITE16X16 32
#define SPRITE_NO_ZOOM 0
#define SPRITE_ZOOM 1
void screen_mode_2();
void put_vram(unsigned char* block,int vramaddr,int size);
void setup_sprites(char spritesize, char zoom);
#endif
Et on le compile avec :
sdcc -mz80 -c video.c
Les sprites : la théorie
Les sprites sur Coleco/Msx, c'est 2 zone mémoires.
1 Zone mémoire image, qui va contenir toute les représentations des sprites. Le début de l'adresse de cette zone est à peek_word(0xF3CF)
1 Zone mémoire attribut qui va contenir pour chaque sprite : sa position x,sa position y,le n° de son image,sa couleur (0 à 15). Le début de l'adresse de cette zone est à peek_word(0xF3CD).
Comme vous pouvez de suite le voir, un sprite = 1 seule couleur.
Les sprites : la pratique
Pour affiche un sprite à l'écran, on va donc les initialiser. Ici on va utiliser le cas le plus complexe, les sprites de 16*16. On décidera de ne pas zoomer.
setup_sprites(SPRITE16X16, SPRITE_NO_ZOOM);
Pourquoi le plus compliqué ? Pour calculer le n° d'image d'un sprite de 8*8 pixels c'est simple, si on veut l'image 0, c'est 0, si on veut l'image 1, c'est 1 ...
Un sprite de 16*16 est composé de 4 images de 8*8. Et donc le début de l'image 0 = 0, le début de l'image 1 = 1*4 = 4 et le début de l'image 2 = 2*4 etc etc ...
Dans ce tutorial, je vais vous donner le code de 3 images, un carré, un triangle et un rond. On apprendra à créer ces images dans un autre tutorial, à la main, et avec des utilitaires qui vont bien :)
// Size = 3 sprites * 4 caractères
// = 3 sprites * (4*8) octets = 96 octets
//
// pattern de début Carré = image 0 * 4 = 0
// pattern de début Triangle = image 1 * 4 = 4
// pattern de début Rond = image 2 * 4 = 8
const unsigned char SPATTERN[] = {
0x00, 0x00, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00, 0x00, // Carré
0x00, 0x00, 0x00, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, // Triangle
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x03, 0x07, 0x0F, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Rond
0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
Voilà, on va maintenant charger ces images de sprites à l'adresse mémoire des images de sprites :)
int addr_sprite_pattern;
addr_sprite_pattern = peek_word(0xF3CF);
put_vram(SPATTERN,addr_sprite_pattern,96);
On sa créer une structure en C, et un tableau de 32 "sprites".
typedef struct
{
unsigned char y;
unsigned char x;
unsigned char pattern;
unsigned char colour;
} sprite_t;
sprite_t sprites[32];
Et maintenant on va définir nos sprites en mémoire RAM :
// Carré
sprites[0].x=10;
sprites[0].y=10;
sprites[0].pattern=0; // Image 0*4
sprites[0].colour=2;
// Triangle
sprites[1].x=42;
sprites[1].y=42;
sprites[1].pattern=4; // Image 1*4
sprites[1].colour=3;
// Rond
sprites[2].x=42+32;
sprites[2].y=42+32;
sprites[2].pattern=8; // Image 2*4
sprites[2].colour=4;
Mais cela ne suffit pas ... Il faut maintenant copier cette table d'attribut en VRAM pour activer l'affichage.
addr_sprite_attr = peek_word(0xF3CD);
put_vram(sprites,addr_sprite_attr,4*32);
Compilez avec :
sdcc -mz80 --std-c99 --data-loc 0xc000 --code-loc 0x4020 --no-std-crt0 crt0.rel -main.ihx tools.rel video.rel main.c
et
objcopy --input-target=ihex --output-target=binary main.ihx result.rom
Voici le code source complet pour ceux qui sont un peu perdu :
#include "tools.h"
#include "video.h"
// Size = 3 sprites * 4 caractères
// = 3 sprites * (4*8) octets = 96 octets
//
// pattern de début Carré = image 0 * 4 = 0
// pattern de début Triangle = image 1 * 4 = 4
// pattern de début Rond = image 2 * 4 = 8
const unsigned char SPATTERN[] = {
0x00, 0x00, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00, 0x00, // Carré
0x00, 0x00, 0x00, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, // Triangle
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x03, 0x07, 0x0F, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Rond
0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
typedef struct
{
char y;
char x;
char pattern;
char colour;
} sprite_t;
sprite_t bsprites[32];
void main(void)
{
int addr_sprite_pattern;
int addr_sprite_attr;
screen_mode_2();
setup_sprites(SPRITE16X16, SPRITE_NO_ZOOM);
addr_sprite_pattern = peek_word(0xF3CF);
put_vram(SPATTERN,addr_sprite_pattern,96);
// Carré
bsprites[0].x=10;
bsprites[0].y=10;
bsprites[0].pattern=0; // Image 0*4
bsprites[0].colour=2;
// Triangle
bsprites[1].x=60;
bsprites[1].y=60;
bsprites[1].pattern=4; // Image 1*4
bsprites[1].colour=2;
// Rond
bsprites[2].x=42+32;
bsprites[2].y=42+32;
bsprites[2].pattern=8; // Image 2*4
bsprites[2].colour=2;
addr_sprite_attr = peek_word(0xF3CD);
put_vram(bsprites,addr_sprite_attr,4*32);
while(1){};
}
Lancez la rom dans un émulateur et ... admirez !!!!
Dans le prochain tuto, on va faire bouger tout ça... A la manette !!
Commentaires
Enregistrer un commentaire