Scroller dans toutes les directions avec l'ASIC de la gamme PlusDans les pages sur le [scrolling horizontal],et le [scrolling vertical], j'ai pris le cas le plus simple en suivant le tableau, celui où on incrémenteet quand on déborde du compteur, on revient à zéro et on incrémente l'autre compteur. Pour aller en "marche arrière", on ne déborde pas dans le même sens donc lescomparaisons sont un peu moins intuitives et les réinitialisations de compteur ne se font pas à zéro mais aux maximums respectifs. Rien d'insurmontable ;) Pour commencer, on va se définir un écran purement carré. Il n'a que des avantages, c'est pour ça que vous le trouvez dans beaucoup de jeux/démos : - Largeur multiple de 256 donc facilité de calculs de position à l'écran - Tous les octets sont visibles ce qui -en cas de scrolling- est un cadeau pour savoir où écrire les nouvelles données (la ligne ou la colonne qui disparait, réapparait de l'autre côté) | Étapes de scrolling horizontal |
|---|
| position X en pixel mode 1 | scroll CPC | scroll CPC et registre 3 | scroll ASIC + SSR | adresse écran |
|---|
| 0 | CRTC Adr = #0000 | CRTC Adr = #0000 R3 = #8C | CRTC Adr = #0000 SSR = 0 | #C000 | | 1 | | | CRTC Adr = #0000 SSR = 2 | #C000 | | 2 | | | CRTC Adr = #0000 SSR = 4 | #C000 | | 3 | | | CRTC Adr = #0000 SSR = 6 | #C000 | | 4 | | CRTC Adr = #0000 R3 = #85 | CRTC Adr = #0000 SSR = 8 | #C001 | | 5 | | | CRTC Adr = #0000 SSR = 10 | #C001 | | 6 | | | CRTC Adr = #0000 SSR = 12 | #C001 | | 7 | | | CRTC Adr = #0000 SSR = 14 | #C001 | | 8 | CRTC Adr = #0001 | CRTC Adr = #0001 R3 = #8C | CRTC Adr = #0001 SSR = 0 | #C002 | | 9 | | | CRTC Adr = #0001 SSR = 2 | #C002 | | 10 | | | CRTC Adr = #0001 SSR = 4 | #C002 | | ... | ... | ... | ... | ... |
| Étapes de scrolling vertical |
|---|
| position Y | scroll CPC | scroll ASIC + SSR | adresse écran |
|---|
| 0 | CRTC Adr = #0000 | CRTC Adr = #0000 SSR = #00 | #C000 | | 1 | | CRTC Adr = #0000 SSR = #10 | #C800 | | 2 | | CRTC Adr = #0000 SSR = #20 | #D000 | | 3 | | CRTC Adr = #0000 SSR = #30 | #D800 | | 3 | | CRTC Adr = #0000 SSR = #40 | #E000 | | 5 | | CRTC Adr = #0000 SSR = #50 | #E800 | | 6 | | CRTC Adr = #0000 SSR = #60 | #F000 | | 7 | | CRTC Adr = #0000 SSR = #70 | #F800 | | 8 | CRTC Adr = largeur / 2 | CRTC Adr = largeur / 2 SSR = #00 | #C000 + largeur | | 9 | | CRTC Adr = largeur / 2 SSR = #10 | #C800 + largeur | | ... | ... | ... | ... |
Nul besoin d'avoir un tableau pour le multi-directionnel, il suffit de réaliser chaque direction l'une après l'autre et tout se passera bien. Pour illustrer notre programme du jour, j'ai converti quelques tuiles d'une planche en libre accès et créé une carte avec le logiciel [ Tiled ]. J'imagineque beaucoup d'entre vous le connaisse, c'est un logiciel gratuit, opensource et multi-plateforme. Il est assez simple d'importer des données, d'indiquer à l'éditeur quelle est la taille des tuiles etensuite de construire une carte avec ces tuiles. Bon, moi j'suis pas graphiste alors vous me pardonnerez le coup de truelle sur cette carte de démonstration ;) 

