Animer un sprite softUne petite modification de la routine de sprite qui prend en entrée l'adresse du sprite dans DE. En permutant à la fin HL et DE, on remet dans DE l'adresse du sprite suivant. On peut ainsi réaliser plusieursappels successifs à la routine, sans devoir mettre de côté le pointeur de données ou calculer l'adresse de l'étape suivante. Téléchargez [cette planche de sprites], puis assemblez ce code source (vous avez le droit de le lire, il est commenté de partout). BUILDSNA : BANKSET 0 ORG #100 RUN #100ld bc,#7F00+%10001100+%00 : out (c),c ; MODE 0 ; on règle quelques couleurs pour notre sprite ld bc,#7F00 : out (c),c : ld a,#54 : out (c),a ld bc,#7F01 : out (c),c : ld a,#44 : out (c),a ld bc,#7F02 : out (c),c : ld a,#5C : out (c),a ld bc,#7F03 : out (c),c : ld a,#5E : out (c),a ld bc,#7F04 : out (c),c : ld a,#4E : out (c),a ld bc,#7F05 : out (c),c : ld a,#43 : out (c),a ld bc,#7F06 : out (c),c : ld a,#4B : out (c),a ld iy,listePositions debutSequence ld de,donnees_sprite ld a,20 ; notre compteur de sprites deplacerSprite exa ; on met le compteur dans A' call waitVBL ld l,(iy+0) : inc yl ; en n'incrémentant que le poids faible, on revient tout seul ; au départ au bout de 256 valeurs ld bc,60 ; X=60 ld h,0 ; Y=(iy+0) ld xl,21 ld xh,72 call AfficheSprite exa ; on récupère notre compteur dans A dec a jr nz,deplacerSprite jr debutSequence ; on reprend la séquence de zéro au bout de 20 étapes align 256 listePositions angle=0 repeat 256 defb sin(angle)*20+20+70 angle=angle+360/128 ; 2 périodes histoires d'aller plus vite rend waitVBL ld b,#F5 .loop in a,(c) : rra : jr nc,.loop ret AfficheSprite ; BC=coordonnée X (0-319) ; HL=coordonnée Y (0-199) ; DE=adresse des données du sprite ; XL=largeur du sprite en octets ; XH=hauteur du sprite en nombre de lignes push de ; on met DE dans la pile car le calcul d'adresse s'en sert call CalculeAdressePixel pop de ; et on récupère DE ; HL=destination écran ; DE=toujours l'adresse source des données ex hl,de ; on permute source et destination pour être utilisées ; avec l'instruction LDIR .afficheLignes ld b,0 ld c,xl ; chargeur la largeur d'une ligne push de ; on met l'adresse de début de la ligne de côté ldir ; copier la ligne de HL vers DE sur BC octets pop de ; on récupère l'adresse du début de ligne ; et on calcule le passage à la ligne suivante ex hl,de ; on permute HL et DE pour pouvoir faire des additions ld bc,#800 : add hl,bc : jr nc,.dansLeBloc ld bc,80-#4000 : add hl,bc ; changement de bloc! .dansLeBloc ex hl,de ; on permute à nouveau pour retrouver notre DE une ligne plus bas dec xh ; notre compteur de lignes jr nz,.afficheLignes ex hl,de ; on renvoie dans DE l'adresse du sprite suivant ret ;------------------- CalculeAdressePixel ; BC=coordonnée X (0-159) ; HL=coordonnée Y (0-199) ; adresse de la ligne dans HL en résultat ld de,tableau add hl,hl ; adresses 16 bits, il faut indexer de 2 en 2 add hl,de ld a,(hl) : inc hl ld h,(hl) : ld l,a srl bc : add hl,bc ret ;------------------- adresse_ecran=#C000 largeur_ecran=80 tableau repeat 25 repeat 8 defw adresse_ecran adresse_ecran+=#800 rend adresse_ecran+=largeur_ecran adresse_ecran-=#4000 rend donnees_sprite incbin 'quiPiqueSequence.bin'Ça va trop vite! Bienvenue dans le monde de la programmation pure hard où les routines non optimisées doivent être ralenties ^_^ Mais pourtant, nous attendons bien la VBL? Oui, c'est le cas, mais la planche de sprites n'en contient qu'une vingtaine, ce qui fait qu'à 50Hz, autrement dit 50 balayages par seconde, c'est trop rapide. L'idée première serait d'appeler deux ou trois fois la routine d'attente VBL c'est ça? Mais il y a un hic! Une VBL dure quelques milliers de NOP, si on redemande à attendre la VBL juste après la première, on sera toujours dans la même VBL. C'est assez facile à vérifier en triplant la ligne, il ne se passe rien c'est toujours aussi rapide. La solution est d'abord de vérifier que nous ne sommes pas dans une VBL avant d'attendre la VBL. Nous devons attendre le début de la VBL, pas autre chose. BUILDSNA : BANKSET 0 ORG #100 RUN #100ld bc,#7F00+%10001100+%00 : out (c),c ; MODE 0 ; on règle quelques couleurs pour notre sprite ld bc,#7F00 : out (c),c : ld a,#54 : out (c),a ld bc,#7F01 : out (c),c : ld a,#44 : out (c),a ld bc,#7F02 : out (c),c : ld a,#5C : out (c),a ld bc,#7F03 : out (c),c : ld a,#5E : out (c),a ld bc,#7F04 : out (c),c : ld a,#4E : out (c),a ld bc,#7F05 : out (c),c : ld a,#43 : out (c),a ld bc,#7F06 : out (c),c : ld a,#4B : out (c),a ld iy,listePositions debutSequence ld de,donnees_sprite ld a,20 ; notre compteur de sprites deplacerSprite exa ; on met le compteur dans A' call waitVBLstart ; 50Hz call waitVBLstart ; 25Hz call waitVBLstart ; 17Hz call waitVBLstart ; 12Hz nous afficherons 12 images par seconde ld l,(iy+0) : inc yl ; en n'incrémentant que le poids faible, on revient tout seul ; au départ au bout de 256 valeurs ld bc,60 ; X=60 ld h,0 ; Y=(iy+0) ld xl,21 ld xh,72 call AfficheSprite exa ; on récupère notre compteur dans A dec a jr nz,deplacerSprite jr debutSequence ; on reprend la séquence de zéro au bout de 20 étapes align 256 listePositions angle=0 repeat 256 defb sin(angle)*20+20+70 angle=angle+360/128 ; 2 périodes histoires d'aller plus vite rend waitVBLstart ld b,#F5 .loop in a,(c) : rra : jr c,.loop ; attendre l'absence de VBL waitVBL ld b,#F5 .loop in a,(c) : rra : jr nc,.loop ; attendre la VBL ret AfficheSprite ; BC=coordonnée X (0-319) ; HL=coordonnée Y (0-199) ; DE=adresse des données du sprite ; XL=largeur du sprite en octets ; XH=hauteur du sprite en nombre de lignes push de ; on met DE dans la pile car le calcul d'adresse s'en sert call CalculeAdressePixel pop de ; et on récupère DE ; HL=destination écran ; DE=toujours l'adresse source des données ex hl,de ; on permute source et destination pour être utilisées ; avec l'instruction LDIR .afficheLignes ld b,0 ld c,xl ; chargeur la largeur d'une ligne push de ; on met l'adresse de début de la ligne de côté ldir ; copier la ligne de HL vers DE sur BC octets pop de ; on récupère l'adresse du début de ligne ; et on calcule le passage à la ligne suivante ex hl,de ; on permute HL et DE pour pouvoir faire des additions ld bc,#800 : add hl,bc : jr nc,.dansLeBloc ld bc,80-#4000 : add hl,bc ; changement de bloc! .dansLeBloc ex hl,de ; on permute à nouveau pour retrouver notre DE une ligne plus bas dec xh ; notre compteur de lignes jr nz,.afficheLignes ex hl,de ; on renvoie dans DE l'adresse du sprite suivant ret ;------------------- CalculeAdressePixel ; BC=coordonnée X (0-159) ; HL=coordonnée Y (0-199) ; adresse de la ligne dans HL en résultat ld de,tableau add hl,hl ; adresses 16 bits, il faut indexer de 2 en 2 add hl,de ld a,(hl) : inc hl ld h,(hl) : ld l,a srl bc : add hl,bc ret ;------------------- adresse_ecran=#C000 largeur_ecran=80 tableau repeat 25 repeat 8 defw adresse_ecran adresse_ecran+=#800 rend adresse_ecran+=largeur_ecran adresse_ecran-=#4000 rend donnees_sprite incbin 'quiPiqueSequence.bin' Roudoudou CPCrulez[Content Management System] v8.732-desktop/c Page créée en 422 millisecondes et consultée 26 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. |
|