CODINGCLASSEURS WEKA ★ Comment exploiter toutes les ressources et augmenter les performances de votre AMSTRAD CPC ★

5/09.2 - Définition et animation de sprites (22e Complément)Coding Classeurs Weka
5/9.2 Définition et animation de sprites

Si vous êtes amateur de jeux d'arcades, vous savez très certainement ce que sont les sprites. Pour les néophites, les sprites (ou lutins) sont des objets graphiques qui se déplacent sur l'écran sans l'effacer. Dans ce paragraphe, nous allons :

  • étudier un générateur de sprites en MODE 1 ;
  • étudier une RSX (|SPRITE) qui permettra aux programmeurs Basic de déplacer très simplement jusqu'à 8 sprites en même temps sur un écran en MODE 1 ;
  • utiliser la RSX |SPRITE pour effectuer une démonstration du déplacement d'un sprite en MODE 1.
    Un peu de théorie

Comme vous le savez (voir Partie 5 Chapitre 7), l'écran peut être considéré comme un bloc mémoire dans lequel chaque octet représente deux, quatre ou huit points élémentaires (MODES 0, 1 et 2). En ce qui nous concerne (MODE 1), chaque octet représente quatre points élémentaires ainsi codés :

Bit76543210
Stylo22221111
Point01230123

Interprétation du tableau :

  • chaque point élémentaire peut avoir quatre couleurs ;
  • lorsque tous les bits correspondant à un point élémentaire valent 0, le point a la couleur du fond de l'écran (PEN 0) ;
  • pour allumer le point élémentaire le plus à gauche avec la couleur 1, il faut stocker la valeur &H08 (bit 3 à 1) dans la mémoire concernée ;
  • pour allumer le point le plus à gauche avec la couleur 2, il faut stocker la valeur &H80 (bit 7 à 1) dans la mémoire concernée ;
  • pour allumer le point le plus à gauche avec la couleur 3, il faut stocker la valeur &H88 (bits 7 et 3 à 1) dans la mémoire concernée ;
  • le codage des 3 autres points élémentaires suit la même démarche logique :

Point 1 :Point 2 :Point 3 :
CouleurValeurCouleurValeurCouleurValeur
0&H000&H000&H00
1&H041&H021&H01
2&H402&H202&H10
3&H443&H223&H11

La RSX que nous allons étudier permet de manipuler des sprites de 8 points élémentaires sur 8, ce qui représente 16 octets : 2 octets pour représenter une ligne de 8 points élémentaires, et 8 lignes élémentaires.

Les quatre couleurs possibles pourront être modifiées à volonté à l'aide d'instructions Basic INK (voir Partie 4).

Le générateur de sprites

Avant de parler de la RSX |SPRITE, nous allons étudier un générateur de sprites qui vous permettra de créer vos propres sprites de 8 points élémentaires sur 8, et comportant jusqu'à quatre couleurs.

Comment utiliser le programme

Saisissez et exécuter le programme Basic suivant :



Une grille de 8 points sur 8 apparaît sur l'écran. C'est dans cette grille que vous définirez vos sprites.

La partie haute de l'écran laisse apparaître les quatres couleurs disponibles. Une flèche vers la droite (>) indique quelle est la couleur courante, c'est-à-dire la couleur de tracé. Pour changer la couleur courante, appuyez autant de fois que nécessaire sur la touche < Copy >.

La partie centrale de l'écran affiche les données hexadécimales correspondant au sprite en cours de création. Lorsque vous avez défini un sprite, notez ces données sur un bout de papier. Elles seront par la suite intégrées au programme d'animation...

Enfin, la partie basse de l'écran résume les diverses actions possibles.

Pour définir un sprite, respectez les étapes suivantes :

  • positionnez le « curseur » sur la case de votre choix (le curseur est symbolisé par une case discontinue) à l'aide des touches flèches ;
  • choisissez éventuellement la couleur de la case courante à l'aide de la touche < Copy > du clavier ;
  • appuyez sur la touche < Enter > du clavier pour colorier une case courante ;
  • recommencez les opérations qui viennent d'être décrites jusqu'à ce que le sprite soit entièrement défini ;
  • notez alors les données hexadécimales correspondantes.

