Positionnement individuel des sprites sur un meta-objetJusqu'à présent, nous avons utilisé (pour Conrad) des meta-sprites composés de sprites unitaires alignés et organisés systématiquement de la même façon. C'est beaucoup plus pratique, tant que le personnage ne bouge pas, on n'a pas à faire bouger nos sprites. La gestion des séquences est simplifiée et leur création aussi. Sauf qu'on n'a pas toujours autant de sprites qu'on voudrait à disposition et il y a par ailleurs un gâchis évident des sprites. Pour illustrer ce qu'on peut faire comme modifications à notre système de gestion, voici un sprite issu d'un jeu en cours de création. Comme Conrad, il occupe 6 sprites hard, cette fois organisés à l'horizontale. 
C'est ainsi que Titan m'a envoyé la planche, avec Esteban bien centré, prenant ses aises avec les resources de la machine. Maintenant voici une version où je décale certains blocs multiples de 16 pixels à la manière d'un taquin. - Je décale tous les sprites de 4 pixels vers le bas (opération faite sur l'ensemble de la planche) - Je décale les 4 sprites les plus à gauche de 5 pixels vers le bas. - Enfin, je décale le sprite tout en haut à gauche de deux pixels vers la gauche. Et voici le résultat : 
Extrait de la planche (non complète ici) annotée avec les modifications. 
En résumé et DANS MON CAS, j'ai 3 transformations à appliquer sur mon meta-sprite de référence : - Déplacer les deux sprites de gauche vers le bas. - Déplacer le sprite du milieu vers le bas (même si c'est souvent pareil que les deux autres, j'ai UN cas particulier à gérer). - Enfin, le sprite en haut à gauche à décaler vers la gauche. Jusqu'à présent (avec Conrad), on avait une routine spécifique qui ne s'occupait que des X, la revoici : ; HL=position X du côté gauche .SetX ld de,32 ; 16 pixels mode 1 == 32 pixels mode 2 en précision d'affichage ld (#6000),hl : ld (#6010),hl : ld (#6020),hl : add hl,de ld (#6008),hl : ld (#6018),hl : ld (#6028),hl retComme on le voit, lorsqu'on bouge un meta-sprite, il faut de toutes façons ré-écrire chacune des coordonnées, calculer les positions des sprites adjacents, etc.Autant alors définir chacun de nos sprites de façon relative au premier qui sera notre référence. Dans le cas d'Esteban, nous avons par défaut : - premier sprite (0/0) - deuxième sprite (0/16) - sprite du milieu (32/16) - sprite des pieds (64/16) Ce qui, en relatif, deviendrait 0/0, 0/16, 32/0, 32/0. Pourquoi passer sur du relatif vous me demanderez? Hé bien pour éviter de recharger à chaque fois la référence qui peut se situer n'importe où sur l'écran, pas comme notre 0/0 de cet exemple! 
Voici une routine générique qui fonctionne dans tous les cas. Elle utilise les informations de placement avec d'abord l'ensemble des décalages X et ensuite ceux en Y. ; IX=info du premier sprite dans l'ASIC ; IY=info de placement des sprites ; HL=x DE=y du premier sprite ; A=nombre de sprites SetMetaSprite ; **** d'abord boucler sur les X ************ push af,de,ix : ld de,8 .modifyX exa ld c,(iy+0) ld a,c : add a : sbc a : ld b,a ; faire une valeur 16 bits signées à partir de C add hl,bc ; modifier le X ld (ix+0),hl add ix,de inc iy exa : dec a : jr nz,.modifyX pop ix,hl,af .modifyY exa ld c,(iy+0) ld a,c : add a : sbc a : ld b,a ; faire une valeur 16 bits signées à partir de C add hl,bc ; modifier le X ld (ix+2),hl add ix,de inc iy exa : dec a : jr nz,.modifyY retMaintenant, comment pourrait-on intégrer nos données de placement aux routines des articles précédents?On va modifier notre structure qui contient la définition d'un mouvement et comme il n'est plus possible d'automatiser la création d'un mouvement, on va se créer une macro pour pousser petit à petit chaque étape. Il faudra ajouter les modificateurs de coordonnées après chaque étape à la main (bouuuuuuh, en attendant mieux dans l'article suivant). startingindex 0 macro animate_push_step addr,meta,zebank,spraddr ; si l'adresse n'est pas nulle, on la force, sinon on calcule l'adresse de la cellule suivante if {addr} : defw {addr} : else : defw $+6+2*{meta} : endif defb #80|{zebank},{meta} defw {spraddr} mendRevenons à notre Esteban, ses 4 sprites, et l'animation complète qui reboucle avec 11 étapes!
Pour rappel, nos coordonnées relatives donnent par défaut 0/0, 0/16, 32/0, 32/0, donc en écrivant d'abord les X, ensuite les Y... defb 0,0,32,32,0,16,0,0 estebanNage animate_push_step 0,4,{bank}hsp_estebanNage,hsp_estebanNage ; 1ère étape, les 3 premiers sprites sont décalés de 1 pixel vers le bas defb 0,0,32,32,-1,16,0,1 ... ; la suite dans le code source plus bas ;)C'est pas marrant, c'est une petite gymnastique cérébrale mais il suffit de suivre les flèches vertes ^_^Et si on affichait tout ça maintenant? Jetez un oeil à la routine animate_execute_step légèrement modifiée. On sauvegardela valeur courante des données d'animation pour appeler SetMetaSprite dans la foulée. Voici le source final, vous pouvez télécharger le [ ZIP ] avec les binaires, le snap, ... startingindex 0 macro animate_push_step addr,meta,zebank,spraddr ; si l'adresse n'est pas nulle, on la force, sinon on calcule l'adresse de la cellule suivante if {addr} : defw {addr} : else : defw $+6+2*{meta} : endif defb #80|{zebank},{meta} defw {spraddr} mendmacro animate_push_coord dekx,deky defb {dekx},{deky} mend i 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+%0100 : out (c),c ; MODE 0 + ROM_UP 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 hl,#6400 : .toBlack ld (hl),#333 : inc l : jr nz,.toBlack ld hl,palette ld de,#6422 ld bc,64 ldir ; on envoie toutes les couleurs d'un coup, fond, border, sprites ei ; activer 4 sprites en ratio mode 1 ld a,%1001 : ld (#6004),a : ld (#600C),a : ld (#6014),a : ld (#601C),a ;*************************************************************** reloop ;*************************************************************** ld h,5 .wait ld b,#F5 : .waitNoVBL in a,(c) : rra : jr c,.waitNoVBL ld b,#F5 : .waitVBL in a,(c) : rra : jr nc,.waitVBL dec h : jr nz,.wait ld hl,animation : ld a,#40 : call animate_execute_step jr reloop ; A=sprite destination ; HL=animation animate_execute_step ;.reloop ld e,(hl) : inc hl : ld d,(hl) : dec hl ; current step in 'animation' ex hl,de : ldi : ldi ; overwrite current step in 'animation' ld b,#DF : ld c,(hl) : inc hl : out (c),c : ld d,a ; Dx=adresse du sprite hard ld a,(hl) : inc hl : ld xl,a : ld xh,a ; backup du compteur dans XH ld a,(hl) : inc hl : ld e,(hl) : inc hl : push hl : ld h,e : ld l,a : ld e,0 ; HL = sprite data source / DE = sprite destination ld b,hi(hsp_conversion) .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 ; DE = next sprite ld a,d : sub #40 : sub xh : ld c,xh add a : add a : add a : ld xh,#60 : ld xl,a ld hl,(positionx) : ld de,(positiony) pop iy : ld a,c ; IX=info du premier sprite dans l'ASIC ; IY=info de placement des sprites ; HL=x DE=y du premier sprite ; A=nombre de sprites SetMetaSprite ; **** d'abord boucler sur les X ************ push af,de,ix : ld de,8 .modifyX exa ld c,(iy+0) ld a,c : add a : sbc a : ld b,a ; faire une valeur 16 bits signées à partir de C add hl,bc ; modifier le X ld (ix+0),hl add ix,de inc iy exa : dec a : jr nz,.modifyX pop ix,hl,af .modifyY exa ld c,(iy+0) ld a,c : add a : sbc a : ld b,a ; faire une valeur 16 bits signées à partir de C add hl,bc ; modifier le X ld (ix+2),hl add ix,de inc iy exa : dec a : jr nz,.modifyY ret align 256 hsp_conversion sprdata=0 repeat 256 defb sprdata>>4 : sprdata+=1 rend palette defw #000,#040,#060,#4B2,#0D0,#6D4,#65D,#76E,#BB9,#96F,#C6D,#BF6,#FE9,#DCF,#FFF align 256 : hsp_estebanNage incbin 'hsp_esteban.bin' animation defw estebanNage positionx defw 260 positiony defw 90 align 2 estebanNage animate_push_step 0,4,{bank}hsp_estebanNage,hsp_estebanNage ; 1ère étape, les 3 premiers sprites sont décalés de 1 pixel vers le bas defb 0,0,32,32,-1,16,0,1 animate_push_step 0,4,{bank}hsp_estebanNage,hsp_estebanNage+(4*128)*1 ; étapes suivantes, même topo, décalage des 3 premiers et réajustement inverse sur le dernier defb 0,0,32,32,-1,16,0,1 animate_push_step 0,4,{bank}hsp_estebanNage,hsp_estebanNage+(4*128)*2 defb 0,0,32,32,-2,16,0,2 animate_push_step 0,4,{bank}hsp_estebanNage,hsp_estebanNage+(4*128)*3 defb 0,0,32,32,-4,16,0,4 animate_push_step 0,4,{bank}hsp_estebanNage,hsp_estebanNage+(4*128)*4 defb 0,0,32,32,-4,16,0,4 animate_push_step 0,4,{bank}hsp_estebanNage,hsp_estebanNage+(4*128)*5 defb 0,0,32,32,-5,16,0,5 ; 7è étape, 3 premiers sprites ajustés de 5 vers le bas PLUS la tête de 2 vers la gauche (à compenser sur le 2è sprite) animate_push_step 0,4,{bank}hsp_estebanNage,hsp_estebanNage+(4*128)*6 defb 2,-2,32,32,-5,16,0,5 animate_push_step 0,4,{bank}hsp_estebanNage,hsp_estebanNage+(4*128)*7 defb 3,-3,32,32,-5,16,0,5 animate_push_step 0,4,{bank}hsp_estebanNage,hsp_estebanNage+(4*128)*8 defb 2,-2,32,32,-5,16,0,5 animate_push_step 0,4,{bank}hsp_estebanNage,hsp_estebanNage+(4*128)*9 defb 2,-2,32,32,-4,16,0,4 ; 11è étape, deux premiers sprites décalés de 2 vers le bas, 3è sprite de 3 vers le bas, compensation sur le dernier animate_push_step estebanNage,4,{bank}hsp_estebanNage,hsp_estebanNage+(4*128)*10 defb 0,0,32,32,-2,16,-1,3Et voici le résultat en mode debug avec l'émulateur CPCEC patché pour le debug :) 
Suggestion de présentation :p 
Rendez-vous dans [ l'article suivant ] pour améliorer notre jeu de routines Roudoudou CPCrulez[Content Management System] v8.732-desktop/c Page créée en 606 millisecondes et consultée 48 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. |
|