Table des matières

Retourner au sommaire

Rolling sprite

Basé sur l'article publié dans Quasar CPC numéro 8, Demomaking, par SNN.

Pour faciliter la compréhension de l'effet il serait de bon ton d'ajouter des captures d'écrans (en gif-anim ?) de l'effet issu des 3 sources citées ci-dessous.

Je suis la rolling coccinelle ! Cet effet a été rendu célèbre par The Demo dans deux parties : la Megalomaniak de Digit et la Phoenix Part de Longhost. Il s'agit en fait d'un sprite qui s'enroule et se tortille à l'écran. Techniquement, il peut être réalisé de diverses manières aussi bien en soft qu'en hard (notamment à l'aide de la rupture ligne-à-ligne).

Je vous propose ici d'en étudier une version 100% soft codée par OffseT pour la part de Quasar CPC 31) qui contenait la rubrique “Perfectionnement à l'Assembleur”. Le source dérivé de cette implémentation du Rolling Sprite se trouve ci-dessous et nous allons donc étudier pas à pas comment cela fonctionne.

Les initialisations

Tout d'abord, on sauve la pile (1). Anodin, certes, mais indispensable puisque nous allons nous en servir par la suite comme pointeur de mot2) sachant qu'un mot pointera sur une adresse écran calculée dans la partie (2) du programme. Pour cela, on prend les adresses Y dans ”TableY”, soit en &4300 et les X en &5000 dans ”TableX”.

Les données sont fournies par le programme BASIC à exécuter au préalable. La dernière valeur fournie par le BASIC sera suivie par &FF, dans chaque table, pour indiquer à l'assembleur la fin de la table. Le petit programme BASIC poke également un sprite tout bidon en &4000 juste pour tester le programme ; c'est toujours plus agréable que d'avoir une infâme bouillie d'octets à l'écran.

Le calcul de l'adresse en Y est on ne peut plus simple : on prend la coordonnée Y dans les bras velus de l'accu (0 correspond au haut de l'écran), on transfère tout dans B, on fait une boucle qui descend d'autant de lignes que B en contient par des CALL BC26 sur HL3). Le tout est sauvé dans HL.

Puis, pour X, on charge A avec le contenu de la ”TableX”, on transporte le tout dans C. On annule la valeur de B, et on fait ADD HL,BC (3) ; c'est-à-dire qu'on ajoute A à HL, quoi. On décale donc notre adresse écran vers la droite après être descendu. Paf ! On a notre adresse dans HL. On la sauve grâce à la pile par un PUSH HL. La pile décrémente alors de 2 octets. Ainsi de suite, en ayant pris soin de décaler nos pointeurs (INC DE et une mini-automodif' pour HL, très facile à comprendre). Quand c'est fini, on remet tout en ordre dont le pointeur de HL (au cas où on voudrait relancer le pré-calcul) (4).

Je rappelle qu'il faut, pendant toute la manœuvre, supprimer les interruptions (par un DI) car elles utilisent SP elles aussi ! Mais il faut aussi faire attention à ne pas oublier le EI final.

Le programme principal

Satanés rolling dragons ! Je ne vous ferai pas l'affront de détailler l'attente du signal VBL (ok, je le fais : on attend que le bit 0 du port B du PPI, donc en &F5xx soit à 0 pour lancer la suite du programme) ou le test clavier qui suit le schéma expliqué ici. Le label ”Offset” (mégalo !) est, tout comme la saucisse, la clé du mystère.

Bon, pour commencer, on charge avec la pile la dernière valeur précalculée (qui se trouve donc être la première, magique non ?). Ensuite, HL reçoit dans la tronche les valeurs que la pile récupère (toujours mot par mot, 2 octets par 2 octets). Si le poids fort de cette adresse écran est nul (H=0), alors on lance le plan de secours qui fait boucler : ”Init04” (5). Celui-ci remet la pile sur le début de la table et lit presto une nouvelle valeur (si on avait gardé la dernière, les restarts en auraient pris plein la poire !). Puis, vient, dans tous les cas, l'affichage d'une ligne du sprite, avec autant de LDD que le sprite contient d'octets de large (ce sont les 4 petites lignes au tout début du programme qui s'occupe de poker le bon nombre de LDD ici).

Arrêtons-nous sur l'utilité du label ”Init042”. Supposons que notre sprite fasse 20 lignes de haut et qu'une fois arrivé à la dixième, nous sommes à la fin de la table ! Diable ! Que faire ? Eh bien, en bon stratège qu'il est, Offset remet la pile sur le droit chemin et, tout comme ”Init04”, lit derechef une valeur correcte. Quand on a tout affiché, on rend la main au programme principal qui va lancer le test clavier. C'est fini.

Petite indication tout de même quant au ”BC26” : modifiez la valeur de ”LargeurEcran” pour faire fonctionner cette routine en overscan (LargeurEcran=2*valeur du registre 1 du CRTC).

Afin d'éviter de tagger votre écran avec une infâme bouillie, pensez également à laisser une ligne vide au début de votre sprite afin que celle-ci efface automatiquement la dernière ligne affichée à la frame précédente.

Le mot de la fin

Bon, à présent j'ai deux choses à dire : la première c'est que tout ce que j'ai dit, je ne l'ai pas pris d'une quelconque anti-sèche qu'aurait pu me donner Offset : j'ai dû me taper de comprendre ce programme et de vous le pré-digérer. La deuxième, c'est que j'avais prévu un tout petit texte. Je me suis fait remballer par Offset, gêné, au téléphone qui m'a dit : “On a rien compris.” Résultat : je me retape tout ça, dans le noir, pendant que mes parents pensent que je travaille. Merci Offset.