Les tuiles sont obtenues avec la commande suivante sur ce [fichier image] convgeneric.exe -m 0 -g -tiles -size 8x16 mapMulti.pngOn récupère la palette, la petite tileMap (qui s'assemble en 4k) et le petit binaire des graphismes (3K). Seulement 7K de données pour cette map, il faut dire qu'il y avait peu de sprites sur cette planche (64) et jene me suis servi que de 47 d'entre eux! Pour réaliser notre scrolling, nous allons avoir besoin :- d'une position X et d'une position Y (une position en tuiles ou une position absolue. On peut aussi prendre l'offset direct dans la table ) - d'une sous-position X et d'une sous position Y (à l'intérieur des tuiles, donc limité par la taille d'une tuile) - d'une adresse écran correspondant au coin supérieur gauche - de l'adresse du CRTC correspondant à ce coin - des décalages verticaux et horizontaux dans des compteurs séparés qu'on recombinera avant d'envoyer à l'ASICOn va se créer une structure pour gérer notre double buffer facilement, contenant toutes ces informations struct multi mapOffset defw HSSR defb ; 0-12 VSSR defb ; #00-#70 colonne defb ; 0-3 dans la tuile ligne defb ; 0-60 par pas de 4 dans la tuile adresseDebut defw crtc12 defb ; cache des bits de bank crtcHL defw ; adresse CRTC endstruct ; et on se déclare deux structures pour un double buffer struct multi ecran1 struct multi ecran2On va déjà commencer par limiter notre scrolling aux contours de la map. C'est assez simple, il faut compter les tuiles et connaitre le nombre de tuiles présentes sur un écran :Notre écran est carré pour 128 pixels sur 256, nos tuiles font 8 pixels sur 16 lignes. Un écran contient 16 tuiles sur 16 tuiles. Notre tileMap fait 64 tuiles sur 64 donc quand on arrive à la tuile 48, que ce soit en hauteur ou en largeur, on arrête de scroller respectivement en bas et à droite. Pour l'autre côté, nous avons besoin d'une double comparaison, nous arrêtons de scroller en haut et à gauche quand : - L'index de tuile vaut zéro - Le décalage vaut zéro Pour terminer avec les chiffres, notre tileMap correspond à 16 écrans (4 en largeur, 4 en hauteur). On attaque les routines? On commence par une routine qui initialise l'écran et les structures avec nos tiles (déjà vue dans [l'article sur les tiles]) InitEcran ; IX = structure buffer ; A = poids fort de la page vidéo ld hl,tileMap ld (ix+multi.mapOffset),hl ld hl,0 ld (ix+multi.HSSR),h ld (ix+multi.VSSR),h ld (ix+multi.colonne),h ld (ix+multi.ligne),h ld (ix+multi.crtcHL),hl ld h,a : ld (ix+multi.adresseDebut),hl rrca : rrca : ld (ix+multi.crtc12),a; Afficher les tuiles sur tout l'écran ld de,(ix+multi.adresseDebut) ld ix,tileMap ; on n'utilise plus la structure à partir de là ld yh,16 ; 16 tuiles en hauteur afficheLigne ld yl,16 ; nombre de tuiles en largeur push de ; sauvegarder l'adresse de début de ligne de l'écran afficheTuile push de ; sauvegarder l'adresse du début de la tuile à l'écran ld h,(ix+0) : inc ix : ld l,0 : srl hl : srl hl ; x 256 / 4 c'est la taille de nos tuiles (64 octets) ld bc,tuiles : add hl,bc ; on a l'adresse de la tile ld a,16 afficheLigneTuile push de : ldi 4 : pop de ld bc,#800 : ex hl,de : add hl,bc : jr nc,.novf : ld bc,64-#4000 : add hl,bc : .novf ex hl,de dec a : jr nz,afficheLigneTuile pop hl : ld bc,4 : add hl,bc : ex hl,de ; se placer juste à côté de la tuile précédente dec yl : jr nz,afficheTuile ld bc,48 : add ix,bc ; revenir à la ligne de tuile (64-16 dans notre cas) pop hl : ld bc,128 : add hl,bc : ex hl,de ; se placer sous les tuiles à gauche dec yh : jr nz,afficheLigne retQu'on se déplace horizontalement ou verticalement, on va avoir besoin à chaque fois d'aller récupérer l'adresse de la tuile courante, d'incrémenterson déplacement dans la tileMap. En gérant tous les cas de clipping, on va partir parfois d'une tile entière, d'une ligne de tuile, d'unecolonne de tuile et même en plein milieu d'une tuile. C'est le bon moment pour préparer quelques macros qui vont nous 'éclaircir' le code d'affichage sans qu'on passe notre temps à relire et reliredes calculs adresse qui se ressemblent comme deux gouttes d'eau. Une des sources d'erreur en programmation est de recopier un peu troprapidement des morceaux de code pour les utiliser ailleurs. D'ailleurs, devinez qui s'est planté en écrivant cet article et aurait dû les écrire de suite? ^_^ La routine qui calcule l'index primaire peut ensuite avancer (ou pas) dans la table, avec un incrément simple ou une valeur plus grandepour parcourir la table en Y. MACRO calculeAdresseTuile increment exx : ld a,(hl) ; index de la tile dans A if {increment}==0 : elseif {increment}==1 : inc hl : else : add hl,bc : endif exx ; index de la tile dans A / HL'=tileMap ld hl,tuiles : ld b,a : ld c,0 : srl bc : srl bc : add hl,bc ; HL=adresse du début de la tuile MEND MACRO calculeAdresseTuileLigne increment calculeAdresseTuile {increment} ld a,(ix+multi.ligne) : add l : ld l,a ; HL=adresse du début de la tuile à la bonne ligne MEND MACRO calculeAdresseTuileColonne increment calculeAdresseTuile {increment} ld a,(ix+multi.colonne) : add l : ld l,a ; HL=adresse du début de la tuile à la bonne colonne MEND MACRO calculeAdresseTuileLigneColonne increment calculeAdresseTuile {increment} ld a,(ix+multi.ligne) : add (ix+multi.colonne) : add l : ld l,a ; HL=adresse du début de la tuile à la bonne ligne ET bonne colonne MENDJ'allais oublier, on modifie l'écran, on modifie nos compteurs, mais on n'a toujours pas envoyé au hardware!UpdateHardware RMR2 ASICON ld a,(ix+multi.HSSR) : or (ix+multi.VSSR) : or #80 : ld (#6804),a ld hl,(ix+multi.crtcHL) : ld a,h : and 3 : ld h,a : ld a,(ix+multi.crtc12) : or h : ld bc,#BC00+12 : out (c),c : inc b : out (c),a inc c : dec b : out (c),c : inc b : out (c),l RMR2 ASICOFF retOn va écrire un premier programme qui n'affiche QUE notre écran (besoin des fichiers mapMulti.bin et mapMulti.tilemap) BUILDSNA : BANKSET 0 SNASET CPC_TYPE,4 ; modèle 6128+ conseillé ORG #100 : RUN #100 ;*** RMR2 tags + macro *** ASICOFF equ 0 : ROM0000 equ 0 : ROM4000 equ %01000 : ROM8000 equ %10000 : ASICON equ %11000ROM0 equ 0 : ROM1 equ 1 : ROM2 equ 2 : ROM3 equ 3 : ROM4 equ 4 : ROM5 equ 5 : ROM6 equ 6 : ROM7 equ 7 macro RMR2 tags ld a,{tags}+%10100000 ld b,#7F out (c),a mendstruct multi mapOffset defw HSSR defb ; 0-12 VSSR defb ; #00-#70 colonne defb ; 0-3 dans la tuile ligne defb ; 0-60 par pas de 4 dans la tuile adresseDebut defw crtc12 defb ; cache des bits de bank crtcHL defw ; adresse CRTC endstruct ld bc,#7F00+%10001100+%00 : out (c),c ; MODE 0 call UnlockAsic : RMR2 ASICON ld hl,palettePlus : ld de,#6400 : ld bc,32 : ldir : ld hl,#000 : ld (#6420),hl ; +border noir ld bc,#BC00+1 : out (c),c : ld bc,#BD00+32 : out (c),c ; Notre map fait 128 pixels de large, adaptez selon VOS besoins ld bc,#BC00+2 : out (c),c : ld bc,#BD00+42 : out (c),c ; Centrer l'écran en X ld bc,#BC00+6 : out (c),c : ld bc,#BD00+32 : out (c),c ; Hauteur de l'écran visible en lignes de caractères ld bc,#BC00+7 : out (c),c : ld bc,#BD00+34 : out (c),c ; Centrer l'écran en Y ld bc,#BC00+12 : out (c),c : ld bc,#BD30 : out (c),c ; adresse par défaut ld bc,#BC00+13 : out (c),c : ld bc,#BD00 : out (c),c ld ix,ecran1 : ld a,#C0 : call InitEcran jr $ ;--------------------------------------------------------------------- InitEcran ; IX = structure buffer ; A = poids fort de la page vidéo ld hl,tileMap ld (ix+multi.mapOffset),hl ld hl,0 ld (ix+multi.HSSR),h ld (ix+multi.VSSR),h ld (ix+multi.colonne),h ld (ix+multi.ligne),h ld (ix+multi.crtcHL),hl ld h,a : ld (ix+multi.adresseDebut),hl rrca : rrca : ld (ix+multi.crtc12),a ; Afficher les tuiles sur tout l'écran ld de,(ix+multi.adresseDebut) ld ix,tileMap ; on n'utilise plus la structure à partir de là ld yh,16 ; 16 tuiles en hauteur afficheLigne ld yl,16 ; nombre de tuiles en largeur push de ; sauvegarder l'adresse de début de ligne de l'écran afficheTuile push de ; sauvegarder l'adresse du début de la tuile à l'écran ld h,(ix+0) : inc ix : ld l,0 : srl hl : srl hl ; x 256 / 4 c'est la taille de nos tuiles (64 octets) ld bc,tuiles : add hl,bc ; on a l'adresse de la tile ld a,16 afficheLigneTuile push de : ldi 4 : pop de ld bc,#800 : ex hl,de : add hl,bc : jr nc,.novf : ld bc,64-#4000 : add hl,bc : .novf ex hl,de dec a : jr nz,afficheLigneTuile pop hl : ld bc,4 : add hl,bc : ex hl,de ; se placer juste à côté de la tuile précédente dec yl : jr nz,afficheTuile ld bc,48 : add ix,bc ; revenir à la ligne de tuile (64-16 dans notre cas) pop hl : ld bc,128 : add hl,bc : ex hl,de ; se placer sous les tuiles à gauche dec yh : jr nz,afficheLigne ret ;--------------------------------------------------------------------- NextLineHL ld a,h : add 8 : ld h,a : and #38 : ret nz ; tester le changement de bloc sur n'importe quelle page ld a,64 : add l : ld l,a : ld a,#C0 : adc h : ld h,a : res 3,h : ret ;--------------------------------------------------------------------- UnlockAsic ld bc,#BCFF out (c),c out (c),0 ld hl,%1001000011101010 .loop out (c),c ld a,h:rlca:ld h,l:ld l,a srl c:res 3,c and #88 or c ld c,a cp #4D jr nz,.loop ld a,#CD out (c),a : out (c),a ret WaitVBL ld b,#F5 : noVBL in a,(c) : rra : jr c,noVBL VBL in a,(c) : rra : jr nc,VBL : ret paletteplus: defw #323,#646,#5B3,#967,#A57,#B95,#6E4,#9B7,#C89,#ABA,#CE2,#DB8,#DB9,#EC6,#EC9,#EED tuiles incbin 'mapMulti.bin' align 2 : tileMap include 'mapMulti.tilemap' ; et on se déclare deux structures pour un double buffer struct multi ecran1 struct multi ecran2Nos tuiles s'affichent, c'est un bon début, et il est essentiel!  La préparation étant faite, on va pouvoir ajouter nos directions dans la [ deuxième partie ]
Roudoudou CPCrulez[Content Management System] v8.732-desktop/c Page créée en 046 millisecondes et consultée 44 foisL'Amstrad CPC est une machine 8 bits à base d'un Z80 à 4MHz. Le premier de la gamme fut le CPC 464 en 1984, équipé d'un lecteur de cassettes intégré il se plaçait en concurrent du Commodore C64 beaucoup plus compliqué à utiliser et plus cher. Ce fut un réel succès et sorti cette même années le CPC 664 équipé d'un lecteur de disquettes trois pouces intégré. Sa vie fut de courte durée puisqu'en 1985 il fut remplacé par le CPC 6128 qui était plus compact, plus soigné et surtout qui avait 128Ko de RAM au lieu de 64Ko. |
|