Animation d'un personnage avec les sprites hardComme évoqué dans l'article [ Animation delta des sprites hards ], les sprites hards possèdent leur propre mémoire qu'il faut écrire à chaque fois qu'on veut en changer le contenu. Ce ne sont pas des sprites hard "traditionnels" avec lesquels il n'y aurait que l'adresse des données à changer. L'article donnait plusieurs méthodes pour écrire dans les sprites hards. Nous allons utiliser la méthode qui décompresse à la volée. Pourquoi? Pour simplifier la gestion de notre personnage, qui voudrait aller à droite, à gauche, sauter, changer de direction instantanément, nousn'allons pas utiliser le delta, cela impliquerait de calculer beaucoup de combinaisons, de créer un code complexe. Ici, nous allons nous concentrer sur quelques animations et en fonction du souhait de l'utilisateur, nous changerons l'animation courante.C'est pourquoi la copie complète dans les sprites est la plus adaptée, même si plus lente. Voici la routine pour rappel. Copie avec décompression à la volée startingindex 0 align 256 tableDecale4 repeat 256,x defb x>>4 renddecrunchSprite ; HL = source alignée sur 128 octets ; DE = destination dans l'ASIC ld b,hi(tableDecale4) .loop repeat 8 ld a,(hl) : inc l : ld (de),a : inc e ld c,a : ld a,(bc) : ld (de),a : inc e rend jr nz,.loop retDifférents type d'animations Voici une planche très allégée d'un très bon jeu disposant de nombreuses étapes d'animations. Si on se concentre sur la première ligne, elle contient 4 animations différentes : - Le personnage est orienté vers la gauche et ne bouge pas. - Le personnage est orienté vers la droite et ne bouge pas. - Le personnage se tourne de gauche à droite et ne bouge plus. - Le personnage se tourne de droite à gauche et ne bouge plus. 
Si les 5 premiers meta-sprites (composés chacun de 6 sprites hards) sont numérotés de 0 à 4, on peut définir les 4 animations de la sorte : - sprite 0, reboucler sur la dernière étape, y en a qu'une, c'est le sprite 0 - sprite 4, reboucler sur la dernière étape - sprite 0, 1, 2, 3, 4, puis reboucler sur la dernière étape (sprite 4) - sprite 4, 3, 2, 1, 0, puis reboucler sur la dernière étape (sprite 0) Pour le moment, c'est assez simple, on peut utiliser le même type d'animation pour tout le monde, dérouler un ou plusieurs meta-sprite, puis reboucler sur le dernier. Listes chainées Vous connaissez les listes chainées? C'est une technique qui consiste à relier des objets identiques en incluant dans chaque objet une notion de suivant (et parfois de précédent mais ce cas ne nous intéresse pas). Ainsi, quand on a différentes étapes à exécuter, on définit chaque étape dans un objet et on indique quelle est l'étape suivante. Cela peut se faire avec un pointeur, un index... 
Dans notre cas, nous avons besoin de peu de choses : L'adresse des données à copier et l'objet suivant. On va s'écrire une macro pour pouvoir tout définir facilement. Pour rappel, nos sprites sont stockés sur 128 octets chacun. startingindex 0 macro animate_single zelabel,nbanim curspr=0 repeat {nbanim}-1 defw $+4 ; nos objets font 4 octets, on passe au suivant defw {zelabel}+6*128*curspr curspr+=1 rend defw $ ; boucle infinie sur la dernière étape defw {zelabel}+6*128*curspr mendExemple d'utilisation de la macro. animate_single hspConrad_GaucheDroite,1 ; Conrad regarde à gauche animate_single hspConrad_GaucheDroite+4*6*128,1 ; Conrad regarde à droite animate_single hspConrad_GaucheDroite,5 ; Conrad regarde de gauche à droite puis reste figé à droiteAh! Il nous manque le cas où les données sont lues à l'envers! Vite, une petite macro ;) startingindex 0 macro animate_single_reverse zelabel,nbanim curspr=nbanim-1 repeat {nbanim}-1 defw $+4 defw {zelabel}+6*128*curspr curspr-=1 rend defw $ ; infinite loop on last step defw {zelabel}+6*128*curspr mendExemple d'utilisation de la macro inversée. animate_single_reverse hspConrad_GaucheDroite,5 ; Conrad regarde de droite à gauche puis reste figé à gaucheMoteur d'animation exploitant la liste chainéeOn a créé nos listes avec à chaque fois [suivant+adresse données], reste à exploiter ces listes. Principe de base, on a une variable qui pointe vers un objet. En lisant l'adresse suivante dans l'objet, on actualise cette variable. Nos listes chainées ne changent jamais, elles sont uniquement lues. Notre routine aura deux paramètres, l'adresse de la variable pointant vers l'objet, et la destination (quel sprite hard écrire) ; A=sprite destination ; HL=animation animate_execute_step ;.reloop ld e,(hl) : inc hl : ld d,(hl) : dec hl ;: ex hl,de ; current step in 'animation' ex hl,de : ldi : ldi ; overwrite current step in 'animation' ld d,a : ld e,0 : ld a,(hl) : inc hl : ld h,(hl) : ld l,a ; HL = sprite data source / DE = sprite destination ld b,hi(hsp_conversion) ld xl,6 ; meta-sprite de 6 sprites hards .unpack_hsp repeat 8 ld a,(hl) : inc l : ld (de),a : inc e : ld c,a : ld a,(bc) : ld (de),a : inc e ; 1 byte => 2 pixels rend jr nz,.unpack_hsp dec l : inc hl inc d ; next sprite dec xl jr nz,.unpack_hsp ret ; DE = next spriteBon, on se l'affiche? D'abord la conversion, classique avec deux options en particulier. Le stockage des pixels groupés par deux sur un octet et la conservation des sprites vides. ; 30 parce que 6x5=30 convgeneric.exe -hsp -g -meta 2x3 -c 30 -p 2 -k flashBackSheet.pngLe premier jet sera au plus simple, on gère les touches gauche et droite du joystick et on affiche soit la planche de droite, soit celle de gauche...Il vous faudra les fichiers[flashBackGround.bin],[conradGD.bin][conradGDanimate.asm]pour compiler le source. buildsna SNASET CPC_TYPE,4 ; 6128+ bankset 0 org #38 ei : ret org #100 run #100;*** RMR2 tags *** ASICOFF equ 0 : ROM0000 equ 0 : ROM4000 equ %01000 : ROM8000 equ %10000 : ASICON equ %11000 ROM0 equ 0 : ROM1 equ 1 : ROM2 equ 2 : ROM3 equ 3 : ROM4 equ 4 : ROM5 equ 5 : ROM6 equ 6 : ROM7 equ 7 macro RMR2 tags : ld a,{tags}+%10100000 : ld b,#7F : out (c),a : mend ld sp,#100 ; la pile avant le code ld bc,#7F80+%1100 : out (c),c ; MODE 0 jp UnlockAsic include 'conradGDanimate.asm' ; définir les routines d'animation et les macros UnlockAsic ld bc,#BCFF out (c),c out (c),0 ld hl,%1001000011101010 .loop out (c),c ld a,h:rlca:ld h,l:ld l,a srl c:res 3,c and #88 or c ld c,a cp #4D jr nz,.loop ld a,#CD out (c),a : out (c),a RMR2 ASICON ld a,199 : ld (#6800),a ; interruption ligne 200 ld hl,palette ld de,#6400 ld bc,64 ldir ; on envoie toutes les couleurs d'un coup, fond, border, sprites ei ; activer 6 sprites en ratio mode 1 ld a,%1001 ld hl,#6004 : ld b,6 : ld de,8 .setHsp ld (hl),a : add hl,de : djnz .setHsp ; il faut positionner nos sprites à minima à l'initialisation ld hl,200 : ld (#6000+8*0),hl : ld (#6000+8*2),hl : ld (#6000+8*4),hl ld hl,232 : ld (#6000+8*1),hl : ld (#6000+8*3),hl : ld (#6000+8*5),hl ld hl,72 : ld (#6002+8*0),hl : ld (#6002+8*1),hl ld hl,88 : ld (#6002+8*2),hl : ld (#6002+8*3),hl ld hl,104 : ld (#6002+8*4),hl : ld (#6002+8*5),hl ;******************************************************** mainLoop ;******************************************************** halt : halt : halt : halt ; lire le joystick ld a,#49 : ld bc,#F40E : out (c),c : ld bc,#F6C0 : out (c),c : out (c),0 ld bc,#F792 : out (c),c : dec b : out (c),a : ld b,#F4 : in a,(c) ld bc,#F782 : out (c),c : dec b : out (c),0 bit 2,a : jp z,Conrad.gauche bit 3,a : jp z,Conrad.droite jp Conrad.execute ; continuer l'animation en cours si aucune touche ;********* Conrad ;********* .gauche ld hl,conradGauche : ld (.animation),hl : jp .execute .droite ld hl,conradDroite : ld (.animation),hl : jp .execute .execute ld a,#40 : ld hl,.animation : call animate_execute_step : jp mainLoop .animation defw conradDroite ; animation par défaut à droite conradGauche animate_single hspConrad_GaucheDroite,1 ; Conrad regarde à gauche conradDroite animate_single hspConrad_GaucheDroite+4*6*128,1 ; Conrad regarde à droite conradGaucheDroite animate_single hspConrad_GaucheDroite,5 ; Conrad regarde de gauche à droite puis reste figé à droite conradDroiteGauche animate_single_reverse hspConrad_GaucheDroite,5 ; Conrad regarde de droite à gauche puis reste figé à gauche palette defw #000,#004,#322,#041,#444,#664,#00B,#775,#885,#886,#995,#996,#63D,#AA6,#BB6,#EEF border defw #000 hsp defw #360,#461,#572,#194,#693,#44A,#2B5,#55B,#888,#66C,#7C6,#77E,#88F org #8000 : hspConrad_GaucheDroite incbin 'conradGD.bin' org #C000 : incbin 'flashBackGround.bin' Rendez-vous dans [ l'article suivant ] pour voir comment on va faire évoluer la gestion de notre personnage et utiliser les deux autres animations. Roudoudou CPCrulez[Content Management System] v8.732-desktop/c Page créée en 169 millisecondes et consultée 45 foisL'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. |
|