Exemple de sprite :

Le programme en détail

La logique du programme obéit à l'ordinogramme suivant :

La ligne 1080 définit le tableau dans lequel seront stockées les données (allumé/éteint) des points du sprite :

DIM t(8,8) Tableau du sprite

La ligne 1090 définit le tableau qui contient le poids de chaque point élémentaire en fonction de sa couleur :

DIM t2(4,4) 'Valeur des couleurs

Chaque octet contient la définition de quatre points élémentaires successifs. Les quatres points sont ainsi codés :

Points
Couleurs1234
00000
18421
2128643216
3138683417

Les données de ce tableau s'interprètent ainsi :

  • lorsque le point élémentaire 1 est allumé avec la couleur 0 (couleur de fond), l'octet de définition est inchangé ;
  • lorsque le point élémentaire 1 est allumé avec la couleur 1, l'octet de définition doit être incrémenté de 8 ;
  • lorsque le point élémentaire 1 est allumé avec la couleur 2, l'octet de définition doit être incrémenté de 128 ;
  • lorsque le point élémentaire 1 est allumé avec la couleur 3, l'octet de définition doit être incrémenté de 136 ;
  • de ce qui précède, vous pouvez déduire vous même le codage des points élémentaires 2 à 4.

Les données de ce tableau sont stockées dans t2 entre les lignes 1100 et 1130 :

1100 t2(1,1)=0:t2(1,2)=0:t2(1,3)=0:t2(1,4)=0
....
1130 t2(4,1 )=136:t2(4,2)=68:t2(4,3)=34:t2(4,4)=17

Le tracé de la grille est effectué entre les lignes 1190 et 1260 :

1190 MODE 1
1200 GRAPHICS PEN 1
1210 FOR i=1 TO 9
1220 MOVE i*20,100
1230 DRAW i*20,260
1240 MOVE 20,80+i*20
1250 DRAW 180,80+i*20
1260 NEXT i

La ligne 1200 spécifie que la grille doit être tracée avec la couleur PEN 1.

Les diverses données qui accompagnent la grille sont affichées sur l'écran entre les lignes 1320 et 1480 :

  • les quatre couleurs possibles sont affichées en haut et à gauche de l'écran à l'aide d'une boucle FOR NEXT dans laquelle la couleur du papier (paper) est modifiée :

1320 LOCATE 20,1
1330 PRINT "Couleurs possibles"
1340 FOR i=0 TO 3 1350 LOCATE 23,i+5
1360 PAPER i
1370 PRINT" "
1380 NEXT i

  • les données hexadécimales correspondant au sprite sont initiali-sées à 0 et affichées à l'aide d'instructions PRINT :

1400 LOCATE 15,12
1410 PRINT "Données correspondantes"
1420 LOCATE 15,15
1430 PRINT "00 00 00 00 00 00 00 00"
1440 LOCATE 15,16
1450 PRINT "00 00 00 00 00 00 00 00"

  • enfin, le rappel des commandes est affiché en bas de l'écran à l'aide d'instructions PRINT :

1470 LOCATE 1,22
1480 PRINT” Deplact = Fléchés, Couleur = Copy"
1490 PRINT" Pixel = Enter,  Fin = Q"

Le programme se poursuit par la boucle principale de définition dans laquelle les diverses touches pressées sur le clavier sont interprétées.

Après diverses initialisations, le sous-programme situé en ligne 1710 est appelé. Ce sous-programme affiche la case courante dans la grille :

1590 l=1:c=1:sl=l:sc=1:GOSUB 1710

La case courante affichée, le programme se met en attente d'une action au clavier :

1600 a$=INKEY$:IF a$=M " THEN 1600

Lorsqu'une touche est pressée, son code ASCII est stocké dans la variable a :

1610 a=ASC(a$)

Les ligne et colonne courantes sont sauvegardées dans les variables sc et si :

1620 sc=c:sl=1'Sauvegarde ligne et colonne

Lorsque la touche pressée est une touche flèche, la variable I ou c est modifiée en conséquence :

