09-Déplacement du joueur

Maintenant que les SPRITES sont affichés, on va commencer à faire bouger la fusée du joueur.

Pour cela on va un peu modifier la structure du code assembleur. Il y surement d’autres méthodes, mais c’est celle présentée par le livre, donc je l’ai suivi.

Jusqu’à présent la ROM démarre et appelle tout de suite le sous-programme INIT. Pourquoi ? Ben, parce qu’on l’a spécifié dans l’entête du code, souvenez vous le DW INIT :

Bon et bien maintenant on ne veut pas simplement faire une initialisation (accéder au SCREEN 1 et afficher les SPRITES), on veut installer une partie de code qui va devenir le programme principal, c’est par lui que la ROM va débuter.

C’est encore lui qui va se charger d’initialiser l’affichage la première fois, et qui ensuite, va continuellement surveiller le clavier (via une boucle infinie) et appeler momentanément des sous-programmes de déplacement en fonction de la touche qu’il a détecté.

Bon, on va mieux visualiser par un schéma :

![orga](/tuto asm 01/09/images/1.png?classes=shadow)

Ainsi la ROM ne va plus appeler INIT mais un label que j’appelle DEBUT qui va se charger d’appeler le sous-programme (ou routine) INIT. Ensuite DEBUT se termine et donne la main à un nouveau label (ou étiquette) qui s’appelle BOUCLE (c’est notre boucle sans fin) qui va tourner en boucle justement en appelant une routine de temporisation (qui ralenti l’affichage écran) et qui surveille le clavier.

Si pendant cette boucle infinie, une touche directionnelle est enfoncée alors on fait appel à la routine de déplacement de la fusée.

Tous les sous-programmes sont codés de façon à retourner au programme principal une fois leur boulot exécuté.

Voilà à quoi va ressembler notre programme principal:

![orga 1](/tuto asm 01/09/images/2.png?classes=shadow)

Dans l’article précédent nous avons déjà codé la routine INIT: (INITIALISATION), Il reste à coder le programme principal, les routines de temporisation et de déplacement. Mais avant, modifions notre entête pour que la ROM lance DEBUT au démarrage et non plus INIT :

PROGRAMME PRINCIPAL - DEBUT

Je vous livre le code par morceaux, ne vous occupez pas de savoir où le placer dans le fichier, je vous ferai une copie intégrale du code à la fin pour que vous voyez l’organisation.

Rien de plus simple pour commencer. Vous remarquez qu’il n’y a pas d’instruction ret (RETURN) à la fin de cette routine. Ainsi le code va continuer au label déclaré juste en dessous puisqu’il n’est pas arrêté ni re-routé. Ca tombe bien puisque le prochain label que l’on va déclarer ensuite est BOUCLE

PROGRAMME PRINCIPAL - BOUCLE

C’est bien le coeur du programme et il va tourner en boucle (comme son label l’indique), d’ailleurs la dernière ligne de cette partie du code se termine par un JP BOUCLE : Saute au début du label BOUCLE:.

Voici ce que fait la boucle :

  • Appelle une routine DELAI. Verifie si la touche gauche est enfoncée, si tel est le cas, elle appelle la routine de déplacement du sprite vers la gauche FUSGAU. Cette routine lui rendra la main à la fin.
  • Appelle la routine DELAI. Verifie si la touche droite est enfoncée, si tel est le cas, elle appelle la routine de déplacement du sprite vers la droite FUSDRO. Cette routine lui rendra la main à la fin. Appelle la routine DELAI.
  • Retourne au début de la boucle.

0n voit déjà que l’on aura 3 routines à écrire par la suite :

-Routine DELAI

  • Routine FUSGAU
  • Routine FUSDRO

Mais revenons à notre boucle pour l’instant. On voit qu’après avoir appelé la routine DELAI, on vérifie l’enfoncement de la touche gauche, comment ça marche ?

En fait, on se base sur une matrice de clavier et une instruction du BIOS qui surveille cette matrice :

![orga 1](/tuto asm 01/09/images/3.png?classes=shadow)

Et l’instruction SNSMAT du BIOS c’est le CALL 321 (ou call 141 en hexa) :

SNSMAT
Address : #0141
Function : Returns the value of the specified line from the keyboard matrix
Input : A - for the specified line
Output : A - for data (the bit corresponding to the pressed key will be 0)
Registers: AF

Cette instruction BIOS nous dit : Donnez-moi dans A la ligne qui vous intéresse, et je vous charge dans A les infos des bit0 à 7 de cette ligne.

Nous on veut la touche gauche, elle correspond à la ligne 8, donc si on charge A avec 8 et qu’on appelle la routine, on récupère toutes les infos de cette ligne dans A.

