ASMtrad CPC

Apprenez l'assembleur Z80

Déplacement de sprite, restitution:

Maintenant qu'on sait tester une touche, on va pouvoir déplacer notre sprite.

Imaginons votre routine de sprite comme tel:

                FRAME               LD      B,#F5
                FRM                 IN      A,(C)
                                    RRA
                                    JR      NC,FRM              ;on teste la VBL

                Coordonnee_ecran    LD      HL,#C020            ;notez que j'utilise des noms de label très explicites.
                                    CALL    AFFICHE_SPRITE      ;là bien evidement ce label saute à votre routine d'affichage
                                    LD      D,5:CALL TOUCHE     ;J'ai mis la routine de test de touche plus loin avec un label TOUCHE et là je teste la ligne 5
                                    CP      %01111111           ;je regarde si la touche ESPACE est pressée
                                    JP      NZ,FRAME            ;si ce n'est pas le cas on retourne à FRAME
                                    RET                         ;sinon on s'arrete là

Nous voulons déplacer notre sprite vers la droite. Ajoutons un test de touche pour cela.

Ensuite, pensons à ce que revient de déplacer un sprite vers la droite.
Cela signifie tout simplement à l'afficher 1 octet plus loin à l'écran.

Ainsi, il suffit d'incrémenter l'adresse d'affichage !!!

Nous allons utiliser les automodifications.

Comme notre adresse est stockée au label Coordonnee_ecran, il suffira d'aller modifier à cette adresse.
Mais attention: LD HL,data prend 1 octet (#21). Les octets de l'adresse sont juste après en RAM.

Il faudra donc modifier ce qui est en Coordonnee_ecran+1.

                FRAME               LD      B,#F5
                FRM                 IN      A,(C)
                                    RRA
                                    JR      NC,FRM                      ;on teste la VBL

                Coordonnee_ecran    LD      HL,#C020                    ;adresse ou on affiche le sprite à l'écran
                                    CALL    AFFICHE_SPRITE              ;saute à votre routine d'affichage
                                    LD      D,0:CALL TOUCHE             ;la touche curseur droit sur le clavier est à la ligne 0
                                    CP      %11111101                   ;c'est le bit 1 qu'il faut tester
                                    JP      NZ,FRAME                    ;si ce n'est pas le cas on retourne à FRAME
                droite              LD      HL,(Coordonnee_ecran+1)     ;on prend l'adresse contenue en Coordonnee_ecran+1
                                    INC     HL                          ;on incrémente l'adresse
                                    LD      (Coordonnee_ecran+1),HL     ;on automodifie l'adresse
                                    JP      FRAME                       ;on retourne au début de la boucle FRAME

Bien entendu aller à gauche signifie decrementer (DEC HL) l'adresse.
Descendre revient à mettre l'adresse d'en dessous et monter, l'adresse d'au dessus (il faudra les calculer par exemple).

Restitution du fond

C'est bien gentil tout ca mais c'est moche !!!

Notre sprite se déplace, mais laisse une affreuse trainée derrière lui :(

C'est normal, quand notre sprite est affiché décalé d'un octet, le sprite précedement affiché n'est pas effacé.
Il reste donc une colonne du précédent sprite qui n'a pas été écrasée par le nouvel affichage.

Nous avons donc deux solutions:

- Avoir un fond de couleur uniforme et effacer la zone avant d'afficher notre sprite.
- Sauvegarder le fond et le ré-afficher avant le déplacement.

Pour la première solution rien de plus simple, avant d'afficher notre sprite, on remplis la zone avec des 0 par exemple (ou un autre octet si vous n'avez pas utilisé la couleur 0). Au passage, on peut utiliser un fond uniforme tramé ou répétitif ce qui sera plus original qu'un fond noir...
On se contentera donc de faire un affichage avec une valeur fixe.

Exemple:

                                    LD      A,0                                 ;on met un octet 0 dans A car ce sera notre couleur de fond
                                    LD      HL,adresse_du_sprite_a_l_ecran      ;label long mais explicite
                                    LD      B,hauteur                           ;hauteur du sprite
                sprite_vide         PUSH    BC
                                    PUSH    HL
                                    LD      (HL),A                              ;on balance un 0 a l’écran
                                    LD      E,L:LD D,H:INC DE                   ;on recopie HL dans DE et on incrémente l'adresse. DE contient donc HL+1
                                    LD      BC,largeur-1                        ;-1 car on a déjà envoyé un octet                                  
                                    LDIR                                        ;on recopie les 0
                                    POP     HL
                                    CALL    calcul_ligne_inferieure             ;si la routine de calcul fonctionne avec HL, sinon ajoutez un EX DE,HL Avant et après le CALL
                                    POP     BC
                                    DJNZ    sprite_vide

A noter que la je remplis de 0 toute la zone du sprite, ce qui est idiot si vous vous déplacez d'un seul octet !!!
Il suffirait d'afficher une bande noire, d'un seul octet, à la coordonnée de votre sprite, avant de le bouger vers la droite...
Il en est de même pour les autres directions mais la bande à droite si vous allez à gauche etc etc.

Mais le plus intéressant, c'est quand même de sauvegarder le fond pour le restituer ensuite.

Pour cela il va falloir capturer le fond avant d'afficher dessus.

Le principe est simple:

Avant (ou pendant) que vous affichez votre sprite, vous récupérez les octets de l'écran avant d'afficher par dessus.
Vous stockez alors le tout quelque part en RAM.
Lorsque vous déplacerez votre sprite, vous devrez alors réafficher le fond que vous avez stocké, puis vous continuerez.

Bien entendu, il faut réflechir avant de stocker votre fond. Plusieurs solutions existent.
Vous pourrez par exemple stocker par bande, et ne ré-afficher que la bande nécessaire.
Réfléchissez bien au temps pris par votre routine car parfois tout réafficher est plus rapide que de n'afficher qu'une bande selon comment elle est stockée
Ne perdez pas de cpu inutilement...

Notez aussi que parfois, dans certains jeux la solution d'avoir le fond quelque part en mémoire avec rien dessus a été retenue.
Ce n'est pas forcément une mauvaise solution si vous avez beaucoup de RAM disponible. Encore une fois il faut calculer.

Vous pourrez aussi par exemple sauvegarder le fond à une adresse, puis récupérer les valeurs grâce à la pile (donc par groupe de 2 octets) afin de gagner du temps.

Il y a donc beaucoup de possibilité en fonction du besoin et des contraintes.
Beaucoup d'astuces aussi à trouver. Mais je vous laisse y réfléchir.