Revenir au plan du site

Il nous reste une fonte et de l'espace disponible dans les bandes noires...

Les Amstrad ne sont pas capable de réaliser des scrollings verticaux partiels simplement. Pas que ça soit impossible mais la technique est inutilisable hors démo et la complexité est largement hors de portée de ces cours pour débutants. Pour commencer, nous allons scroller une bande noire, en fait déplacer les données de chaque ligne, une ligne plus haut.
Note : Notre colonne fait 4 octets de large.
ScrollBande
; HL=adresse du coin supérieur gauche de la colonne à scroller
ld de,hl : ld a,h : add 8 : ld h,a ; calculer l'adresse de la ligne suivante
ld xl,100 ; compteur 100 parce qu'on va faire deux copies par tout de compteur
.scroll200
ldi : ldi : ldi : ld a,(hl) : ld (de),a ; copier 4 octets au dessus
ld d,h ; la ligne courante devient la nouvelle destination
ld a,h : add 8 : ld h,a ; on descend la ligne courante
jr nc,.okBlock : ld bc,80-#4000 : add hl,bc : .okBlock
; nos pointeurs sont maintenant sur la droite, on copie à l'envers!
ldd : ldd : ldd : ld a,(hl) : ld (de),a
ld de,hl ; courante devient destination, on copie aussi le poids faible en cas d'ajustement de bloc
ld a,h : add 8 : ld h,a ; on descend la ligne courante, on est sûr de rester dans le bloc
dec xl : jr nz,.scroll200
ret

Vous pouvez jouer à envoyer l'adresse du milieu de l'écran pour voir scroller le graph.


Et quand vous aurez fini de buller, vous revenez de suite bûcher votre assembleur nom didjou! Il nous reste des lettres à faire scroller!

Si on décrit le processus de ce scrollText, une fois que l'on a déplacé toutes les lignes vers le haut, il faut... ...toutes? Non!
La dernière ligne n'est pas déplacée, elle est copiée. Ce qui veut dire que la ligne du bas se dédouble. Si on veut que quelque chose monte dans la colonne de Scroll, il faut l'insérer, ligne après ligne, en bas de la colonne.

Plus détaillé, nous avons un texte dont il faut parcourir chaque lettre l'une après l'autre, et pour chaque lettre, nous devons parcourir l'une après l'autre chaque ligne de la lettre.

Pour réaliser cela, il nous faut donc :
- un pointeur sur le caractères courant
- un pointeur vers le sprite courant
- un compteur de la ligne de caractère en cours d'affichage

À chaque tour, on affiche la ligne courante du caractère courant, on incrémente la ligne, si on termine la 17è ligne, on revient à zéro et on passe au caractère suivant. Idéalement on contrôle aussi qu'on ne soit pas au dernier caractère du texte pour revenir au début.

Allez, au code!
BUILDSNA : BANKSET 0
ORG #38 : EI : RET
ORG #100 : RUN #100

ld sp,#100 : ei
ld bc,#7F00+%10001100+%00 : out (c),c ; MODE 0
ld hl,palette : ld bc,#7F00
setPalette out (c),c : inc c : inc b : outi : ld a,(hl) : or a : jr nz,setPalette
LaBoucle
call waitVBLstart
ld iy,yeuxOuverts : pokeYeux=$-2 : call GestionEtape
ld iy,doigts1 : pokeDoigts=$-2 : call GestionEtape

ld hl,#C000+3 : call ScrollBande
ld de,#C000+3+24*80+7*#800 ; ligne 199 en dessous
call DisplayCharLine
ld hl,#C000+72 : call ScrollBande
ld hl,#C000+3+10*80 : ld de,#C000+72+24*80+7*#800 : ldi : ldi : ldi : ldi ; copie retardée
jr LaBoucle
;---
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
;---
struct etape
duree defb
sprdata defw
adrecran defw
hauteur defb
etapeSuivante defw
pokeEtape defw
dureeMin defb
dureeMod defb
endstruct
;---
yeuxOuverts
defb 1
defw yeuxFermesdata
defw #C000+80*7+#800*6+40
defb 21
defw yeuxFermes
defw pokeYeux
defb 4,3

yeuxFermes
defb 1
defw yeuxOuvertsdata
defw #C000+80*7+#800*6+40
defb 21
defw yeuxOuverts
defw pokeYeux
defb 30,31

doigts1
defb 1
defw doigts2data
defw #C000+80*13+32+#800*2
defb 30
defw doigts2
defw pokeDoigts
defb 15,15