1630 IF a=243 THEN c=c+1:GOSUB 1710 'Vers la droite
1640 IF a=242 THEN c=c-1:GOSUB 1710 'Vers la gauche
1650 IF a=240 THEN 1=1-1:GOSUB 1710 'Vers le haut
1660 IF a=241 THEN 1=1+1:GOSUB 1710 'Vers le bas

Lorsque la touche < Copy > est pressée, le sous-programme de changement de couleur est activé :

1670 IF a=224 THEN GOSUB 1950 'Changement de la couleur

Lorsque la touche < Enter > est pressée, le sous-programme d'affichage d'un pixel est activé :

1680 IF a=13 THEN GOSUB 2080 'Affichage d'un pixel

Enfin, lorsque la touche “Q" est pressée, le programme prend fin. Dans tous les autres cas, la touche est ignorée et le programme se met en attente d'une autre action au clavier :

1690 IF UPPER$(a$)<>''Q" THEN 1600

Le listing se termine par les trois sous-programmes dont nous venons de parler :

Les lignes 1710 à 1940 affichent la case courante dans la grille.

Les paramètres nécessaires en entrée sont les nouvelles ligne (l) et colonne (c) de la case courante.

Si ces données sont incorrectes (par exemple suite à l'appui sur la touche flèche vers la droite alors que le curseur se trouve dans la dernière colonne de la grille), elles sont révisées :

1760 IF l=9 THEN l=8
1770 IF l=0 THEN l=1
1780 IF c=9 THEN c=8
1790 IF c=0 THEN c=1

La case courante est repérée dans la grille par une ligne discontinue. L'ancienne case courante (de coordonnées sc,sl) est affichée avec une ligne continue :

1800 MASK 255
1810 MOVE 20+(sc-1 )*20,260-(sl-1 )*20
1820 DRAW 40+(sc-1)*20,260-(sl-1)*20
1830 DRAW 40+(sc-1)*20,240-(sl-1)*20
1840 DRAW 20+(sc-1 )*20,240-(sl-1 )*20
1850 DRAW 20+(sc-1 )*20,260-(sl-1 )*20

et la nouvelle case courante est affichée avec une ligne discontinue :

1800 MASK 85
1810 MOVE 20+(c-1)*20,260-(l-1)*20
1820 DRAW 40+(c-1 )*20,260-(l-1 )*20
1830 DRAW 40+(c-1 )*20,240-(l-1 )*20
1840 DRAW 20+(c-1 )*20,240-(l-1 )*20
1850 DRAW 20+(c-1 )*20,260-0-1 )*20

Les lignes 1950 à 2070 permettent de changer la couleur courante.

La couleur courante est sauvegardée puis incrémentée :

2000 sc=cc 'Sauvegarde couleur courante 2010 cc=cc+1

Lorsque la nouvelle couleur est égale à 5 (le nombre de couleurs disponibles étant égal à 4), la variable cc est initialisée à 1 pour pointer sur la première couleur disponible :

2020 IF cc=5 THEN cc=1

Le signe ">" pointant sur l'ancienne couleur courante est effacé et le nouveau signe est affiché :

2030 LOCATE 22,sc+4 2040 PRINT “ "
2050 LOCATE 22,cc+4 2060 PRINT V

Les lignes 2080 à 2390

  • affichent un point élémentaire dans la grille lorsque la touche < Enter > est pressée,- modifient et affichent les valeurs hexadécimales correspondantes.
  • Le remplissage de la case sélectionnée se fait à l'aide de l'instruction FILL:

2130 GRAPHICS PEN cc-1
2140 MOVE 20+(sc-1)*20,260(sl-1)*20
2180 DRAW 20+(sc-1)*20,260-(sl-1)*20
2190 FILL cc-1
2200 GRAPHICS PEN 1
2220 MASK 85
2230 MOVE 20+(sc-1)*20,260-(sl-1)*20
2280 DRAW 20+(sc-1)*20,260-(sl-1)*20
2290 MASK 255

La couleur de la case affichée est mémorisée dans le tableau t :

2300 t(1,c)=cc-1

Le curseur est positionnné sur la donnée hexadécimale à modifier :

