Come si è potuto constatare dalla puntata precedente, lavorare sui background è davvero semplice. La libreria libnds ci mette a disposizione un numero incredibile di funzioni e procedure che coprono qualsiasi aspetto relativo alla gestione dei layer, dal movimento allo zoom, dalla priorità alle rotazioni. Ed è appunto di rotazioni e zoom che ci occuperemo nel prossimo esempio.
Per prima cosa occorre cambiare la modalità dello schermo, perché il Mode 0 non gestisce rotazioni e zoom sui background. Potremmo usare, per esempio, il Mode 5, che permette di gestire due background di tipo text e due di tipo extended rotation. Vediamo subito il codice di esempio, che non varia poi molto da quanto già visto:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
program Mode5_a; {$L build/wood.o} {$mode objfpc} uses ctypes, nds9; const woodTilesLen = 16448; woodMapLen = 2048; woodPalLen = 512; var woodTiles: array [0..0] of cuint; cvar; external; woodMap: array [0..0] of cushort; cvar; external; woodPal: array [0..0] of cushort; cvar; external; var bg3: integer; x: integer = 256; zoomOut: boolean = true; const angle = 64; begin videoSetMode(MODE_5_2D); vramSetBankA(VRAM_A_MAIN_BG); bg3 := bgInit(3, BgType_ExRotation, BgSize_ER_256x256, 0, 1); bgSetScroll(bg3, 128, 128); bgSetCenter(bg3, 128, 128); dmaCopy(@woodTiles, bgGetGfxPtr(bg3), woodTilesLen); dmaCopy(@woodMap, bgGetMapPtr(bg3), woodMapLen); dmaCopy(@woodPal, BG_PALETTE, woodPalLen); while true do begin if x = 128 then zoomOut := true; if x = 512 then zoomOut := false; if zoomOut then inc(x) else dec(x); bgSetScale(bg3, x, x); bgRotate(bg3, angle); swiWaitForVBlank(); bgUpdate(); end; end. |
Come al solito, scorriamo insieme le righe di codice più significative.
[32]: Dopo le solite impostazioni e dopo avere attivato il Mode 5, impostiamo il background 3 che ruoteremo e scaleremo.
[34-35]: Centriamo il background nello schermo e impostiamo il punto di rotazione in modo tale che sia al centro dell'immagine (provate a giocare con i valori per vedere come varia la rotazione).
[51]: Effettuiamo lo zoom, utilizzando lo stesso valore di x, in modo tale da avere uno zoom proporzionato. Cambiando i due valori è possibile ottenere anche un effetto stretching sul background. La funzione che si occupa dello zoom è
bgSetScale(id: cint; sx, sy: cint32);
che richiede come parametri il background da zoomare (id) e il livello di zoom orizzontale e verticale (sx, sy). Un valore pari a 256 indica che non c'è nessuno zoom; un valore inferiore ingrandisce il background (128 indica un fattore di zoom di 2X) e un valore superiore rimpicciolisce il background (512 indica un fattore di zoom di 1/2X). Da notare che nei background (extended) rotation la tilemap non viene ripetuta, come accade invece nei background di tipo text.
[52]: La rotazione di un background può essere effettuata in due modi, utilizzando una delle funzioni
bgRotate(id, angle: cint); bgSetRotate(id, angle: cint);
Queste due funzioni non sono equivalenti. Infatti, in bgRotate la rotazione è cumulativa, quindi è sufficiente passare un valore costante come parametro e l'angolo di rotazione viene incrementato di quel valore ad ogni frame. bgSetRotate non è cumulativa, quindi ad ogni frame il valore dell'angolo viene riportato a 0.
Esiste poi una funzione che si occupa di ruotare e scalare un background in un sol colpo:
bgSetRotateScale(id, angle: cint; sx, sy: cint32);
Il suo uso è del tutto simile alle due funzioni appena viste. Ricordate però che la rotazione non è cumulativa e si comporta come bgSetRotate.
L'esempio seguente dovrebbe chiarire ogni dubbio in proposito:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
program Mode5_b; {$L build/wood.o} {$mode objfpc} uses ctypes, nds9; const woodTilesLen = 16448; woodMapLen = 2048; woodPalLen = 512; var woodTiles: array [0..0] of cuint; cvar; external; woodMap: array [0..0] of cushort; cvar; external; woodPal: array [0..0] of cushort; cvar; external; var bg3: integer; x: integer = 256; zoomOut: boolean = true; angle: integer = 0; begin videoSetMode(MODE_5_2D); vramSetBankA(VRAM_A_MAIN_BG); bg3 := bgInit(3, BgType_ExRotation, BgSize_ER_256x256, 0, 1); bgSetScroll(bg3, 128, 128); bgSetCenter(bg3, 128, 128); dmaCopy(@woodTiles, bgGetGfxPtr(bg3), woodTilesLen); dmaCopy(@woodMap, bgGetMapPtr(bg3), woodMapLen); dmaCopy(@woodPal, BG_PALETTE, woodPalLen); while true do begin inc(angle, 64); if x = 128 then zoomOut := true; if x = 512 then zoomOut := false; if zoomOut then inc(x) else dec(x); bgSetRotateScale(bg3, angle, x, x); swiWaitForVBlank(); bgUpdate(); end; end. |
L'unica differenza con quanto visto in precedenza è la chiamata alla funzione bgSetRotateScale.
Per commenti e chiarimenti: http://www.lazaruspascal.it/index.php?topic=78.0