Sviluppare un gioco per Game Boy
by ProGM
Tutorial dedicato a Mercury, Impaled Janus e Guardian of Irael
Introduzione:
Fin da quando ero un ragazzetto piccolo e stupido ho sempre sognato di creare un gioco per quella incredibile console che è il Game Boy, e se siete della mia generazione la cosa sarà capitata anche a voi. Oggi è possibile ?O?!
Purtroppo "possibile" non è sinonimo di "facilmente accessibile". Per inoltrarsi nello sviluppo c'è bisogno necessariamente di avere più di qualche fondamento di programmazione (anche se cercherò di preparare del codice prefatto, in modo che anche i non-addetti-ai-lavori possano divertirsi a creare qualcosa di proprio).
Esistono principalmente due modi per sviluppare un gioco per Game Boy. Il primo è (ahaha) rimboccarsi le maniche, studiarsi il funzionamento completo dell'hardware di questa fantastica macchina e iniziare a sviluppare in assembler (ovvero linguaggio macchina). I vantaggi si hanno alla lunga per leggerezza del codice e miglior controllo di ogni componente. Gli svantaggi sono la difficoltà e l'enorme dispendio di tempo per avere qualcosa di pratico.
Il secondo metodo, che è quello che cercherò di spiegarvi, utilizza un'implementazione di C per gameboy sviluppato da due pazzoidi, tale GBDK: http://gbdk.sourceforge.net/
Questo interessantissimo progetto, ormai morto dal 2001, fortunatamente non è ancora stato inghiottito dall'oblio della rete, come invece (purtroppo) la maggior parte della documentazione e dei tutorial.
è possibile scaricarne la versione per windows e linux, ottimamente funzionante, della penultima versione rilasciata, nonchè i source dell'ultima versione, rilasciata nel 2002.
Informazioni generali e completamente inutili:
Giusto per introdurre il tutto, inizierò con le solite nozioni inutili, ma che tornano sempre comode. Il gameboy è una console rilasciata per la prima volta nel 1989 in giappone. Ne uscirono poi una serie di nuove versioni, di cui l'ultima è il game boy color, nel 1998 (il gameboy advance è da considerarsi una console del tutto diversa). GBDK consente di sviluppare giochi per tutte le versioni di gameboy, fino a gameboy color. Io, per puro attaccamento alle tradizioni, mi focalizzerò principalmente sulla primissima versione, nonostante abbia tantissime limitazioni.
Tutte le versioni uscite sono pressoche indifferenti a livello di processore (il famosissimo z80), ma differiscono per caratteristiche secondarie (quantità di memoria, tipo di display, palette di colore, funzionalità aggiuntive, ecc...)
Requisiti del tutorial
Conoscenza, anche di base, della sintassi del C. Anche non del C, ma per lo meno un po' di scioltezza mentale nell'approcciarsi alla logica "informatica".
Ora metà delle persone che stanno leggendo si prenderanno un colpo e chiuderanno il topic. In realtà per tutti coloro che non sanno un tubo di programmazione, ma sono molto motivati a provare, consiglio di provare comunque a seguire e contattarmi per vari dubbi ^_^. Cercherò di essere il più chiaro possibile. ><
Parte 1: Installazione
Difficoltà: bassa (dipende molto dal Sistema Operativo)
Per windows:
http://sourceforge.n...k-win32/2.95-3/
A questo indirizzo trovate tutto ciò che vi serve per iniziare. L'installazione va fatta manualmente... ovvero, dovete estrarre il file (procedura davvero complicatissima) in una cartella a vostra scelta (che sia definitiva, consigliato C:\Programmi\gbdk).
All'interno della cartella troverete una serie di cartelle. In mezzo all'inutilissima documentazione (mai vista una documentazione tanto approssimativa e scritta da cani), troverete una cartella chiamata "bin". Qui c'è quello che vi serve per iniziare, ovvero il fantasmagorico compilatore!
Iddo funziona perfettamente su windows XP 32 bit, ma non ho provato né su vista, né su seven 64bit. Nel caso più tardi spiegherò come compilare i source, nel caso qualcosa non funzioni.
Per facilitarvi la vita ora dovrete fare una complicatissima operazione che potrebbe corrompere in modo terrificante la vita ?O?. Scherzavo.
Aprite il pannello di controllo (se avete vista o seven cliccate IMMEDIATAMENTE su "passa a visualizzazione classica" ?_?), clickate su "Sistema". Vi si aprirà una finestra con varie schede. Clickate su Avanzate, infine su "variabili d'ambiente". Cercate la parola PATH e clickate su cambia. Ora, stando molto attenti a NON ELIMINARE NESSUNA INFORMAZIONE, scrivete all'inizio della stringa che vi appare il seguente testo:
C:\Programmi\gbdk\bin;
Fate tanti begli ok e la procedura è conclusa. Per verificare che sia tutto andato a meraviglia fate start -> esegui e digitate cmd. Vi si aprirà la console di winzozz. digitate ora lcc. Se vi appare una sorta di guida va tutto bene, se vi dà qualche errore va tutto male XD. A fine procedura consiglio di procurarsi un editor di testo che colori la sintassi. Tradotto, un programmino che vi consenta di scrivere i programmi in C senza che vi si incrocino gli occhi. Consiglio notepad++, notepad2, SciTE, o simili, ce ne sono a migliaia.
GNU/Linux:
Voi linuxari avete un vantaggio: sapete già tutto. Quindi non vi spiegherò la procedura, è sempre la solita. O vi scaricate i file già compilati, che tanto non funzioneranno mai, oppure scaricate il tarball e digitate, come se fosse la vostra bibbia:
tar -xf gbdk-xxxx.tar.gz cd gbdk make make install
Fine. XD
N.B. l'ultima versione rilasciata contiene degli errori di sintassi. E' consigliabile scaricare la penultima rilasciata.
Mac Os
Per Mac non esistono release precomplilate... o meglio, non esistevano finchè non l'ho compilata io:
http://www.rpgmaker....oflame/gbdk.zip
Renderlo funzionante è stata veramente un'impresa. ._____. purtroppo rispiegarvi i passaggi richiederebbe una guida a parte (ci ho perso 4 giorni).
E' compilato per mac os x 10.6.6, dovrebbe, e ripeto, dovrebbe funzionare anche su release precedenti, purchè non troppo vecchie.
Auguri.
Per gli sfigati di windows a 64bit a cui non funziona nulla
Mwahuhahuha a voi tocca installarvi cygwin, mi dispiace per voi. ?_?
http://www.cygwin.com/
cygwin è una piaga: non è altro che una console alternativa a quella di windows che imita un ambiente GNU/linux, così da compilare i source. Armatevi di coraggio e pazienza perchè sarà lunga. Seguite l'installazione normalmente. Tutto sembrerà normale finchè non vi chiederà, in inglese, che pacchetti desiderate installare.
I pacchetti sono la chiave per far funzionare o meno la compilazione. Il punto è che non si capisce mai cos'è che si è scordati di installare.
So di per certo che vanno installati:
gcc, cc, g++, flex, bison, tar.
Per il resto... non ne ho idea. Per trovare questi fantomatici pacchetti servitevi del riquadro cerca in alto.
A fine installazione, che prenderà dalle 6 alle 30 ore a seconda della vostra connessione, vi sarà possibile iniziare a fare qualche prova.
All'interno della cartella di cygwin sono presenti miliardi di cartelle, ma l'unica di nostro interesse è la cartella Home. Al suo interno troverete una cartella col nome del vostro utente. Là dentro andrà copiato il tutto.
Il cosidetto tutto sono i seguenti file:
http://sourceforge.n...tar.gz/download
http://sourceforge.n...ar.bz2/download
copiate i file nella cartella indicata, quindi avviate cygwin (dovrebbe avervi creato una icona sul desktop).
Ora digitate:
tar -xf maccer-0.25.tar.gz cd maccer ./configure make make install
Dopo ogni "a capo" fate una preghierina alla madonna.
Quando ha finito digitate:
tar -xf maccer-0.25.tar.gz cd maccer make make install
Anche qui accendere un cero in genere aiuta. Se tutto è andato a buon fine non apparirà alcun messaggio del tipo:
make[2] error: qualcosa
Se appare, consideratevi spacciati. XD
Meglio, contattatemi XD.
Per verificare che tutto vada bene digitate lcc.
Fine ^_^
Parte 2: Un po' di teoria
Difficoltà: media
Prima di iniziare a mettere mano sul codice, ho bisogno di spiegarvi alcuni concetti che, a chi sa già programmare, saranno abbastanza chiari, ma che sono molto utili per chi è la prima volta che si avvicina a questo mondo.
Prima di tutto: una regola d'oro per chi programma per Gameboy.
Tenete sempre ben chiaro in mente che non avete a che fare con un pc di ultima generazione con prestazioni stratosferiche, ma con un processore che probabilmente ai giorni d'oggi sarebbe obsoleto persino per un tostapane.
Avete spazio, memoria e velocità estremamente limitati, tutto ciò che non spiego qui o che vi dico che non si può fare è al 99% per limiti tecnici intrinsechi al gameboy.
Tipi di dati
Per chi non è avvezzo alla programmazione questa parola potrà risultare già preoccupante. In realtà significa soltanto, come dice il nome, che tipo di informazione si sta memorizzando in un dato momento.
Vi faccio un esempio scemo. Voi siete a letto e non riuscite ad addormentarvi. Così iniziate a contare le pecorelle. 1, 2, 3, 4... che tipo di dato state trattando? Beh, un numero!
Altro esempio. State pensando a qual è l'iniziale del vostro nome. Che tipo di dato è? un carattere!
Bene, dopo questa premessa idiota, traduciamo questo concetto in un calcolatore. Ricordate sempre che qualsiasi apparecchio elettronico lavora SOLO ed ESCLUSIVAMENTE con numeri. L'unica cosa che differenzia un numero da un altro sono le sue dimensioni e la valenza logica che gli viene attribuita.
Ad esempio, io con un numero posso rappresentare un numero, e fin qui niente di originale. Iniziamo un po' a spaziare. Se io volessi rappresentare una lettera, come potrei fare? Ad esempio potrei, in ordine, associare ogni lettera ad un numero, ovvero 0 alla lettera "a", 1 alla b, 2, alla c, e così via.
Se invece volessi rappresentare un'immagine come farei? Potrei associare ogni numero ad un colore, e iniziare a scrivere, in ordine dall'alto in basso, i colori presenti nell'immagine. Così via possiamo rappresentare praticamente ogni cosa.
Il punto è che ogni numero ha un "peso" diverso all'interno di un computer, in termini di memoria occupata. Se nei nostri pc moderni questo problema può essere considerato secondario (lo dico ora e lo nego tra 5 secondi), in un almanacco di quinta categoria quale è il gameboy questo problema diventa fondamentale.
Come sapete il computer lavora a bit, ovvero 0 e 1. Una sequenza di questi 0 e 1, con una certa combinazione, genera un numero, tutto questo è detto codifica binaria.
Se io avessi a disposizione per ogni informazione non più di 8 bit consecutivi, quante combinazioni di 1 e 0 potrei avere? Non state a scervellarvi, la soluzione è semplicemente 2 elevato alla 8 (che non a caso fa 256).
Ecco, quindi se noi avessimo 1 byte (8 bit) di memoria potremmo rappresentare 256 numeri, ad esempio da 0 a 255. Oppure, a nostra scelta, da -128 a + 127, se ci interessano i numeri negativi. (o anche mille altri casi, ma questi sono quelli più usati). E con 16 bit invece? 2 alla 16 = 65536.
Ora, tornando al discorso di prima. Immaginiamo di dover scrivere un carattere, quanti byte (gruppi di 8 bit) potremmo usare per non sprecare spazio?
Beh... mettiamo che ci sono 25 lettere, 50 tra maiuscole e minuscole... aggiungiamoci qualche carattere speciale... salvo che non siamo giapponesi, dovremmo star dentro nelle 200 lettere. Eccoci la soluzione, 8 bit (1 byte) !
Ora vi svelerò un segreto: il processore del gameboy è guardacaso un processore a 8 bit, ovvero è molto molto molto efficiente nel trattare dati a 8 bit (non è proprio così, ma ve la butto lì). Dite che ce la facciamo a riassumere tutto ciò che ci serve in gruppi di numeri da 8 bit?
Io dico di sì ;3
Dal punto di vista un po' più pratico, il gameboy, nonostante possa usare fino a dati da 4 byte, usa al 99% dati a 1 byte (o meglio, 1 byte alla volta, non 1 byte per tutto). Ad esempio per rappresentare parole utilizza un byte a lettera. Per le immagini utilizza un byte per ogni quadretto dello schermo. Per i numeri si "accontenta" di 256 numeri, a scelta col segno (da -128 a +127) o senza segno (da 0 a 255).
Espanderò questo concetto, in modo un po' più approfondito più avanti, quando servirà in pratica. Per ora mi basta che abbiate capito questo.
ROM
Letteralmente Read Only Memory, in realtà è il nome dato a dei particolari file eseguibili .gb, che possono essere eseguiti solo sul gameboy o eventuali emulatori. Il nome ROM deriva dal fatto che in genere questi file venivano salvati appunto su supporti ROM, ovvero memorie magnetiche sola lettura.
Compilazione
Mi dispiace per i pochi credenti, ma le macchine non sanno leggere. Quando voi scrivete un programma, state usando un linguaggio simbolico, che voi credete che i computer riescano a comprendere. In realtà non è così, di mezzo c'è un processo chiamato compilazione, che converte ciò che avete scritto (insieme di parole con vari significato), nel solito ammasso di bit, unica cosa comprensibile al processore.
Questa procedura è divisa in 3 fasi, ma a noi non ce ne frega nulla.
Quello che ci interessa è come fare a compilare.
Nei compilatori moderni non dovete fare gran che, basta pigiare un tasto.
lcc, ovvero il compilatore per gameboy, invece, è molto old style e può essere utilizzato solo da linea di comando.
Non starò qui a dilungarmi troppo.
Una volta che avrete pronto qualcosa da compilare, dovete salvare il file con l'estensione ".c", che serve a far capire che il linguaggio utilizzato è il C.
Per chi usa windows consiglio di fare così:
Aprite il blocco note e scrivete:
lcc -Wa-l -Wl-m -Wl-j -DUSE_SFR_FOR_REG -c -o test.o test.c lcc -Wa-l -Wl-m -Wl-j -DUSE_SFR_FOR_REG -o test.gb test.o pause
al posto di "test" metteteci il nome del file che avete salvato.
Ora salvate come make.bat nella cartella in cui avete messo il file .c
Se volete fare i coatti, nella cartella in cui c'è il file .c metteteci il famosissimo emulatore visual boy advance, quindi modificate il make.bat in questo modo:
lcc -Wa-l -Wl-m -Wl-j -DUSE_SFR_FOR_REG -c -o test.o test.c lcc -Wa-l -Wl-m -Wl-j -DUSE_SFR_FOR_REG -o test.gb test.o VisualBoyAdvance.exe test.gb
Doppioclickando su make.bat il file verrà compilato oppure verranno mostrati eventuali errori di compilazione. Nel caso ci sia VisuaBoyAdvance, partirà direttamente anche il test del gioco :3
Le basi del C
Il C è un linguaggio di programmazione studiato per essere di alto livello (ovvero comprensibile all'umana ragione), ma a stretto contatto con ciò che è il supporto hardware.
Quello che vi serve sapere di C è principalmente la sintassi, quindi dateci un'occhiata, fate un paio di hello world e prendeteci la mano. Mi basta anche solo che sappiate fare programmini solo testuali (stile esercizietti scemi in pascal delle superiori), in quanto, per ciò che ci serve qui, non abbiamo bisogno dei puntatori (o meglio, non direttamente), neanche di allocazione dinamica della memoria. Dovete principalmente sapere cosa significa dichiarazione di variabili, sapere cos'è un ciclo, if, insomma, le basi.
Interrupt
Gli interrupt sono dei "messaggini" che vengono inviati al processore quando si verifica un certo evento. Un interrupt, ad esempio, è l'impulso elettrico che si innesca quando premiamo un tasto del gameboy. Un altro interrupt si verifica ogni tempo di refresh (ogni volta che viene ridisegnato lo schermo), e così via. L'interrupt "avvisa" il processore di questo evento e si chiama così perchè appunto il processore interrompe ciò che sta facendo per dar retta a questo interrupt.
Ciclo grafico
Importantissimo è il concetto di ciclo grafico. Qualsiasi applicazione che contenga grafica ne ha bisogno.
Un ciclo grafico è un processo che si scatena ogni tot di tempo (in genere abbastanza breve) che si occupa di ridisegnare lo schermo. Il gameboy, durante questo processo, ovvero finchè non finisce di ridisegnare lo schermo, non può in nessun modo (se non usando uno speciale interrupt) modificare il contenuto della memoria video, ovvero quella da cui legge le informazioni riguardanti la grafica. Tradotto, se volete modificare qualcosa sullo schermo dovete sincronizzarvi con questi processi, in modo da modificare la grafica solo nel momento del refresh.
Numeri esadecimali
Come sapete i calcolatori lavorano a bit (l'avrò ripetuto cento volte). Di tanto in tanto ci capiterà di dover inviare o dover salvare delle informazioni di basso livello (ovvero degli insiemi di bit). Le sequenze di bit, come vi ho spiegato, al 90% saranno da 8 bit. Scrivere però una sequenza di 8 uni e zeri è parecchio scomodo. Esiste un modo per scrivere una sequenza binaria in modo abbastanza comodo, ovvero utilizzando la codifica esadecimale. Essa è un modo di rappresentare i numeri in cui il numero di simboli a disposizione non sono 2 come nel binario, e neanche 10 come nel decimale (da 0 a 9), ma sono 16 ( ovvero i numeri da 0 a 9 più le lettere da A ad F).
Vi faccio un esempio stupido: Vogliamo scrivere il numero 23 in esadecimale? Nel decimale semplicemente contiamo fino a 23, associando ad ogni numero un simbolo ( zero = 0, uno = 1, due = 2) finchù non arriviamo al nove (nove = 9). Giunti qui abbiamo finito i simboli e passiamo alla cifra successiva (dieci = 10). Nell'esadecimale invece, avendo a disposizione ancora simboli (ovvero le lettere da A ad F) si continua: dieci = A, undici = B, dodici = C, 13 = D, 14 = E, 15 = F, fine simboli XD. A questo punto si fa come nel decimale, ovvero sedici = 10, diciassette = 11, ecc...
ventitre sarà quindi 17 in esadecimale e 23 in decimale.
Fine spiegazione teorica. Ora procuratevi una calcolatrice diverse da quella che trovate nelle merendine kinder e vedrete che avrà integrato un bel convertitore da decimale a binario a esadecimale :3 fate un po' di prove e tenetevela a portata di mano ^_^.
Ultimo dettagli tecnico. In C i numeri esadecimali si rappresentano anteponendo al numero uno "0x".
Quindi, per scrivere in decimale il numero ventitre scriveremo 23, in esadecimale scriveremo 0x17.
Parte 3: Il nostro primo programmino-gioco
Difficoltà: facile
Ancor prima di iniziare a chiacchierare, vi mostro subito un bel hello world, ovvero il programma di test di qualsiasi linguaggio di programmazione.
#include <gb/gb.h> #include <stdio.h> void main() { printf("Hello World"); }
Attenzione: Il C da usare è l' ansi-C standard, niente modernità. Tradotto, la dichiarazione delle variabili va fatta all'inizio, non nel mezzo del codice, non si può dichiarare gli indici nei for, alla fine di ogni "case" ci va un "break;".
Provate a compilare questo programmino e godetevi il risultato sull'emulatore. Siete soddisfatti?
Questo potrebbe farvi credere che è tutto rose e fiori, in realtà non è proprio così.
Iniziamo spiegando le prime due righe. I due include impongono al compilatore di leggere il contenuto di gb.h e stdio.h, entrambi presenti nella cartella include di GBDK (attenzione, l'stdio non è quello standard del vosto sistema operativo, ma quello di gbdk, per questo funziona XD).
La funzione printf ha lo stesso funzionamento del c standard, solo che è riadattata per funzionare su gameboy.
Proviamo qualcosa di più complesso:
#include <gb/gb.h> #include <stdio.h> void main() { INT8 a=3, b=1; while(b < a) { b = b*2; } printf("a = %d, b=%d", a, b); }
Come vedete nulla di strano, classico C. INT8 sta per numero intero (ovvero con segno) da 8 bit (da -128 a +127).
Se invece avessimo voluto un numero senza segno avremmo dovuto usare un UINT8. (U sta per Unsigned)
Consiglio di impratichirvi un po', se siete poco esperti col C, facendo dei semplici programmini simili.
In questa pagina ci sono alcuni consigli per quanto riguarda le prestazioni. Utilizzare certi comandi è più efficace di altri. (per esempio è sempre meglio fare confronti di == o != che non di < o >. Inoltre è sempre meglio usare tipi di dati Unsigned (senza segno) piuttosto che signed.
http://gbdk.sourcefo...guidelines.html
Parte 4: I banchi ROM
Difficoltà: medio
Questa parte del corso è molto importante, cercate di comprenderla al meglio, poichè è fondamentale per poter creare un gioco degno di questo nome e non incepparsi al primo problema (come io ho fatto all'inizio).
Il gameboy è fatto, come sapete, per girare su una cartuccia, anche detta ROM (read only memory). Per motivi intrinsechi al funzionamento del nostro GBDK, esso si comporta come se i banchi di memoria fossero suddivisi in piccoli sottobanchi da 8 kb l'uno. Infatti, non appena il codice che abbiamo creato "sfora" questo 8 kb, il gioco non verrà più compilato e ci verrà restituito un errore del tipo "ERROR: pointer overflow (XXXX > 8000)".
Ora vi insegnerò come fare in modo di espandere la ROM in dimensioni, per far stare tutto quello che vi serve, e come gestire il tutto a livello di codice.
Prima di tutto, sappiate che la cosa che in generale occupa di più, a livello di spazio, sono le "risorse", ovvero grafiche e musiche. Esse, come già vi ho anticipato, verranno salvate all'interno del GB come enormi sequenze di bit, espresse a livello di codice tramite array di numero esadecimali. Non preoccupatevi ora di come tradurremo un'immagine o una musica in una sequenza di bit comprensibile al GB, lo spiegherò successivamente.
Il primo consiglio che vi do è di essere ordinati, ovvero utilizzate un banco di memoria separato per ogni "parte" del vostro gioco. Ad esempio, utilizzate un banco per la grafica dei chara, uno per le musiche, uno per le mappe e così via.
Per una sorta di bug del compilatore GBDK, purtroppo salvare grandi sequenze di bit come array in C non funziona come dovrebbe. Quello che succede è che il compilatore "spreca" un sacco di spazio e vi ritrovate a finire molto rapidamente lo spazio disponibile. Per risolvere questo problema saremo costretti a mettere qualche piccola parte del codice in Assembler, ovvero nel linguaggio macchina, più vicino possibile ai bit.
Non preoccupatevi, non è nulla di sovrumano.
Prima di tutto, sappiate che per ogni blocco di memoria dovrete creare un nuovo file.
Per esempio, vogliamo creare una nuova variabile che conterrà ipoteticamente un chara (è solo un esempio). Prima di tutto, prima del main() del nostro programma, scriviamo questa cosa:
extern unsigned char nomevariabile[];
Questo serve a dichiarare la nostra variabile come array di caratteri (ovvero numeri a 8 bit). La parola Extern fa capire che questa variabile non sta all'interno del codice, ma in un banco esterno.
Ora creiamo un nuovo file di testo e chiamiamolo, ad esempio, chara.s .
L'estensione ".s" sta per "file in assembler". Apriamolo e dichiariamo la variabile in assembler. Per farlo dobbiamo scrivere due semplici righe:
.globl _nomevariabile .dw _nomevariabile
come noterete davanti al nome della variabile ho aggiunto un "_". Questa è una regola: Se vogliamo far interagire C e assembler correttamente, dobbiamo ricordare che se una variabile in C si chiama "ciao" in assembler si chiamerà "_ciao". Facile, no?
Ora assegnamo alla variabile il contenuto:
_nomevariabile: .db 0x03, 0xFF, 0xF2
Questo codice equivale, in C, a questo:
unsigned char nomevariabile[] = { 0x03, 0xFF, 0xF2 }
Alcune regole importanti:
1) ogni 16 numeri esadecimali dovete andare a capo e scrivere di nuovo .db, quindi continuare ad elencare i numeri.
2) ogni quando andate a capo omettete la virgola
eccovi un esempio un po' più serio:
_variabile: .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
Abbiamo fatto!
Ora andiamo all'inizio del file, prima di globl e dw e aggiungiamo una riga:
.area _CODE_X
Questo codice serve a decidere quale banco di memoria occupare. Al posto di X metteteci un numero da 1 a (banchi disponibili - 1).
Ora vi spiego come compilare correttamente il banco di memoria.
Prima di tutto aprite il file makefile.bat, che utilizzate per compilare e scrivete nel seguente modo:
lcc -v -Wa-l -Wf-bo1 -DUSE_SFR_FOR_REG -c -o chara.o chara.s lcc -Wa-l -Wl-m -Wl-j -DUSE_SFR_FOR_REG -c -o test.o test.c lcc -Wa-l -Wl-m -Wl-j -Wl-yt1 -Wl-yo4 -DUSE_SFR_FOR_REG -o test.gb test.o chara.o pause
Ora vi spiego tutto:
La prima riga serve a compilare il primo banco di memoria nel file chara.o. Il parametro -Wf-bo1 serve a specificare quale banco occupare, tra quelli disponibili. Al posto di 1 metteteci il numero che volete.
Il secondo, come sapete, serve a compilare il codice vero e proprio del gioco nel file test.o .
Il terzo serve a collegare (link) i due file che avete creato dentro al file test.gb, ovvero la rom definitiva. Come noterete sono apparsi due nuovi parametri all'ultima riga, rispetto a quelli a cui siamo abituati, ovvero -Wl-yt1 e -Wl-yo4. Il primo serve a indicare che desideriamo utilizzare banchi esterni, il secondo specifica quanti ne vogliamo. Nel mio caso ne ho scelti 4. Attenzione a una cosa. Il primo banco è "sottinteso", ed è quello che contiene il codice che voi usate.
Se una variabile sta nel secondo banco, dovrete scrivere nel file .s _CODE_1 e come parametro -Wf-bo1!!!
Non confondetevi ^^!
Ora, ultimissima nozione: il passaggio da un blocco di memoria all'altro non è assolutamente automatico, ma va specificato manualmente all'interno del codice.
Per farlo eccovi un piccolo esempio. Mettiamo di voler accedere (senza un motivo preciso) al secondo valore dell'array che abbiamo creato (nomevariabile) e scriverlo su schermo come numero:
#include <gb/gb.h> #include <stdio.h> extern unsigned char nomevariabile[]; void main() { SWITCH_ROM_MBC1(1); printf("Il secondo valore di nomevariabile è %d", nomevariabile[1]); SWITCH_ROM_MBC1(0); }
Il comando SWITCH_ROM_MBC1 serve appunto a "switchare" a un banco di memoria indicato tra le parentesi.
Come vedete ho switchato al secondo banco (ovvero quello con id 1, ricordatelo sempre) e a quel punto ho potuto accedere a nomevariabile ^_^.
Se non fate lo switch il risultato di quel printf risulta essere un valore qualsiasi, preso "a caso" (non proprio, ma non importa) dalla rom.
Parte 5: Fondamenti di grafica #1
Difficoltà: medio-alto
Il gameboy, così come molte vecchie console, al fine di ottimizzare e sfruttare al meglio i pochi bit che ha a disposizione di memoria, sfrutta un metodo di disegno detto "a tile", ovvero, quando deve disegnare una certa immagine su schermo, è necessario che venga scomposta in gruppi di quadratini di dimensione fissa (nel caso del gameboy 8x8 pixel). Spero per voi che sappiate cos'è un pixel, se no filate a leggere su wiki, che è fondamentale!!
Vi ricordo inoltre che il gameboy ha a disposizione un fantastico schermo che consente massimo 4 colori diversi (tonalità di grigio).
Fossero solo queste le limitazioni!
Andiamo con ordine. Il gameboy offre a noi programmatori 3 livelli su cui è possibile disegnare (un po' come quelli di rpgmaker, nelle mappe).
Il livello bkg, ovvero background, che serve generalmente per creare le mappe. Questo è il livello più basso e viene coperto dai due successivi
Il livello window, un livello senza trasparenze che sta al di sopra del livello background, utilizzato generalmente per creare finestre dei messaggi o hud di vario tipo (rigorosamente rettangolose). Questi livelli funzionano a tileset (un po' come RPG Maker): Si carica in memoria un tileset divisi in quadretti di 8x8 pixel, successivamente si dovrà "mapparli", ovvero selezionare i vari quadrettini e decidere in che ordine e come appaiono su schermo. Insomma uguale ad rpgmaker.
Infine abbiamo un terzo livello, il livello sprite, utilizzato per i personaggi sulla mappa, che sfrutta le trasparenze ma che ha un colore in meno degli altri 2 livelli (uno dei 4 colori disponibili, il più chiaro, indica il colore trasparente).
Anche qui si ha a disposizione un tileset, in quanto per disegnare chara di dimensioni superiori a 8x8 pixel si dovranno combinare (ovvero affiancare) tanti sprite diversi, componendo il chara un po' come un puzzle.
Ecco le limitazioni a cui andiamo incontro quando tentiamo di sfruttare ciò che il gameboy ci offre:
- Numero di sprite disegnabili in contemporanea: 40, non uno di più
- Numero di tile differenti disegnabili contemporaneamente dal livello background: 256
- 2 modalità per disegnare gli sprite: 8x8 pixel oppure 8x16 pixel (spiegherò meglio più avanti)
- Il livello window e il livello background condividono lo stesso "tileset", ovvero più tile usate per la window, meno ne avrete per il background.
Vi faccio notare un dettaglio: lo schermo del gameboy ha una risoluzione di 160x144 pixel. Se vi fate due conti scoprirete che non esiste alcun metodo che consente di disegnare tramite i tile a disposizione (ovvero il livello background + il livello sprite) una immagine che ricopra interamente lo schermo (a meno che non ripetiate più volte lo stesso quadretto in più punti dello schermo.
Ovviamente un metodo esiste, ma lo spiegherò più avanti (sfrutta un "trucchetto").
Ora il dubbio esistenziale: come si crea grafica per gameboy?
Beh, prima di tutto armatevi di un programma di grafica, di una paletta da 4 colori in scala di grigi e di tanta pazienza. Preparatevi un tileset per il background e uno per gli sprite.
Eccovi un template (in alto a sinistra c'è una paletta di esempio ^_^):
Sappiate che, e l'ho giò anticipato, il gameboy non legge nessun formato immagine attualmente conosciuto. Sapete cosa legge?
Insiemi di bit. XD
Per i più curiosi...
rappresenta i tile utilizzando una coppia di tile per ogni riga da 8x1 pixel. 8 righe (ovvero 16 byte) danno un tile.
le righe funzionano così:
il primo byte indica in ordine sequenziale se il bit è acceso o spento (acceso = nero, spento = bianco).
per esempio:
10010100 indicherà che il primo, il quarto e il sesto pixel dovranno essere neri, gli altri bianchi.
Il secondo byte è complementare al primo, e serve a generare la completezza dei 4 colori.
Per esempio: primo byte 10010100, secondo byte 00011111. quando al primo bit del primo byte c'è un 1 e anche al secondo byte, primo bit c'è un uno indica nero puro. 1-0 indica grigio chiaro, 0-1 indica grigio scuro, 0-0 indica bianco puro.
Dopo aver letto la spiegazione vi chiederete: io devo seriamente mettermi a scrivere quella robaccia ?O?!?
No no no, ovvio ^_^ esistono programmini che convertono la grafica da bitmap a quel patacco incomprensibile. ^^
Non trovandone uno che non fosse link scaduto o un pre-alpha-instable-dement-devasting, ne ho sviluppato uno molto semplice io:
GB Tile Editor
(Abbiate pazienza, è ancora sotto testing pesante)
Scaricatelo e avviatelo (è un file .jar, richiede che abbiate installato java).
Vedrete subito l'interfaccia molto semplice, in cui è possibile scegliere due modalità: sprite mode e background mode.
Come è presagibile Sprite mode serve a generare uno sprite, background mode serve a generare e a mappare un background.
Per provarne il funzionamento create una semplice immagine a 4 colori seguendo il template e apritela con quel programma. Se l'immagine non era già a 4 colori, tenterà una conversione a forza bruta (non sempre l'effetto è dei migliori). Ora passate al background mode e impostate la dimensione della mappa a 20x18 (ovvero una schermata di gameboy).
Potete selezionare parti dell'immagine in alto e disegnarla nella schermata sotto, così come fate con rpgmaker (anche se con meno funzioni). Quando avete finito ci si appresta a salvare.
Per esportare l'immagine clickate su file -> salva.
Ora potete importare l'immagine nel vostro gioco. A questo punto dovremo ritirare fuori dal cappello le nozioni apprese riguardo ai banchi di memoria. Il programmino vi avrà salvato un file .h, che conterrà:
1) la dichiarazione delle variabili in C (extern unsigned blabla) che dovrete mettere poco prima del main del programma principale
2) dei DEFINE, che vi servirà più avanti, per impostare le dimensioni del chara e che dovrete copincollare all'inizio del codice C
3) tutta la dichiarazione delle variabili in assembler, che dovrete copincollare in un .s e compilare nel banco di memoria opportuno, come spiegato nella precedente lezione.
Ora vi mostrerò come disegnare una parte dell'immagine che avete convertito sul livello background(l'immagine che vi ho fatto creare è di 128x128. Potete anche caricare un'immagine da 160x144, vi ricordo che il gameboy regge massimo 256 tile diversi su mappa, contro i 360 che servirebbero per riempire interamente lo schermo).
Prima di tutto, nel file .h vi ho fatto notare che ci sono due variabili, una chiamata QUALCOSA_tiledata[] e una QUALCOSA_tilemap[]. La prima è semplicemente un elenco di numeri che indicano l'immagine in sè (colori, dove stanno i pixel, ecc). La seconda, ovvero il tilemap indica come deve posizionare i tile definiti nella prima variabile sullo schermo. In pratica è come se tiledata fosse il tileset, e tilemap la mappa già mappata. Per indicare i tile immaginate che siano numerati da 0 a 255, e nel tilemap fossero indicati in ordine dal tile in alto a sinistra andando verso destra, andando a capo a fine schermo. In pratica, se volessimo che i primi 5 quadretti dello schermo fossero identici, nel tilemap ci sarebbe scritto 0x00, 0x00, 0x00, 0x00, 0x00. La rappresentazione esadecimale è equivalente a quella decimale, quindi avrei potuto scrivere 0, 0, 0, 0, 0. (semplicemente è più comodo l'esadecimale perchè tutti i numeri hanno lo stesso numero di cifre, quindi esce tutto allineato)
Non state troppo a sbatterci la testa, tanto il programma che ho creato genera tutto in automatico.
Ricordate una cosa:
Se create più mappe con lo stesso tileset, copiate una sola volta la variabile _tiledata, in quanto altrimenti se no avreste tanti inutili doppioni.
Eccovi il codice completo per mostrare l'immagine sul livello background, che poi commenterò a dovere.
#include <gb/gb.h> #include <stdio.h> extern unsigned char ?QUALCOSA_tiledata[]; extern unsigned char QUALCOSA_tilemap[]; void main() { DISPLAY_OFF; HIDE_SPRITES; HIDE_WIN; HIDE_BKG; disable_interrupts(); SWITCH_ROM_MBC1(1); set_bkg_data(0, 255, QUALCOSA_tiledata); set_bkg_tiles (0, 0, 20, 18, QUALCOSA_tilemap); SHOW_BKG; DISPLAY_ON; enable_interrupts(); while(1) { wait_vbl_done(); } }
AAAAllora, partiamo da una premessa. Per iniziare dobbiamo far spegnere lo schermo al gameboy, per evitare che, durante il caricamento della grafica, si vedano schifezze varie sullo schermo. Questo si fa col comando DISPLAY_OFF;
HIDE_SPRITES, WIN e BKG rispettivamente disattivano i 3 livelli sprite, windows e bkg, che ci serve perchè per il momento ci serve solo il bkg (ovvero background). disable_interrupts serve a disattivare gli interrupts, appunto, ovvero imporre al gameboy di sospendere temporaneamente l'invio degli interrupts che riguardano refresh schermo, tasti, ecc...
a questo punto arriva la parte interessante.
set_bkg_data(0, 255, QUALCOSA_tiledata); serve a caricare in memoria il nostro tileset. I primi due numeri servono rispettivamente a indicare da che tile iniziare a caricare la grafica (dal primo) e quanti tile caricare (il secondo). Non potete caricarne più di 255, ovviamente, per il motivo spiegato prima ^_^. QUALCOSA_tiledata è il nome del tileset, ovvero il nome della variabile che sta nel file .h, e dipende da come si chiamava il vostro file.
set_bkg_tiles (0, 0, 20, 18, QUALCOSA_tilemap); serve invece a caricare la mappa. I primi due numeri indicano la coordinata x e y in cui si vuole iniziare a disegnare i tile (mi raccomando, non su mappa, non stiamo disegnando ancora nulla, le coordinate in cui disegnare sul tileset!). I secondi 2 numeri indicano quanto grande è la mappa (io ho scelto 20*18 perchè voglio ricoprire interamente lo schermo).
Dopodichè mostriamo il livello bkg tramite il comando apposito e riaccendiamo lo schermo del gameboy, nonchè riattiviamo gli interrupts. Ecco fatto.
L'ultima parte di codice, ovvero il ciclo infinito, serve a "tenere viva" la rom. Se non lo facciamo il gameboy giungerebbe a fine programma e (credo) si spegnerebbe. In ogni caso non è molto importante per ora, ne tratterò meglio quando giungeremo al capitolo sugli interrupt.
Che dire, provate ;3.
Per quanto riguarda gli sprite la procedura è un po' diversa.
Al contrario che con le mappe, per gli sprite va prima di tutto fatta una scelta.
Il gameboy ha due modalità per disegnare gli sprite: 8x8 e 8x16.
Queste due modalità hanno vantaggi e svantaggi diversi, e va valutato di caso in caso quale dei due usare.
La modalità 8x8 disegna un tile da 8x8 per ogni sprite, la modalità 8x16 disegna due tile da 8x8 per ogni sprite.
Sì, ok, lo so, vi siete persi.
La differenza è principalmente questa:
voi avete una immagine di un chara di dimensioni 16x32 e volete disegnarlo su schermo. Potete farlo in due modi:
1) usate 8 sprite (dei 40 che potete mostrare in contemporanea) in modalità 8x8
2) usate 4 sprite in modalità 8x16
E qui vi chiederete: E perchè mai dovrei usare la modalità 8x8, se con la 8x16 risparmio sprite?
Semplice, quando attivate la modalità 8x16, tutti gli sprite saranno mostrati in quella modalità, non potete decidere quali sì e quali no. Inoltre utilizzare la modalità 8x16 impone, a meno di non voler sprecare tile spazio con margini enormi, che l'altezza dei chara sia multiplo di 16 pixel.
Nel programmino che vi ho fornito è possibile scegliere la modalità con cui salvare gli sprite.
Per gli sprite e per il loro utilizzo e movimento dedicherò una lezione a parte, quindi per il momento provate a mostrare uno sprite di prova, in questo modo:
-Aprite GB Tile Editor e caricate un'immagine di un chara da esattamente 8x16.
-Salvatene 2 copie, una in modalità 8x8 e una in 8x16
-Per la prima provate questo codice:
#include <gb/gb.h> #include <stdio.h> extern unsigned char NOMEFILE_tiledata[]; void main() { DISPLAY_OFF; SPRITES_8x8; HIDE_SPRITES; HIDE_WIN; HIDE_BKG; disable_interrupts(); SWITCH_ROM_MBC1(1); set_sprite_data(0, 2, NOMEFILE_tiledata); set_sprite_tile(0, 0); set_sprite_tile(1, 1); move_sprite(0, 8, 16); move_sprite(1, 8, 16+8); SHOW_SPRITES; enable_interrupts(); while(1) { wait_vbl_done(); } }
-Per la seconda provate invece questo:
#include <gb/gb.h> #include <stdio.h> extern unsigned char NOMEFILE_tiledata[]; void main() { DISPLAY_OFF; SPRITES_8x16; HIDE_SPRITES; HIDE_WIN; HIDE_BKG; disable_interrupts(); SWITCH_ROM_MBC1(1); set_sprite_data(0, 2, NOMEFILE_tiledata); set_sprite_tile(0, 0); move_sprite(0, 8, 16); SHOW_SPRITES; enable_interrupts(); while(1) { wait_vbl_done(); } }
Questa è la spiegazione, che serve se volete comprendere i meccanismi che ci stanno dietro:
Aaallora... Come al solito spegnamo schermo e nascondiamo tutto.
Il comando set_sprite_data(0, 2, NOMEFILE_tiledata) fa esattamente la stessa cosa che faceva quello sul background, ovvero disegna sul "tileset" degli sprite 2 tile (l'immagine infatti contiene 2 tile da 8x8).
Il primo e il secondo codice differiscono di due comandi. set_sprite_tile(0, 0) serve a disegnare su mappa, nello sprite numero 0, il primo dei due tile che abbiamo impostato prima.
Ovviamente in modalità 8x8 vanno disegnati 2 tile in 2 sprite diversi, mentre invece in 8x16 si usa un solo sprite per 2 tile. Il comando move_sprite serve solo a spostare il chara in una posizione che sia visibile (ovvero non fuori dallo schermo). Ne parlerò meglio più avanti.
Ma da tutto questo discorso, cosa ne voglio ricavare?
Sappiate che questa è solo teoria, in pratica per mostrare e gestire gli sprite preparerò del codice già fatto per semplificarvi la vita.
Quello che deve restare da questo piccolo esempio è che dovete fare una scelta:
Se usate la modalità sprite 8x8 si occupano molti più sprite a parità di dimensioni del chara che volete mostrare, ma non avete troppi problemi nel farlo, quindi in un gioco con sprite piccoli (8x8, ad esempio) questo metodo è indicato.
Il metodo 8x16 invece è indicato per chara grandi, ma impone che tutti gli sprite rispettino quelle proporzioni, e quindi crea qualche problema nel creare la grafica (anche perchè vi ricordo che il "tileset" degli sprite ha dimensione finita, ovvero 256 sprite!)
Parte 6: Fondamenti di grafica #2 (APA mode)
Difficoltà: facile
Nella scorsa lezione vi ho spiegato che, tramite sprite e background, non è possibile disegnare un'immagine che riempia completamente lo schermo, se non riciclando parti di immagini in più punti. In effetti tramite la normale gestione dei tile non è in alcun modo possibile risolvere questo problema (per lo meno su GameBoy classico, sul color si può), per questioni di limitatezza di memoria video.
Esiste però un metodo per imporre al gameboy di non lavorare a tile, ma a pixel (così come lavorano gli schermi moderni), ovvero in APA mode (all points accessible). (metodo inventato da Jeff Frohwein) Per i più curiosi:
Questo metodo sfrutta gli interrupt nel seguente modo. Carica l'immagine che volete disegnare nella memoria video fintanto che c'è spazio (imponendogli di considerare la parte dedicata agli sprite e quella dedicata al background come un blocco unico). Poi a metà del refresh, tramite un interrupt mandato al processore, carica la seconda parte dell'immagine nella memoria video. Questo molto sommariamente (non entro nei dettagli, non ci interessano).
Ora vi chiederete: come faccio a sfruttare questa fantastica feature?
Prima di tutto, vado a precisare: Per le parti di gioco in sè questo metodo è da evitare al 99% dei casi, in quanto è più lento del metodo a tile e soprattutto ha molta meno libertà.
Seconda cosa: Quando è attivo il metodo APA, è altamente sconsigliato usare il metodo a tile (vanno in conflitto e generano errori grafici).
A cosa ci serve questo APA mode, quindi? Beh, per tutte le parti che richiedono immagini statiche o in movimento semplice, per esempio schermate dei titoli, piccole sequenze introduttive, ecc ecc.
Eccovi un piccolo esempio su come implementare APA. Prima di tutto a inizio programma dobbiamo aggiungere un:
#include <gb/drawing.h>
Apriamo il GB tile editor e carichiamo l'immagine (da 160x144 pixel), quindi salviamola subito (in sprite mode, non ci serve la mappa, solo l'immagine).
Eccovi il codice completo che poi commenterò:
#include <gb/gb.h> #include <gb/drawing.h> #include <stdio.h> ?extern unsigned char title_tiledata[]; void main() { disable_interrupts(); DISPLAY_OFF; HIDE_SPRITES; HIDE_WIN; HIDE_BKG; SWITCH_ROM_MBC1(1); draw_image(title_tiledata); DISPLAY_ON; enable_interrupts(); while(1) { wait_vbl_done(); } }
Iniziamo dal principio: la parte iniziale è identica all'esempio della lezione precedente. Si disattivano gli interrupt e lo schermo, si nascondono sprite, finestre e background. La novità sta nel comando "draw_image(title_tiledata);", che semplicemente prende l'immagine dal file title.h e la disegna su schermo, senza se e senza ma.
Tutto così semplice? Ebbene sì, in un semplice comando abbiamo disegnato un'immagine a pieno schermo.
Purtroppo non tutto è rose e fiori.
Prima di tutto un piccolo dettaglio. Se volessimo mostrare del testo sull'immagine, tramite l'APA mode non possiamo più utilizzare il comando printf, ma dobbiamo sostituirlo con il suo rispettivo clone di questa modalità, ovvero gprintf. Eccovi un esempio:
#include <gb/gb.h> #include <gb/drawing.h> #include <stdio.h> #include "title.h" ? extern unsigned char title_tiledata[]; void main() { disable_interrupts(); DISPLAY_OFF; HIDE_SPRITES; HIDE_WIN; HIDE_BKG; draw_image(title_tiledata); gotogxy(5, 15); gprintf("Press Start"); DISPLAY_ON; enable_interrupts(); while(1) { wait_vbl_done(); } }
gotogxy semplicemente posiziona il testo in coordinate 5, 15 ^_^
La seconda magagna dell'APA mode: Una volta che utilizzate anche un solo comando in APA mode, se poi dovete tornare in modalità normale, dovrete riportare il povero gameboy nelle sue condizioni iniziali. Per farlo vi consiglio di creare una funzione come questa (non importa se non ne capite ora il funzionamento, fatto sta che riazzera il gameboy ^^):
void disable_APA() { for (i=0;i<255;i++) { remove_VBL(i); remove_LCD(i); } LCDC_REG = 0x07; mode(0xE2); }
Da richiamare quando vorrete tornare a utilizzare i tile.
Parte 7: Comporre musica 8-bit [IN SCRITTURA]
Difficoltà: medio
Prima di tutto, rifornitevi di due programmini:
1) http://openmpt.org/download è un programma che consente di comporre musica a canali limitati, esporta in un formato ".mod", leggibile da molte vecchie console arcade
2) http://members.fortu...emon26/LP1c.zip e http://members.fortu...od2lp1(dos).zip Questi due file permettono di sentire la musica composta su modplug tracker sul gameboy, tramite un convertitore.
Ok, prima di tutto installate modplug e avviatelo. Creiamo un nuovo file MOD (file->new->mod), clickiamo sulla scheda "general" e clickiamo su song proprieties. Impostiamo:
type: ProTracker MOD
channels: 4
Premiamo ok.
L'interfaccia è un tantino strana, non è proprio similissima ad un programma per comporre. Infatti questo programma non si comporta come guitar pro, finale o altri programmi simili, non mostra un pentagramma, ma delle cose chiamate "patterns" e "Samples". I Samples sono gli strumenti musicali, i pattern sono gli spartiti.
Di predefinito, come vedrete, è tutto vuoto: c'è un pattern vuoto e 32 samples vuoti.
La parte che a noi interessa maggiormente è il pattern.
Anche il gameboy si comporta esattamente in questo modo: lo spartito è suddiviso in pattern da 64 "spazietti" e 4 canali.
Alcune caratteristiche tecniche del GB:
Il gameboy ha, come saprete forse già, 4 canali, ma non sono tutti uguali. I primi due sono identici e possono riprodurre all'incirca qualsiasi suono consentito dall'8 bit. In genere si usano per suonare la melodia e l'accompagnamento.
Avere quattro canali non significa avere 4 strumenti, mi raccomando, significa semplicemente che potranno suonare in contemporanea soltanto 4 strumenti diversi, con solo una nota alla volta.
Il terzo canale è simile ai primi due, ma può suonare solo note "lunghe". Il quarto canale invece genera solo onde quadre, quindi suona solo "rumore", e viene usato per gli strumenti a percussione.
Alle note possono essere applicati molti effetti, i più usati sono alzare e abbassare il volume, il pan (spostare le note a destra e a sinistra), il "tronca note" e l'arpeggio, che simula un accordo suonando molto rapidamente 3 note in sequenza sullo stesso canale.
Ora, purtroppo noi avremo una ulteriore limitazione:
Non potremo creare i samples, ovvero gli strumenti, in quanto il programmino che permetteva di crearli è stato divorato dalla rete ?____?. Dovremo quindi arrangiarci con quelli che un certo Lemon ha preparato per noi ^^.
Inoltre non potremo applicare gli effetti di tronca nota e l'arpeggio, in quanto il convertitore da MOD a "formato per gameboy" non funziona se inseriamo altri effetti ??.
Tornando a modplug:
Esistono vari modi per creare canzoni. Il primo è, come ho fatto io per la musica di assassin's creed, trascrivere le note da qualche parte (a orecchio), ad esempio su guitar pro. A questo punto riscriverle sul programmino in questo modo:
Potete vedere che lo spartito è suddiviso in quattro colonne, una per canale. Le colonne hanno dei trattini, in ognuno di essi può essere inserita una nota.
Esistono due tipi di strumenti e a seconda del tipo le note vanno inserito in modo lievemente diverso. Esistono strumenti a supporto infinito e a supporto limitato. Le note a supporto limitato suonano una volta, emettono il loro suono e si stoppano. Quelle a supporto infinito suonano finchè non viene cambiata la nota, oppure non viene azzerato il volume. XD I primi sono ad esempio chitarrine, tastiere, i secondi sono violini, flauti, ecc...
Per inserire una nota doppioclickate su uno spazietto. Potrete decidere lo strumento, la nota da suonare (con la notazione americana) e nella seconda pagina gli effetti da applicare. Gli unici due effetti che ci interessano sono "Set Volume" e "Set Panning". Ogni spazietto vuoto equivale a una pausa per una nota a supporto finito, un "continua questa nota" per uno a supporto infinito.
[CONTINUERO']
Una volta finito fare file->compatibility export.