2320 IF c2330 octet=(l-1)*2+s
2340 IF octet La nouvelle valeur hexadécimale est calculée à partir des tableaux t et t2 :

2350 tot=0
2360 IF c2370 IF c>4 THEN FOR z=5 TO 8:tot=tot+t2(y(l,z)+1,z-4):NEXT z

et affichée sur deux digits :

2380 PRINT HEX$(tot,2)

La rsx d'affichage |SPRITE

Comment afficher un objet sur l'écran et le déplacer sans effacer le décor ? Eh bien tout simplement en mémorisant le décor qui se trouve sous le sprite et en le réaffichant lors du prochain déplacement. Ce raisonnement simpliste est la base de la RSX |SPRITE.

Lors du premier affichage du sprite sur l'écran, aucun décor n'a encore été mémorisé. Il est donc inutile d'afficher la zone de mémoire correspondant au décor. Par contre, il faut sauvegarder le décor qui se trouve sous le sprite avant de l'afficher. Lors des futurs déplacements de sprite, il faudra :

  • restituer le décor sauvegardé ;
  • mémoriser le nouveau décor ;
  • afficher le sprite à la nouvelle position.

Comment utiliser la RSX

La RSX est bien entendu écrite en Assembleur. En voici le listing :









ABS 9001 ADR 9005 ANCXY 9009 BUF 9029
BIS 9090 BISDEC1 90A3 BISDEC2 90BB BIS2 90F3
BISSAV1 9106 BISSAV2 911B BIS3 912D BISC0L1 9140
BISC0L2 9155 DOTPOS BC1D DEFRSX 9039 ESPRIT 9007
FININC 9096 FININC2 90F9 FININC3 9133 FIN 915E
LOGEXT BCD1 NEXTLINE BC26 NUMERO 9000 ORD 9003
PREMAFF 8200 PTRTAB 902D SAUVDEC 8100 SPRITE 9043
SAUVEDE 90C1 TABLE 9032

La version Assembleur est intéressante pour comprendre le fonctionnement des sprites, mais ce sont surtout les données hexadécimales correspondantes qui seront utilisées en programmation Basic.

Pour utiliser cette RSX , procédez comme suit :

- Définissez la RSX en exécutant le programme situé en &H9039 : CALL &H9039

- Avant d'afficher pour la première fois le sprite N (où N est compris entre 1 et 8) sur l'écran, initialisez la mémoire &H8200+N-1 à zéro par un POKE. Par exemple pour le sprite 1 :

POKE &H8200,0

puis affichez le sprite en spécifiant les coordonnées d'affichage. Par exemple pour afficher le sprite 1 aux coordonnées x=100, y=50 :

|SPRITE,1,100,50

- Lorsque le sprite N (où N est compris entre 1 et 8) a été affiché une fois, initialisez la mémoire &H8200+N-1 à un par un POKE. Par exemple pour le sprite 1 :

POKE &H8200.0

puis affichez le sprite comme dans l'exemple ci-dessus.

Le programme en détail

La logique de la RSX apparaît dans l'ordinogramme suivant :

La RSX est définie à l'aide du petit programme situé entre les lignes 40 et 44 :

DEFRSX: EQU $ ;Point d'entrée
LD BC,PTRTAB ;Ptr table définition
LD HL,BUF ;Buffer pour LOG EXT
CALL LOGEXT ;Définition de la RSX

Lorsque le mot SPRITE sera reconnu par le Basic, le programme situé à l'étiquette SPRITE sera exécuté. En effet, le tableau PTRTAB pointe sur l'étiquette SPRITE et contient le mot clé SPRITE :

PTRTAB: DW TABLE pointeur TABLE
JP SPRITE ;Affichage du sprite
TABLE: DB "SPRIT"
DB "E"+80H
DB 0 ;Fin de table

Le programme situé à l'étiquette SPRITE débute par la mémorisation des données qui lui sont passées :

SPRITE: EQU $ ;Point d'entrée
LD H, (IX+1)
LD L, (IX+0)
LD (ORD) ,HL
LD H, (IX+3)
LD L, (IX+2)
LD (ABS) ,HL ;Sauv abscisse
LD A, (IX+4)
LD (NUMERO) ,A