La touche gauche c’est le bit 4 (colonnes de la matrice), l’instruction BIOS nous dit que si la touche est enfoncée alors le bit correspondant égale 0.

C’est exactement ce que l’on fait avec BIT 4,A : on teste A avec bit 4 et la ligne suivante on appelle la routine FUSGAU si A est à zéro call z,FUSGAU.

Je vous laisse chercher pour le curseur à droite et l’appel à la routine correspondante.

DELAI

Cette routine permet de ralentir le déplacement de la fusée entre autre sinon cela irait trop vite et on ne verrait pas notre fusée se déplacer de façon douce.

Ce n’est rien d’autre qu’une boucle qui va compter de 255 à 0 sans rien faire d’autre avant de rendre la main au programme principal.

Cette routine a 2 labels:

  • Le label DELAI, qui est initialisation du compteur à 255 passe le relai au label DEL qui va faire le travail de comptage.
  • Le label DEL va décrémenter A d’une unité DEC A, si A n’égale pas zéro (NZ=Non Zéro) alors on revient au début de DEL
  • Si A=0 alors on ne fait plus de JUMP (puisque le résultat n’est pas vérifié) mais on fait un retour au programme qui l’a appelé (programme principal) via un RET (return).

Vous pourrez vous amuser à changer la valeur 255 par 1 pour voir le résultat.

FUSGAU

Quand on arrive dans cette routine c’est que la touche gauche a été enfoncée.

Donc on va devoir déplacer notre fusée vers la gauche d’un pixel. Pour cela il nous faut la coordonnée horizontale de notre fusée.

Rien de plus simple, quand on a chargé les attributs des sprites dans la TAS, on a commencée à les enregistrer à l’adresse 6912 (début de la TAS) et en plus le 1er sprite pour lequel on a chargé les infos (4 données: position y, position x, numéro de sprite, couleur) c’est notre fusée. Donc les données de notre sprite sont aux adresses suivantes :

  • Adresse 6912 : position y
  • Adresse 6913 : position x
  • Adresse 6914 : numéro du sprite
  • Adresse 6915 : couleur du sprite

Et ainsi de suite pour les sprites suivants (vous devriez donc connaître les coordonées du sprite ennemi…en tout cas leurs adresses).

Dans notre cas, la fusée, on sait que la position x est à l’adresse 6913.

Il suffit donc de l’appeler, de faire des calculs sur la valeur x et de la recharger dans la TAS pour que notre sprite prenne en compte la nouvelle position.

Pour lire la valeur d’une adresse de la VRAM on fait un CALL 74 (CALL 4A) qui chargera la valeur dans l’accumulateur A :

RDVRM
Address : #004A
Function : Reads the content of VRAM
Input : HL - address read
Output : A - value which was read
Registers: AF

On soustrait 1 unité, et oui pour aller à gauche on revient vers la coordonnée 0 de l’écran. On retourne au programme principale sans rien faire si A=0 (RET Z) car cela veut dire que l’on est déjà à l’extrémité gauche de l’écran. Sinon on continue dans le code, on a déjà décrémenté A, donc il nous reste plus qu’à écrire à l’adresse chargée dans l’accumulateur HL la nouvelle valeur via un CALL 77 (CALL 4D) :

WRTVRM
Address : #004D
Function : Writes data in VRAM
Input : HL - address write
A - value write
Registers: AF

Et on retourne au programme principal (RET).

FUSDRO

C’est pareil que pour la routine précédente. Seul change le test de l’extrémité de l’écran à droite qui est fixé à 240 (240+ 16 pixels de notre sprite =256…..un sprite de 8 mais agrandi x 2).

Comme pour l’instant on pratique des calculs qui nous permettent de comparer à 0 ou non 0 , pour vérifier si x est déjà à 240, il suffit de luis soustraire 240 et de comparer à 0, sinon on lui rajoute les 240 pour le ramener à l’état dans lequel on la récupéré et on lui rajoute 1 pour qu’il se déplace à droite. Ce code devrait s’abstenir de plus de commentaires désormais.

Je vous livre le code en entier pour que vous voyez l’ordre des routines insérées bien qu’il n’y ait pas grande importance (sauf pour celles où on n’a pas mis de RET pour qu’elles enchaînent sur le prochain label en dessous, ex :DEBUT et BOUCLE) puisqu’une fois la ROM démarrée, elle va appeler la routine ‘DEBUT’ et les sauts vont s’enchaîner comme on l’a codé. Compilez, jouez vous devriez pouvoir déplacer votre fusée :