Une routine dédiée par mouvementPlus simple et permettant de gérer tous les cas sans passer sa vie à faire des comparaisons, on va dédier une fonction par mouvement et l'appeler à chaque fois. On change de mouvement, on change la routine de gestion. Le code principal se raccourci : 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 ld hl,(Conrad.routine) : jp (hl) ; saut inconditionnel vers la routine de gestion du mouvement en cours Il faut maintenant définir toutes les combinaisons possibles en fonction de chaque mouvement.Sur le diagramme ci-dessous, j'ai mis en évidence toutes les relations d'un mouvement à l'autre, on voit que certains sont plus complexes qued'autres mais la majorité sont en fait (pour cette planche) des mouvements avec peu de connexions. Le jeu original ajoute les chutes, monterou descendre et c'est beaucoup plus de travail. 

Évolution des objets pour gérer plus de données Avec toutes ces animations, on va exploser largement la mémoire centrale. Nous allons donc modifier nos objets pour qu'ils indiquent la bank/ROM à connecter pour chaque sprite. Et il serapossible plus tard de gérer les données plus finement, c'est à dire optimiser leur placement en mémoire pour bien remplir chaque bank/ROM. startingindex 0 macro animate_single zelabel,nbanim curspr=0 repeat {nbanim}-1 defw $+5 ; nos objets font maintenant 5 octets, on passe au suivant defb {bank}{zelabel} defw {zelabel}+6*128*curspr curspr+=1 rend defw $ ; boucle infinie sur la dernière étape defb {bank}{zelabel} defw {zelabel}+6*128*curspr mendIdem pour les données lues à l'envers, taille de l'objet 5 et le DEFB de la bank... startingindex 0 macro animate_single_reverse zelabel,nbanim curspr=nbanim-1 repeat {nbanim}-1 defw $+5 defb {bank}{zelabel} defw {zelabel}+6*128*curspr curspr-=1 rend defw $ ; infinite loop on last step defb {bank}{zelabel} defw {zelabel}+6*128*curspr mendLe moteur doit gérer cet octet supplémentaire pour connecter la ROM supérieure (ou de la RAM, vous adaptez comme vous voulez le code).; A=sprite destination ; HL=animation animate_execute_step ;.reloop ld e,(hl) : inc l : ld d,(hl) : dec l ;: ex hl,de ; 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 ; ROM connectée 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 spriteNouvelles macros pour gérer d'autres types d'animationsPour la marche, nous aurons besoin d'une macro qui s'occupe de reboucler une animation. startingindex 0 macro animate_loop zelabel,nbanim startAnim=$ 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 startAnim ; retour au début defw {zelabel}+6*128*curspr mendPour le tir, c'est le type "ping-pong" qui va lire les sprites dans un sens, puis dans l'autre et s'arrêter. macro animate_single_pong zelabel,nbanim assert {nbanim}>1,'ping pong seulement avec 2 animations ou plus' curspr=0 repeat {nbanim} defw $+5 defb {bank}{zelabel} defw {zelabel}+6*128*curspr curspr+=1 rend curspr-=2 repeat {nbanim}-2 defw $+5 defb {bank}{zelabel} defw {zelabel}+6*128*curspr curspr-=1 rend defw $ ; on s'arrête après etre revenu au point de départ defb {bank}{zelabel} defw {zelabel}+6*128*curspr mendNew ultimate mega animation engine power boost turbo 2 plus ultraEst-ce que vous êtes chauds? On va réécrire légèrement la gestion de Conrad pour factoriser un peu nos actions, car de façon générale (je n'ai pas mis la marche),on exécute un mouvement puis on gère à nouveau le clavier. Ainsi, chacun de nos mouvements se contentera d'appeler cette routine etau besoin, de gérer quelques touches. L'initialisation a besoin d'un nombre d'étapes (dans A) et de la routine de gestion à appeler (dans HL) une fois le mouvement terminé. Ensuitec'est la routine qui décompte les "pas" qui se charge de décrémenter son compteur et quand il arrive à zéro, on bascule sur la routine de gestion. ; fonction générique pour exécuter un mouvement bloquant de n étapes, suivi d'une routine de gestion .executeMouvementInit ld (.executeMouvement+1),a : ld (.executeMouvementNext+1),hl : ld hl,.executeMouvement : ld (.routine),hl .executeMouvement ld a,#12 : dec a : ld (.executeMouvement+1),a : jp nz,.execute .executeMouvementNext ld hl,#1234 : ld (.routine),hl : ld a,b : jp (hl) .execute ld a,#40 : ld hl,.animation : call animate_execute_step : jp mainLoop .animation defw conradDroite ; animation par défaut à droite .routine defw .attendreDroite ; defautLes mouvements vont alors se définir de façon un peu répétitives, il faut connecter les actions en accord avec ce qu'on veut.Le code est répétitif, j'ai envie de dire, ça tombe bien, si vous êtes courageux, cette partie pourrait même s'automatiserdans un moteur de jeu :) ;********* Conrad ;********* .attendreDroite ld hl,conradDroite : ld (.animation),hl ld hl,.attendreDroiteManage : ld (.routine),hl .attendreDroiteManage bit 1,a : jp z,.assisDroite bit 2,a : jp z,.retournerGauche ;bit 3,a : jp z,.marcherDroite bit 4,a : jp z,.degainerDeboutDroite jp .execute.attendreGauche ld hl,conradGauche : ld (.animation),hl ld hl,.attendreGaucheManage : ld (.routine),hl .attendreGaucheManage bit 1,a : jp z,.assisGauche ;bit 2,a : jp z,.marcherGauche bit 3,a : jp z,.retournerDroite bit 4,a : jp z,.degainerDeboutGauche jp .execute ;----------------------------------------------------------------- .assisDroite ld hl,conradAssisDroite : ld (.animation),hl ; animation ld a,5 : ld hl,.assisDroiteManage : jp .executeMouvementInit .assisDroiteManage bit 1,a : jp z,.execute ; si on continue d'appuyer sur BAS, on reste assis ld hl,conradRemonteDroite : ld (.animation),hl ; animation ld a,5 : ld hl,.attendreDroite : jp .executeMouvementInit .assisGauche ld hl,conradAssisGauche : ld (.animation),hl ; animation ld a,5 : ld hl,.assisGaucheManage : jp .executeMouvementInit .assisGaucheManage bit 1,a : jp z,.execute ; si on continue d'appuyer sur BAS, on reste assis ld hl,conradRemonteGauche : ld (.animation),hl ; animation ld a,5 : ld hl,.attendreGauche : jp .executeMouvementInit ;----------------------------------------------------------------- .retournerGauche ld hl,conradRetournerGauche : ld (.animation),hl ; animation ld a,5 : ld hl,.attendreGauche : jp .executeMouvementInit .retournerDroite ld hl,conradRetournerDroite : ld (.animation),hl ; animation ld a,5 : ld hl,.attendreDroite : jp .executeMouvementInit ;----------------------------------------------------------------- .degainerDeboutDroite ld hl,conradDegaineDroite : ld (.animation),hl ; animation ld a,8 : ld hl,.attendreDroiteGun : jp .executeMouvementInit .attendreDroiteGun bit 1,a : jp z,.assisDroiteGun bit 2,a : jp z,.retournerGunGauche bit 4,a : jp z,.rengainerDeboutDroite bit 5,a : jp z,.tirerDroite jp .execute .rengainerDeboutDroite ld hl,conradRengaineDroite : ld (.animation),hl ; animation ld a,8 : ld hl,.attendreDroite : jp .executeMouvementInit .degainerDeboutGauche ld hl,conradDegaineGauche : ld (.animation),hl ; animation ld a,8 : ld hl,.attendreGaucheGun : jp .executeMouvementInit .attendreGaucheGun bit 1,a : jp z,.assisGaucheGun bit 3,a : jp z,.retournerGunDroite bit 4,a : jp z,.rengainerDeboutGauche bit 5,a : jp z,.tirerGauche jp .execute .rengainerDeboutGauche ld hl,conradRengaineGauche : ld (.animation),hl ; animation ld a,8 : ld hl,.attendreGauche : jp .executeMouvementInit .retournerGunGauche ld hl,conradRetournerGunGauche : ld (.animation),hl ; animation ld a,10 : ld hl,.attendreGaucheGun : jp .executeMouvementInit .retournerGunDroite ld hl,conradRetournerGunDroite : ld (.animation),hl ; animation ld a,10 : ld hl,.attendreDroiteGun : jp .executeMouvementInit .tirerDroite ld hl,conradTirDroite : ld (.animation),hl ; animation ld a,19 : ld hl,.attendreDroiteGun : jp .executeMouvementInit .tirerGauche ld hl,conradTirGauche : ld (.animation),hl ; animation ld a,19 : ld hl,.attendreGaucheGun : jp .executeMouvementInit ;----------------------------------------------------------------- .assisDroiteGun ld hl,conradAssisGunDroite : ld (.animation),hl ; animation ld a,6 : ld hl,.attendreDroiteAssisGun : jp .executeMouvementInit .attendreDroiteAssisGun bit 5,a : jp z,.tirerAssisDroite bit 2,a : jp z,.retournerGunAssisGauche bit 1,a : jp z,.execute ; tant qu'on appuie bas, on reste bas ld hl,conradRemonteGunDroite : ld (.animation),hl ; animation ld a,6 : ld hl,.attendreDroiteGun : jp .executeMouvementInit .assisGaucheGun ld hl,conradAssisGunGauche : ld (.animation),hl ; animation ld a,6 : ld hl,.attendreGaucheAssisGun : jp .executeMouvementInit .attendreGaucheAssisGun bit 5,a : jp z,.tirerAssisGauche bit 3,a : jp z,.retournerGunAssisDroite bit 1,a : jp z,.execute ; tant qu'on appuie bas, on reste bas ld hl,conradRemonteGunGauche : ld (.animation),hl ; animation ld a,6 : ld hl,.attendreGaucheGun : jp .executeMouvementInit .retournerGunAssisGauche ld hl,conradRetournerGunAssisGauche : ld (.animation),hl ; animation ld a,8 : ld hl,.attendreGaucheAssisGun : jp .executeMouvementInit .retournerGunAssisDroite ld hl,conradRetournerGunAssisDroite : ld (.animation),hl ; animation ld a,8 : ld hl,.attendreDroiteAssisGun : jp .executeMouvementInit .tirerAssisDroite ld hl,conradTirAssisDroite : ld (.animation),hl ; animation ld a,13 : ld hl,.attendreDroiteAssisGun : jp .executeMouvementInit .tirerAssisGauche ld hl,conradTirAssisGauche : ld (.animation),hl ; animation ld a,13 : ld hl,.attendreGaucheAssisGun : jp .executeMouvementInitJe vous ai fait un gros ZIP à télécharger [ ICI ] il contient les sources et binaires nécessaires... 
On se retrouve dans [ l'article suivant ] pour ajouter la marche et déplacer Conrad ;) Roudoudou CPCrulez[Content Management System] v8.732-desktop/c Page créée en 295 millisecondes et consultée 46 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. |
|