La variable située en &H8200+NUMERO est ensuite examinée pour déterminer si le sprite est affiché pour la première fois :

LD HL,PREMAFF
LD A, (NUMERO)
DEC A
LD D,0
LD E,A
ADD HL.DE
LD A, (HL) ;lndic1eraff
OR A

Lorsque le sprite est affiché pour la première fois, la phase d'affichage du décor est sautée :

JP Z,SAUVDE ;Sauvegarde décor

A partir du second affichage du sprite, le décor mémorisé à l'ancienne position du sprite est réaffiché. Les coordonnées de ce décor se trouvent dans la zone mémoire qui commence en ANCXY :

- ordonnée en ANCXY + (NUMEROM
— abscisse en ANCXY + (NUMEROM + 2

Ces coordonnées sont extraites de la mémoire et stockées dans les registres DE et HL :

LD H L, ANCXY
LD A,(NUMERO)
DEC A
ADD A,A
ADD A,A → (NUMEROM
LD D,0
LD E,A
ADD HL,DE → ANCXY + (NUMEROM
LD E, (HL)
INC HL
LD D, (HL) → DE = (ANCXY + (NUMEROM)
INC HL
LD C, (HL)
INC HL
LD B, (HL) → BC = (ANCXY + (NUMEROM + 2)
LD H,B
LD L,C

La routine SCR DOT POSITION du Firmware est ensuite appelée pour connaître l'adresse de l'octet qui correspond à ces coordonnées :

CALL DOTPOS

Cette routine renvoie l'adresse recherchée dans le registre HL. Le programme stocke cette adresse dans la variable ADR :

LD (ADR) ,HL

L'adresse mémoire du décor est calculée par une simple addition : l'adresse du premier décor débute en SAUVDEC, et chaque décor occupe 16 octets. L'adresse qui nous intéresse est donc calculée de la manière suivante :

adresse = SAUVDEC + (NUMERO)*16

Comme la multiplication ne fait pas partie des opérations de base du Z80, nous avons eu recours à une boucle pour calculer (NUMERO)*16 :

LD HL,SAUVDEC ;Adresse du premier décor
LD DE, 16 LD A, (NUMERO)
BIS: EQU $
DEC A
JR Z,FININC ;Fin de l'incrémentation
ADD HL,DE
JR BIS ; Boucle d'incrémentation
FININC: EQU $
LD (ESPRIT) ,HL ;Adresse du décor

L'affichage des 16 octets du décor se fait à l'aide de deux boucles. La première affiche les 8 octets correspondant à la partie gauche du décor :

LD DE, (ESPRIT)
LD HL, (ADR)
LD A,8
LD B,A
BISDEC1:
LD A, (DE) octet lu en mémoire
LD (HL) ,A affiché sur l'écran
CALL NEXTLINE → passage à la ligne suivante sur l'écran INC DE —>... et en mémoire
INC DE
DJNZ BISDEC1 → boucle d'affichage

Remarquez :

- la macro NEXTLINE du Firmware qui permet de connaître l'adresse de l'octet qui représente les 4 points situés en-dessous des 4 points courants ;

- l'utilisation pratique de l'instruction DJNZ qui exécute la boucle 8 fois, jusqu'à ce que le registre B soit nul.

La seconde boucle affiche les 8 octets correspondant à la partie droite du décor. Elle utilise la même logique que la précédente. Nous n'y reviendrons pas.

Le nouveau décor est sauvegardé selon le procédé inverse. Les données sont lues sur l'écran à partir des coordonnées ABS et ORD, et sauvegardées en mémoire (lignes 140 à 211). Nous n'y reviendrons pas.

Le programme se termine par l'affichage du sprite aux coordonnées ABS,ORD. Cet affichage est très similaire à l'affichage du décor. Il occupe les lignes 212 à 254.

Le programme se termine par une instruction RET qui redonne le contrôle au Basic.

DÉMONSTRATION DE L'ANIMATION D'UN SPRITE

Le court programme présenté dans ce paragraphe montre comment utiliser la RSX SPRITE dans un programme Basic. Son but est uniquement démonstratif. Aucune action n'est donc demandée à la personne qui l'utilise, si ce n'est l'appui sur une touche quelquonque du clavier qui met fin à son exécution.
Son listing est le suivant :


Le programme en détail

La logique du programme apparaît dans l'ordinogramme suivant :

Le programme débute par la mise en mémoire de la RSX I SPRITE à l'aide d'une boucle FOR NEXT :

1040 FOR i=&9000 TO &915E
1050 READ a$
1060 a$=“&"+a$
1070 a=VAL(a$)
1080 POKE i ,a
1090 NEXT i[:code]

La RSX est ensuite initialisée :

1150 CALL &9039[:code]

Le programme se poursuit par la définition du sprite en mémoire à partir de l'adresse &8000 :

1210 FOR i=&8000 TO &8007
1220 IF (i/2)=INT(i/2) THEN POKE i,&FF ELSE POKE i,0
1230 NEXT i
1240 4
1250 FOR i=&8008 TO &800F
1260 IF (i/2)=INT(i/2) THEN POKE i,0 ELSE POKE i,&FF
1270 NEXT i

Pour montrer que les sprites se déplacent sur l'écran sans effacer le décor affiché, une boucle FOR NEXT remplit l'écran MODE 1 de tirets :

1320 MODE 1
1330 FOR i=1 TO 1000
1340 PRINT"-";
1350 NEXT i

Avant d'afficher le sprite pour la première fois, la mémoire d'adresse &H8200 est initialisée à 0 :

1360 POKE &8200,0: SPRITE, 1,80,100

La mémoire d'adresse &H8200 est alors initialisée à 1 pour tout le reste du programme :

1370 POKE &H8200,1

Les dernières instructions du programme réalisent l'animation du sprite qui semble rebondir sur les coins de l'écran.

La position de départ du sprite est 80,100 :

1380 x=80 1390 y=100

Les déplacements selon les deux axes sont fixés à 2 pixels :

1400 dx=2 → déplacement en x
1410 dy=2 → déplacement en y

La fonction INKEY$ scrute le clavier. Lorsqu'une touche est pressée, le programme prend fin :

1420 a$=INKEY$
1480 IF a$=“ "THEN 1420
1490 MODE 2
1500 END

La logique de déplacement du sprite est ultra simple :

- si le sprite se trouve sur l'extrémité droite ou gauche de l'écran, le déplacement en X est inversé :

1430 IF (x=310) OR (x=0) THEN dx=-dx

- si le sprite se trouve sur l'extrémité haute ou basse de l'écran, le déplacement en Y est inversé :

1440 IF (y=200) OR (y=0) THEN dy=-dy

- les coordonnées du sprite sont incrémentées de dx et dy :

1450 x=x+dx 1460 y=y+dy

Le sprite est enfin affiché à l'aide d'une instruction |SPRITE :

1470 |SPRITE,1,x,y

Les dernières lignes du programme (1520 à 1770) contiennent les données hexadécimales de la RSX |SPRITE.

Afin d'éviter toute erreur dans la saisie des DATA, voici les données de checksum correspondantes :

0 0 86 94 C4 25 A4 7E 57 EE DE FB Al ED 71 F9 AA B7 24 14 93 7B

Page précédente : 5/09.1 - Définition de caractères multiples
Je participe au site:

» Vous avez remarqué une erreur dans ce texte ?
» Aidez-nous à améliorer cette page : en nous contactant via le forum ou par email.

CPCrulez[Content Management System] v8.7-desktop/c
Page créée en 466 millisecondes et consultée 381 fois

L'Amstrad CPC est une machine 8 bits à base d'un Z80 à 4MHz. Le premier de la gamme fut le CPC 464 en 1984, équipé d'un lecteur de cassettes intégré il se plaçait en concurrent  du Commodore C64 beaucoup plus compliqué à utiliser et plus cher. Ce fut un réel succès et sorti cette même années le CPC 664 équipé d'un lecteur de disquettes trois pouces intégré. Sa vie fut de courte durée puisqu'en 1985 il fut remplacé par le CPC 6128 qui était plus compact, plus soigné et surtout qui avait 128Ko de RAM au lieu de 64Ko.