Revenir au plan du site

Amélioration de nos routines de gestion des meta-sprites

Dans l'article précédent, notre routine push_step était bien seule et écrire nos données de déplacement en scindant mentalement le X et le Y est non seulement barbant mais aussi source d'erreur...

Grâce à la dernière version de Rasm (récupérez au moins une version 2.3.9) il est possible de stocker nos coordonnées dans des tableaux et les dépiler dans le bon ordre à la demande, voyons comment faire.

On va d'abord modifier notre première macro de définition d'une étape d'animation en initialisant un compteur et une valeur de vérification.
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}
animateStepCount=0
animateStepCountTarget={meta}
mend

La macro suivante sera à appeler avec le deltaX et le deltaY pour chaque sprite. Vous remarquez que cette macro ne produit aucun octet mais stocke les valeurs dans deux pseudo-tableaux. On en profite pour vérifier qu'on n'ajoute pas trop d'étapes de delta.
macro animate_push_delta dekx,deky
animateStepDeltaX{animateStepCount}={dekx}
animateStepDeltaY{animateStepCount}={deky}
animateStepCount+=1
if animateStepCount>animateStepCountTarget : assert 0==1,"Trop d'etapes!" : endif
mend

Enfin, une fois toutes les coordonnées envoyées, il faut écrire les données pour notre structure, voici la macro qui termine l'étape d'animation. Elle va aussi contrôler que le nombre d'étapes delta est en accord avec celui de la routine animate_push_step
macro animate_pop_delta
if animateStepCount!=animateStepCountTarget : assert 0==1,"Nombre d'etapes incorrect!" : endif
animateStepCount=0
repeat animateStepCountTarget : defb animateStepDeltaX{animateStepCount} : animateStepCount+=1 : rend
animateStepCount=0
repeat animateStepCountTarget : defb animateStepDeltaY{animateStepCount} : animateStepCount+=1 : rend
mend

On peut donc définir une étape d'animation de la façon suivante qui est beaucoup plus lisible :
animate_push_step 0,4,{bank}hsp_estebanNage,hsp_estebanNage
animate_push_delta 0,-1 : animate_push_delta 0,16 : animate_push_delta 32,0 : animate_push_delta 32,1
animate_pop_delta (void) ; sans paramètre il est fortement conseillé d'utiliser le (void)

Le résultat ne change pas visuellement, mais notre code est plus robuste ainsi.

Comment rendre plus souple l'exécution des étapes d'animation?

Pour le moment, notre routine d'exécution des étapes d'animation récupère la positionX et la positionY depuis deux variables. Comment faire pour rendre cette routine générique? Il n'est pas pertinent de modifier à chaque fois ces deux variables, il faudrait que la routine puisse accéder à ces coordonnées de façon indirecte.

Solution la plus simple, utiliser IY comme descripteur de notre objet. Ce registre n'est utilisé que dans la deuxième partie qui modifie les coordonnées des sprites. On peut donc imaginer une structure d'objet renseignant l'animation courante.
struct s_animation
    animation defw
    positionx defw
    positiony defw
    destination defb ; poids fort de la destination hardware
endstruct

On modifie notre routine en accord avec cette structure.
; IY = objet animation
animate_execute_step
push iy : pop hl ; HL pointe sur objet.animation
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 ; connexion de la bank contenant les données
ld a,(hl) : inc hl : ld xl,a : ld xh,a ; backup du compteur dans XL et XH
ld e,(hl) : inc hl : ld d,(hl) : inc hl : push hl : ex hl,de ; HL=sprite data source
ld b,hi(hsp_conversion) ; poids fort pour la table de conversion
ld d,(iy+s_animation.destination) : ld e,0 ; DE=sprite destination
.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,(iy+s_animation.positionx) : ld de,(iy+s_animation.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

...

Maintenant, il est possible de dupliquer facilement Esteban aux 4 coins de l'écran (comme il occupe 4 sprites, on peut fabriquer 4 objets et utiliser les 16 sprites). L'idée derrière cette démonstration est d'avoir une routine qui puisse gérer plusieurs objets, différents si on veut...
struct s_animation esteban01,1,estebanNage,100,90 ,#40 ; sprites 0 à 3
struct s_animation esteban02,1,estebanNage,400,90 ,#44 ; sprites 4 à 7
struct s_animation esteban03,1,estebanNage,100,140,#48 ; sprites 8 à 11
struct s_animation esteban04,1,estebanNage,400,140,#4C ; sprites 12+

Et on enchainera les appels à animate_execute_step en faisant pointer IY vers l'un de ces 4 objets, esteban01, esteban02, ...

Le zip de la démo est téléchargeable [ ici ]