Revenir au plan du site

Un nombre illimité de sprites?


Pour se détendre de toute cette théorie, on va jouer un peu avec les buffers pour un effet visuel bluffant qui n'aura d'autre intérêt que surprendre visuellement. Une quantité de sprites apparemment sans limite sur tout l'écran!

Mais comment cela se peute? Ce peut-il? M'enfin! Comment cela est donc possible?

En fait nous allons poser des sprites et ne jamais les effacer. Et pour donner l'illusion qu'ils bougent, nous allons utiliser 3 écrans vidéos en alternance.



On réutilise le source précédent ou presque. On va tailler dedans, le raccourcir! Plus besoin de sauvegarde, plus besoin de restitution, il faut initialiser les 3 pages vidéos (incbin tout en bas du source). Enfin, il faut que les sprites suivent une trajectoire changeante pour bien remplir l'écran de partout.

Pour la trajectoire, j'utilise un simple sinus que je lirai en changeant uniquement le poids faible de l'adresse. Ainsi, pour rappel, une fois qu'on incrémente la valeur 255 on revient à zéro.

Pour que la lecture fonctionne correctement, il nous faut 256 valeurs ET que le début du tableau commence sur une adresse multiple de 256. Enfin, j'utiliserai deux tables car l'amplitude n'est pas la même en X et en Y.
align 256
ma_table_sinus
ang=0
repeat 256
defb sin(ang)*35+35 : ang=ang+360/256
rend

L'amplitude en X par de zéro et va jusqu'à la largeur écran-largeur_sprite-1. L'amplitude en Y ira de 0 à hauteur_ecran-hauteur_sprite-1. Enfin, comme la valeur d'un sinus s'étends de -1 à 1, il faut diviser cette amplitude par 2 avant de la multiplier au sinus. Enfin on ajoutera l'amplitude divisée par 2 pour que nos nombres soient tous positifs. Si les sinus/cosinus sont un peu obscurs pour vous, n'hésitez pas à me faire des retours, on pourra faire des cours dessus et jouer avec plus en détail.


On est partis?

Utilisation de [hibouZéro] et [forêtZéro]
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

;******************
  BouclePrincipale
;******************
call waitVBLStart
call waitVBLStart ; on attend d'être sûr que l'écran précédent soit complètement affiché
ld a,#10 : ld b,#80 : call AfficherHibou
;
call waitVBLStart
call waitVBLStart ; on attend d'être sûr que l'écran précédent soit complètement affiché
ld a,#20 : ld b,#C0 : call AfficherHibou
;
call waitVBLStart
call waitVBLStart ; on attend d'être sûr que l'écran précédent soit complètement affiché
ld a,#30 : ld b,#40 : call AfficherHibou

jr BouclePrincipale
;=================================================================
; parcourir les tables de sinus et envoyer les sprites à la suite
;=================================================================
AfficherHibou
push bc : ld bc,#BC00+12 : out (c),c : inc b : out (c),a : pop bc
ld h,hi(sinuzix) : ld a,(sinusXpos) : ld l,a : ld c,(hl)
ld de,donnees_sprite
ld h,hi(sinusite) : ld a,(sinusYpos) : ld l,a : ld l,(hl) : ld h,0
ld xl,9 : ld xh,36 ; dimensions du sprite largeur/lignes
call AfficheSprite
ld hl,sinusXpos : inc (hl) : inc hl : inc (hl) ; bouger sur les sinus
.dephase ld a,0 : inc a : and 15 : ld (.dephase+1),a : ret nz
inc (hl) ; extra incrémentation tous les 16 passages pour varier la trajectoire trop régulière sinon

ret

sinusXpos defb 45
sinusYpos defb 0

waitVBLStart ld b,#F5
.loop in a,(c) : rra : jr c,.loop
waitVBL
.loop in a,(c) : rra : ret c : jr .loop
; -------------------------------
AfficheSprite
; BC=page + coordonnée X (0-79) / 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
call CalculeAdressePixel
; HL=destination écran
; DE=toujours l'adresse source des données
ld bc,hl ; on utilise BC comme destination écran

ld h,hi(tableTransparence)
.afficheLignes
ld a,xl : ld yl,a ; chargeur la largeur d'une ligne dans YL
push bc ; on met l'adresse de début de la ligne de côté

.pixelMasque
ld a,(de) ; lire le sprite
ld l,a ; octet du sprite dans L
ld a,(bc) ; on récupère l'octet de l'écran
and (hl) ; on applique le masque
or l ; on fusionne avec la donnée du sprite
ld (bc),a ; on remet dans l'écran
inc bc
inc de ; et on incrémente data+ecran
dec yl
jr nz,.pixelMasque

pop bc ; on récupère l'adresse du début de ligne
; et on calcule le passage à la ligne suivante
; notre routine de passage à la ligne suivante, adaptée pour BC
ld a,b : add 8 : ld b,a ; ajouter #800 à DE
and #38 ; on teste si on déborde de la bank (passage de page+#3800 à page+#0000)
jr nz,.nextLine ; pas zéro, on est toujours dans le même bloc de lignes
ld a,80  : add c : ld c,a ; on ajoute 80 (largeur d'une ligne en octets) pour passer au bloc suivant
ld a,#C0 : adc b : ld b,a ; et on enlève #4000 (additionner #C000 c'est comme enlever #4000)
.nextLine
dec xh ; notre compteur de lignes
jr nz,.afficheLignes
ret
;-------------------
CalculeAdressePixel
; B=page vidéo #00, #40, #80 ou #C0
; C=coordonnée X (0-79)
; HL=coordonnée Y (0-199)
; adresse de la ligne dans HL en résultat
add hl,hl ; adresses 16 bits, il faut indexer de 2 en 2
ld a,lo(tableau) : add l : ld l,a : ld a,h : adc hi(tableau): ld h,a
ld a,(hl) : inc hl
ld h,(hl) : ld l,a
add hl,bc ; ajouter la position X en octets et la page!
ret
;-------------------
adresse_ecran=#0000
largeur_ecran=80
tableau
repeat 25
repeat 8
defw adresse_ecran
adresse_ecran+=#800
rend
adresse_ecran+=largeur_ecran
adresse_ecran-=#4000
rend


align 256
tableTransparence
repeat 256,x
px=x-1 ; car le compteur va par défaut de 1 à 256 et non 0 à 255
masque=0
if (px & (128|32|8|2))==0
    masque|=128|32|8|2 ; pour cet octet on conservera les données écran
endif
if (px & (64|16|4|1))==0
    masque|=64|16|4|1 ; pour cet octet on conservera les données écran
endif
defb masque
rend

align 256
sinusite
ang=0
repeat 256
defb sin(ang)*80+80 : ang=ang+360/256
rend
sinuzix
ang=0
repeat 256
defb sin(ang)*35+35 : ang=ang+360/256
rend
palette defb #4D,#54,#56,#5C,#46,#5E,#40,#47,#43,#4E,#4B,#4C,0 ; Rose en zéro
donnees_sprite incbin 'hibouZero.bin'
; initialiser notre écran sur les trois pages!
org #4000 : incbin 'foretZero.bin'
org #8000 : incbin 'foretZero.bin'
org #C000 : incbin 'foretZero.bin'

Et voici un déroulé temporel dans chacune des banques avec l'affichage écran. On remarque (évidemment j'ai envie de dire) que l'écran a toujours un temps de retard, ceci est dû au fait que la mémoire est mise à jour avant que le balayage n'ait parcouru cette même mémoire. Le point d'arrêt pour réaliser ces séquences était posé juste au début de la routine qui affiche le hibou, lorsque la synchro est terminée.