Scripting Engineering Tutorial
Realizzare un gioco no è certo un'impresa facile, specie se lo si debba realizzare da soli. Chir ci è venuto incontro realizzando il MAGE/IJ, un motore scritto in Java che ci consente di realizzare delle avventure grafiche in stile "Vecchia Lucas" (Monkey Island 1 e 2, Indiana Jones 3 e 4, Loom...) senza la necessità di conoscere il JAVA.
Basta conoscere il linguaggio del MAGE, che è un linguaggio molto semplice ed intuitivo...
... ma questo non significa che realizzare un gioco sia diventata una cosa facile! :-)
Ci sono tanti problemi e tanti ostacoli, per cui bisogna cercare di ottimizzare al meglio (come fanno i veri ingegneri) le nostre possibilità, il nostro tempo e la nostra... mente!
Personalmente non mi ritengo certo un guru della programmazione, ma ho abbastanza esperienza per darvi qualche suggerimento utile. :-) Cominciamo!
Una nota x chi si senta programmatore: leggete anche le prime "lezioni", potreste trovare errori o suggerirmi strade migliori... e fare un bel ripasso ;-)
Innanzitutto cominciamo dalle cose fondamentali: la storia e la sceneggiatura!
Non basta avere in mente una bozza di storia, occorre anche avere una sceneggiatura su cui basarsi. La cosa ideale sarebbe avere la sceneggiatura completa, con tanto di dialoghi, descrizioni e quant'altro, ma possiamo anche utilizzare una sceneggiatura meno dettagliata... ma pur sempre completa! Personalmente, questo è quanto io abbia usato per l'introduzione delle Andy's New Adventures, e che vi riporterò qui come esempio.
Come al solito Andy capita nel posto sbagliato nel momento sbagliato. In questo caso è un castello. Viene incaricato di salvare la principessa che è stata rapita da un drago e se riuscirà a sconfiggerlo potrà avere sia il suo tesoro che la mano della principessa.
La principessa è in realtà orrenda, ma ad Andy passano una foto bellissima per cui prende e parte alla ventura pur essendo un fifone.
E questa è la nostra storia (limitata all'introduzione). Adesso vediamo la sceneggiatura corrispondente:
Intro: interno di una taverna, voce che spiega come Andy si trovi lì perchè "ad un goccetto di quello buono non si dice mai di no", c'è quindi Andy ubriaco che sogna di essere milionario. Ci sono un par di altri avventori, forse anche il barista. La locanda è sita nel villaggio esterno al castello.
Entra una guardia che informa della terribile disgrazia: il drago ha rapito la figlia del re; tutti si fan prendere dallo spavento, Andy è ubriaco e non sente nemmeno che stia succedendo. La guardia vuole un volontario per salvare la figlia del re, Andy blatera le sue frasi senza senso e viene acclamato come volontario da parte di tutti...
-stacco-
Esterno del castello, è passato un po' di tempo (per far svanire i fumi dell'alcool...)
-stacco-
Interno della sala del trono (o anchye: colloquio con il re) Andy ed il re parlano, Andy fa tutto l'obbediente e servile (si vede che la guardia lo ha anche pestato un pochino...) ed il re gli racconta la storia: un drago malvagio ha rapito la sua bella figliola, solo Andy si è offerto di salvarla, se ci riuscirà riceverà sia un milione di pezzi d'oro che la mano della bellissima principessa... e gli da' una foto
-stacco-
Foto di una stangona (o attrice reale universalmente arrapante o disegno provocante con donna che sorride e fa l'occhiolino... in classico stile Disney: "Provochiamo ma tanto è un personaggio che non apparirà mai disegnato così") in dissolvenza sullo schermo, un par di frasi, un GULP (arrapato) da parte di Andy
-stacco-
Di nuovo colloquio, Andy accetta, il re ringrazia
-stacco-
Esterno del castello, dice che ora si sia fatta (per parlare col re) (MA SI PUO' ANCHE TOGLIERE)
-stacco-
Interno del castello, stanza a caso (corridoio con la guardia che lo ha "arruolato"), Andy commenta sulla missione e parte all'avventura... esce dalla porta ed il gioco inizia in modalità mapview
Come potete notare, la sceneggiatura è mooooolto più dettagliata della storia: è più che naturale! Nella sceneggiatura dovrebbero esserci la descrizione delle stanze, la descrizione dei personaggi, i dialoghi e quant'altro: la sceneggiatura è anche lo strumento tramite il quale il grafico/disegnatore riesce a tradurre i pensieri dello sceneggiatore. Occorre quindi dargli quante più informazioni possibili! Questo non significa che bisogni dire proprio tutto tutto... ad esempio nella sceneggiatura ho citato una locanda, degli avventori ed una guardia. Non avendo particolari esigenze, la libertà lasciata al grafico (Riktik) è stata praticamente completa, ed anzi l'immagine della taverna che mi ha fornito è l'esatto opposto di quella che io avevo in mente! Questo non è un problema in questo caso, ma potrebbe esserlo in altre situazioni. Del resto il disegnatore (guardatevi anche il tutorial di Riktik), sfrutta abbondantemente la sceneggiatura per creare i paesaggi: se in una stanza l'azione si svolge vicino ad un caminetto, un disegnatore furbo (come insegna Riktik) lo utilizzerà come cuore dell'immagine... ma sto cominciando a divagare un po' troppo... la cosa fondamentale è quindi: prima di cominciare a scrivere il codice del gioco, bisogna avere la sceneggiatura dello stesso, il più dettagliata possibile.
Notate poi come all'interno della sceneggiatura siano state isolate le scene una ad una, indicandone la cronologia e gli avvenimenti. E' come se steste raccontando un film indicando tutto quel che accada... ;-)
Vediamo cosa riesco adesso a combinare con questa sceneggiatura...
Il primo "comandamento" è quindi di avere una sceneggiatura, e noi l'abbiamo. Cosa facciamo? Cominciamo a tradurla in codice? No.
Prima di cominciare a scrivere il codice bisogna fare delle altre cose, che però esulano da questo tutorial. Le elenco semplicemente:
- Decidere la risoluzione da utilizzare per il gioco: a questo scopo date un'occhiata alla mia guida al MAGE in cui spiego come calcolare le proporzioni e le dimensioni dell'area di gioco.
- Trovare un disegnatore o mettersi di buona lena su matita, china, scanner, programma di grafica (vedi il tutorial di Riktik).
Una volta che avremo tutto... possiamo cominciare.
Un mio professore di qualche corso di ingegneria del software una volta disse: Ogni volta che riscrivi un pezzo di codice, la probabilità che tu faccia un errore aumenta. Ha ragione: è vero!
Se devo compiere una operazione e mi invento un algoritmo (per chi non lo sapesse: algoritmo significa una sequenza ordinata di passi da compiere per svolgere una qualche cosa) buono e che funziona... lo metto nel codice. Poi mi serve di nuovo. Lo riscrivo.
Ma no, io sono moderno! Se è vero che scrivendolo due volte è facile che sbagli... faccio copia e incolla e risolvo il problema.
Facendo copia e incolla si risolve il problema della molteplice riscrittura del codice, è vero... ma non si scappa da un altro problema: stanotte ho trovato una soluzione migliore, un algoritmo più rapido, più bello, più facilmente modificabile in futuro. Che faccio? Devo cambiare ogni file in cui ho scritto quel pezzo di codice! Con il rischio di dimenticarne qualcuno...
La soluzione è quella di scrivere l'algoritmo UNA SOLA VOLTA, e poi "citarlo" dovunque serva: quando volessi modificarlo, basterà cambiare un solo file, e la cosa si rifletterà dappertutto. Inoltre abbiamo file di dimensioni più piccole e più leggibili. :)
Il MAGE ci da' questa possibilità... ma a noi serve? Ho parlato a vanvera oppure la cosa ci torna utile?
Abbiamo deciso la risoluzione del nostro gioco, allora cominciamo a scrivere...
SYSTEM
{
TALK
{
Size { 6 }
Ink { 200 255 255 }
Paper { 0 0 150 }
Font { "sans serif" 12 }
}
WALK // Walking label properties
{
Label { "walk to" }
Position { 2 }
Ink { 255 255 255 }
Paper { 0 0 0 }
}
VERB talk_to
{
Label { "talk to" }
Size { 2 }
Icon { "gr/gui/talk.gif" }
Cursor { "gr/gui/Cursorlips1.gif" 10 10 "gr/gui/Cursorlips2.gif" 10 10 }
}
[... gli altri verbi...]
Defaultv { look } // default verb
FPS { 12 }
ANGLES { 4 }
PLAYER { andy }
SCREEN { 320 142 }
INVENTORY // Properties of Inventory panel
{
Ink { 0 125 255 }
Paper { 0 0 150 }
Position { 4 }
Size { 8 }
}
Title { "Andy" }
} //end SYSTEM
Una faticaccia... ma ne è valsa la pena: abbiamo scritto tutta la nostra interfaccia. Dove la mettiamo?
Beh, mettiamola nell'introduzione, nel primo capitolo, nel secondo capitolo, nel...
E poi quando dobbiamo cambiare l'immagine di un verbo ci tocca mettere mano a tutto?!? Search&Replace?
Chiamiamo il file: interface.adv dopodichè in ogni file dello script inseriamo questa riga, prima di ogni altra istruzione:
In questo modo le modifiche all'interfaccia saranno più sicure, rapide e concentrate.
Può però sorgere la domanda: io voglio avere 4 frame al secondo (blocco FPS) nell'introduzione, e ventiquattro FPS nel primo capitolo. Che faccio?
Basta inserire, dopo la riga di importazione dell'interfaccia, un blocco FPS { 24 } all'interno dello script del primo capitolo: il MAGE legge il valore dell'interfaccia per primo, poi continua nella lettura dello script e trova un nuovo valore, il vostro 24. Capisce che ogni modifica è quella "giusta" e usa 24 frame al secondo. È per questo motivo, peraltro, che nel blocco TITLE dell'interfaccia abbiamo scritto poco: in ogni .adv metteremo quel che serve!
Vediamolo subito: stiamo realizzando l'introduzione, quindi il nostro intro.adv sarà fatto così.
IMPORT "interface.adv"
SYSTEM
{
TITLE
{
LABEL { "Le Nuove Avventure di Andy" }
ABOUT { "Le Nuove Avventure di Andy - Introduzione }
}
FPS { 8 } // Ci bastano 8 fps per l'introduzione.
}
Un suggerimento: lasciate gli stessi FPS per tutto il gioco, ha un risultato più pregevole per l'occhio ed il cervello ;-) Qui mi serviva una cavia e ho scelto il blocco FPS.
Parola d'ordine di questa sottolezione: "Economia di codice & Riusabilità"
Apro una piccola parentesi sul modo in cui scrivere lo script... qui sopra avete visto un modo di farlo, ma avrei anche potuto fare così:
IMPORT "interface.adv"
SYSTEM {
TITLE {
LABEL { "Le Nuove Avventure di Andy" }
ABOUT { "Le Nuove Avventure di Andy - Introduzione } }
FPS { 8 } // Ci bastano 8 fps per l'introduzione.
}
Il MAGE capisce benissimo quel che sia scritto, perchè quando legge ignora gli spazi vuoti: basta che siano rispettate le righe! Quindi, siamo chiari, lo script funziona... però è assolutamente incomprensibile!
Come avete visto nel MAGE si lavora a blocchi e sottoblocchi: SYSTEM ci fornisce l'interfaccia, al suo interno c'è il sottoblocco FPS, ma c'è anche il sottoblocco INVENTORY che ha altri sottoblocchi...
Ho fatto un esempio scemo senza grandi sottoblocchi, ma immaginatevi una situazione normalissima di questo tipo:
blocco STANZA, con dentro (tra le tante cose) un blocco PERSONAGGIO, con dentro (tra le tante cose) un blocco OGGETTO, con dentro i blocchi dell'oggetto... senza l'indentazione (lo spostarsi con gli spazi o i caratteri di tabulazione) si diventa facilmente pazzi cercando di capire a quale blocco appartenga un sottoblocco. Con l'indentazione si rischia di meno la pazzia ;-)
Ok, finalmente cominciamo con le cose "serie". Bisogna cominciare a scrivere il codice... e qui arriva la vera "ingegnerizzazione". A che serve? Perchè ci serve?
Ogni oggetto, personaggio, stanza che apparirà nel vostro gioco avrà un nome, e questo nome deve essere uni(vo)co: non potete avere due guardie dal nome "guardia" o due stanze chiamate "trappola_mortale". Potete farlo solamente se si trovano in file .adv diversi ma occhio! Diversi non significa che mettete "trappola_mortale" in un file, nel secondo pure e poi ci scrivete IMPORT "il_primo_file.adv"!!!
Si tratterebbe in pratica dello stesso file!
Occorre quindi scegliere dei nomi diversi. Possiamo provare a fare così:
ITEM prima_guardia //Con questa parliamo
ITEM seconda_guardia //A questa dobbiamo dare un oggetto per farla andare via.
Ehy, ma aspetta: c'è poi un'altra stanza in cui ci sono proprio due guardie davanti ad una porta! Che facciamo?
ITEM prima_guardia_davanti_porta
ITEM seconda_guardia_davanti_porta
È un'idea, ma non sembra la migliore... si può fare di meglio.
- Dividere gli oggetti nelle seguenti categorie: oggetti che servono solo come sfondo, oggetti che fanno parte dello sfondo ma possono parlare o essere raccolti (sparendo quindi dallo sfondo), oggetti intelligenti con cui si può interagire, parlare, possono muoversi etc.
- Inventarsi uno standard per dare dei nomi agli oggetti in modo da facilitarsi la vita.
- Ricordarsi che ogni oggetto ha virtualmente ALMENO una immagine associata, quindi bisognerà impazzire un pochino anche per i nomi delle immagini!
Che cosa ci guadagniamo con questa analisi?
prima_guardia era un oggetto con cui potevamo parlare: seconda categoria.
seconda_guardia era un oggetto con cui potevamo interagire e che poi si poteva muovere o allontanarsi: terza categoria.
prima_guardia_davanti_porta e seconda_guardia_davanti_porta erano solamente due oggetti di sfondo per non lasciare vuoto il corridoio.
Fatta questa analisi, chiamiamoli in questo modo:
bg_trap_mortale_guardia1 => E' solo uno sfondo, un BackGround => bg_. Inoltre sta dentro la stanza con la trappola mortale. Avere un nome lungo non ci comporta problemi perchè tanto questo oggetto non fa nulla, è solamente uno sfondo! Lo dichiariamo come oggetto, gli diamo una dimensione, una immagine... dopodichè non lo vediamo mai più: ha un nome impronunciabile e non scrivibile, ma noi non lo scrivremo mai!
bg_trap_mortale_guardia2 => come sopra, in più le due sono nella stessa stanza, per cui non ci confondiamo chiamandole 1 e 2. Fossero in stanze diverse potrebbe farci confondere.
guardia_parlante => E' un oggetto che fa poche cose: parla (o con noi, o per dare dimensione di sfondo al gioco)
guardia => E' un personaggio vero che si muove, agisce, parla... lo chiamiamo proprio... guardia!! Come se avesse una identità propria.
In questo modo le cose si sono semplificate: non dobbiamo più impazzire a ricordare quale fosse la prima e quale la seconda guardia, le riconosciamo in base a quel che sappiamo facciano! Inoltre le due che servivano solo come sfondo hanno un nome che è chiaramente identificabile come oggetto da sfondo.
Questo discorso, come anticipato, va allargato anche al nome delle immagini! Innanzitutto l'idea è quella di separare le immagini in cartelle. Tutto quel che riguarda l'interfaccia (bottoni etc etc) lo mettiamo in gr/gui/ [da Graphical User Interface], quello che riguarda il nostro personaggio principale (o i nostri personaggi principali) possiamo metterlo in gr/hero/, dopodichè possiamo separare o con una cartella per ogni stanza o in qualche altro modo che ci sembri comodo. Ad esempio gr/sfondi/, gr/oggetti_di_sfondo/. gr/ombre/, gr/personaggi/, gr/animazioni/... diciamo che qui dipende un po' dal numero di immagini e dalla comodità che si abbia nello sfogliarle.
Torna alla pagina principale del MageGDT