doigts2
defb 1
defw doigts1data
defw #C000+80*13+32+#800*2
defb 30
defw doigts1
defw pokeDoigts
defb 15,15

;---
DisplayCharLine
.currentData ld hl,daFonte : ldi 4 : ld (.currentData+1),hl ; copier la ligne du char
.currentStep ld a,17 : dec a : jr z,.currentChar ; décompter les lignes du sprite
ld (.currentStep+1),a : ret
;
.currentChar ld hl,LeTexte : inc hl : ld (.currentChar+1),hl
ld a,17 : ld (.currentStep+1),a ; réarmer le compteur de lignes
ld a,(hl) : cp 255 : jr nz,.texteOK ; choper le nouveau caractère
ld hl,LeTexte : ld a,(hl) : ld (.currentChar+1),hl ; reinit du texte
.texteOK ld l,a : ld h,0 : ld de,hl
add hl,hl : add hl,hl : add hl,hl : add hl,hl ; x16
add hl,de ; x17
add hl,hl : add hl,hl ; x17 x4
ld de,daFonte : add hl,de ; données de la lettre en cours
ld (.currentData+1),hl ; qu'on remet dans la routine de copie
ret

GestionEtape
; IY=etape
ld a,(iy+etape.duree) : dec a : ld (iy+etape.duree),a : ret nz ; durée pas terminée, aurevoir
ld hl,(iy+etape.sprdata)
ld de,(iy+etape.adrecran)
ld a,(iy+etape.hauteur) : ld xl,a
call AfficheSprite
ld de,(iy+etape.etapeSuivante)
ld hl,(iy+etape.pokeEtape) : ld (hl),e : inc hl : ld (hl),d
ld c,(iy+etape.dureeMod) : ld a,r : and c : add (iy+etape.dureeMin) ; A=nouvelle durée
ld (de),a ; nouvelle duree de la nouvelle structure
ret
;---
AfficheSprite
; HL=données du sprite
; DE=adresse écran en haut à gauche du sprite
; XL=hauteur du sprite
.afficheLigne push de : ldi 12 : pop de
ld a,d : add 8 : ld d,a ; ajouter #800 à DE
jr nc,.nextLine ; pas de débordement, on est toujours dans le même bloc de lignes
ld a,80  : add e : ld e,a ; on ajoute 80 (largeur d'une ligne en octets) pour passer au bloc suivant
ld a,#C0 : adc d : ld d,a ; et on enlève #4000 (additionner #C000 c'est comme enlever #4000)
.nextLine
dec xl
jr nz,.afficheLigne
ret
;---
ScrollBande
; HL=adresse du coin supérieur gauche de la colonne à scroller
ld de,hl : ld a,h : add 8 : ld h,a ; ligne suivante
ld xl,100
.scroll200
ldi : ldi : ldi : ld a,(hl) : ld (de),a ; copier 4 octets au dessus
ld d,h ; la ligne courante devient la nouvelle destination
ld a,h : add 8 : ld h,a ; on descend la ligne courante
jr nc,.okBlock : ld bc,80-#4000 : add hl,bc : .okBlock
; nos pointeurs sont maintenant sur la droite, on copie à l'envers!
ldd : ldd : ldd : ld a,(hl) : ld (de),a
ld de,hl ; courante devient destination, on copie aussi le poids faible en cas d'ajustement de bloc
ld a,h : add 8 : ld h,a ; on descend la ligne courante, on est sûr de rester dans le bloc
dec xl : jr nz,.scroll200
ret
;---
palette defb #54,#5C,#44,#56,#46,#4C,#55,#57,#45,#4E,#5F,#59,#4A,#43,#5B,#4B
border defb #54,0
align 4
daFonte incbin 'daFonte.bin'
doigts1data incbin 'doigts1.bin'
doigts2data incbin 'doigts2.bin'
yeuxOuvertsdata incbin 'yeuxOuverts.bin'
yeuxFermesdata incbin 'yeuxFermes.bin'
; la commande Charset permet de 'renommer' les valeurs ASCII, ici on repart de zéro au lieu de 32
charset ' !"###&\'()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz',0
LeTexte defb ' alors qui est le meilleur? ',255
charset

org #C000 : incbin 'screen160.bin'


Joyeux Noël!

Pour pouvoir enregistrer cette intro sur un support exploitable par un CPC, rendez-vous dans le [3è et dernier article!]