Ceci dit, ce programme est génial, tapez-le, profitez-en, n'abusez pas dans la taille des sprites et remerciez-moi. Bien fait pour Offset si mon texte est trop long, ça lui fera les pieds.

Listings

Génération des tables et du sprite

Télécharger le programme BASIC.

10 ' Calcul des tables 
20 ' 
30 DEG 
40 DEFINT a-z 
50 SYMBOL AFTER 256 
60 MEMORY &3FFF 
70 MODE 2 
80 ' 
90 ' En Y 
100 ' 
110 adr=&4800 
120 FOR x=0 TO 359 
130 POKE adr+x,80*(COS(2*x)+1) 
140 PLOT x,10 
150 NEXT 
160 POKE adr+x,255 
170 ' 
180 ' En X 
190 ' 
200 adr=&5000 
210 FOR x=0 TO 359 
220 POKE adr+x,5*(COS(x*2)+SIN(x)+2) 
230 PLOT x,20 
240 NEXT 
250 POKE adr+x,255 
260 ' 
270 ' Création d'un sprite bidon 
280 ' 
290 MODE 2 
300 PRINT"------------------------------" 
310 PRINT"* << PETIT SPRITE DE TEST >> *" 
320 PRINT"* >> TEST DE SPRITE PETIT << *" 
330 PRINT"------------------------------" 
340 adr=&4000 
350 FOR y=0 TO 31 
360 ecran=&C000+&800*(y MOD 8)+80*(y\8) 
370 FOR x=0 TO 29 
380 POKE adr,PEEK(ecran+x) 
390 adr=adr+1 
400 POKE ecran+x,255 
410 NEXT x 
420 NEXT y

Routine assembleur

Télécharger le listing au format Maxam 1.5

;	"Rolling Sprite"
;
; Par OffseT 1993 / Quasar CPC 3
; Adapté par SNN pour Quasar CPC 8
 
	Org &9000
	Nolist
	Limit &a000
 
LargeurEcran	Equ &50
 
TableX		Equ &5000	; Table Ox
TableY		Equ &4800	; Table Oy
TableAdr	Equ &8000	; Adresses
Sprite		Equ &4000	; Sprite
 
Largeur		Equ 30		; Largeur
Hauteur		Equ 32 		; Hauteur
 
Taille		Equ largeur*hauteur
OffAdr		Equ taille+sprite-1
 
;
; Initialisation
;
 
; Pokage des LDD
 
	ld hl,pokeldd
	ld de,pokeldd+2
	ld bc,2*largeur-2
	ldir
 
; Génération de la table d'adresses
 
	di
	ld (pile),sp	; (1)
	ld sp,tableadr
	ld hl,0
	push hl
	ld de,tabley	; (2)
LoopT40	ld hl,&c000+largeur+10 
 	ld a,(de)
	or a
	jp z,saute
	cp 255
	jp z,nextt4
	ld b,a
LoopT4	push bc
	call bc26
	pop bc
	djnz loopt4
Saute	ld a,(tablex)
	push bc
	ld c,a
	ld b,0
	add hl,bc	; (3)
	pop bc
	push hl
	ld hl,(saute+1)
	inc hl
	ld (saute+1),hl
	inc de
	jp loopt40
 
NextT4	ld (start),sp
	ld sp,(pile)
 
	ld hl,tablex	; (4)
	ld (saute+1),hl
	ld hl,(start)
	ld (posit4),hl
	ei
 
;
; Programme principal
;
Prog	ld b,&f5
Synchro	in a,(c)
	rra
	jr nc,synchro
 
	call offset
 
; Test clavier
 
	di
	ld bc,&f40e
	out (c),c
	ld bc,&f6c0
	out (c),c
	xor a
	out (c),a
	ld bc,&f792
	out (c),c
	ld bc,&f645
	out (c),c
	ld b,&f4
	in a,(c)
	ld bc,&f782
	out (c),c
	ld bc,&f600
	out (c),c
	ei
 
	rla
	jp c,prog
 
; Exit
 
	ret
 
; Affichage du Rolling Sprite
 
Init04	ld sp,(start)	; (5)
	pop hl
	jp return1
 
Init042	ld sp,(start)
	pop hl
	jp return2
 
Offset	di
	ld (pile),sp
	ld sp,(posit4)
	pop hl
	ld a,h
	or l
	jr z,init04
Return1	ld (posit4),sp
	ld de,offadr
	ld b,hauteur
Loop1	ex de,hl
PokeLDD	ldd
	ds 2*largeur-2
	ex de,hl
	pop hl
	ld a,h
	or l
	jr z,init042
Return2	djnz loop1
	ld sp,(pile)
	ei
	ret
 
BC26	ld a,h
	add a,8
	ld h,a
	ret nc
	ld bc,&c000+largeurecran
	add hl,bc
	ret
 
;
; Data
;
 
Posit4	dw 0
Start	dw 0
Pile	dw 0
1) ce numéro de Quasar CPC était un discmag et non un fanzine papier comme tous les suivants
2) word en english, soit, je le rappelle, 2 octets, un de poids faible, l'autre de poids fort ; le résultat est une adresse écran où afficher une ligne du sprite… par des LDD, voir plus loin… compris ?
3) NDOffseT : oui c'est moche, on pourrait faire un calcul direct… mais en même temps c'est juste pour pré-calculer des adresses !