Scarica il tutorial in PDF - Jo-Soft

Transcript

Scarica il tutorial in PDF - Jo-Soft
In questa sezione seguiremo passo passo la costruzione di un semplice gioco realizzato in Flash. Per la realizzazione è stato usato FlashCS3 versione
Studenti/insegnanti che a suo tempo veniva distribuito al prezzo di 228 Euro.
La versione FlashCS3 passata alla Adobe è corredata del linguaggio ActionScript 3 che introduce molte innovazioni rispetto al precedente
linguaggio utilizzato fino alla versione Macromedia Flash8.
Il progetto
Nel mio interesse al problema di come migliorare l'attenzione e la concentrazione al compito, mi è tornato in mente quando alle fiere di paese si
incontravano quasi sempre dei simpatici truffatori che facevano il gioco delle tre carte. Lungi da me, pargolo innocente, l'idea che si trattasse di un
imbroglio, mi trovavo a rammaricarmi della mia scarsa capacità di porre attenzione al movimento delle mani dell'imbonitore e dalla difficoltà a
seguire il movimento della carta che mi interessava.
Ho pensato oggi di riproporre un giochino simile sostituendo alle carte dei cappelli a cilindro da mago uno dei quali nasconde un gioiello: un anello.
Descrizione del gioco: su un tavolo sono visibili tre cappelli; a scelta del giocatore si inizia con i cappelli che si alzano per mostrare sotto quale dei
tre è posizionato l'anello. A cappelli abbassati si ha lo spostamento di due cappeli per volta che invertono la loro posizione (i cambi possibili quindi
sono: 1-2, 1-3, 2-3). Il giocatore viene invitato a fare clic sul cappello che secondo lui copre l'anello: se indovina gli viene assegnato un punto, se
sbaglia il punto viene assegnato al banco. Chi raggiunge il punteggio di 10 vince la manche.
Nella programmazione con Flash/ActionScript si procede su due binari ben distinti: la preparazione degli elementi grafici, la
programmazione delle classi che gestiranno gli elementi grafici stessi.
Si tenga presente che questo non è un tutorial per imparare ad usare Flash nella sua parte grafica; a tal proposito si forniscono vari link ove reperire
materiale utile allo scopo:
http://www.maestrantonella.it/tutorial_flash/tutorials_flash.html
http://www.ufottoleprotto.com/ani_flash1.html
http://www.adobe.com/it/devnet/flash/articles/design_character.html
altri ancora possono essere cercati sui motori di ricerca alla voce "tutorial flash"
Vediamo di quali quali elementi grafici ci serviremo. Sono di due categorie: quelli presenti direttamente sullo stage(che è composto da un singolo
fotogramma), e quelli presenti in libreria che poi verranno caricati e posizionati sullo stage dall'ActionScript.
Lo stage è stato così disegnato:
Gli elmenti grafici della libreria contengono clip animate create utilizzando simboli grafici (cappello, anello) e sfuttando l'interpolazione di
movimento o direttamente disegnando gli elementi frame by frame:
Il cappello è il simbolo grafico
da usare come base per
l'animazione successiva del
cappello che si alza per mostrare
cosa nasconde.
L'anello è l'altro simbolo grafico alla base
dell'animazione di uno dei tre cappelli.
L'animazione del primo cappello (cilindro1) viene creata con
interpolazione di movimento con 10 frame per far salire il
cappello e altri 10 per riportarlo giu.
L'animazione cilindro2 e cilindro 3 si ottengono duplicando
cilindro1 rinominandolo e togliendo il simbolo grafico dell'anello.
Il misuratore di punteggio per il Banco (errati) è stato creato
frame by frame aggiungendo alla forma di base(la scritta e il
rettangolo) via via i quadratini rossi.
Stessa cosa per il misuratore del punteggio del concorrente
(corretti).
Sono stati approntati poi due pulsanti e tre scritte trasformate in clip filmato, un cartello di avviso fine gioco con mancata vittoria ed una coppa per
la vittoria:
Queste scritte sono trasformate in clip filmato per poter essere poi gestite con l'ActioScript
La coppa era una immagine bitmap trasformata in vettoriale con la funzione
di flash: Bitmap/Ricalca bitmap; in questo modo non sgrana quando si
eseguirà il gioco a tutto schermo.
E veniamo ora alla programmazione dell'ActionScript.
Prima di iniziare dobbiamo rendere disponibili tutti i MovieClip creati e i pulsanti per l'ActionScript. Per fare questo agiamo col tasto destro su ogni
MovieClip selezionando Proprietà
e dopo aver scelto la visualizzazione rendiamo disponibile l'oggetto settando la casella "Esporta per ActionScript" ed esporta nel primo fotogramma.
Attenzione! il nome indicato nella casella classe sarà il nome di riferimento dell'ActionScript.
La scena iniziale, che ricordo è composto da un solo frame su cui è disegnato l'uomo dietro al tavolo (una clip in vettoriale trovata tra le tante
gratuite) viene legata alla sua classe di ActionScript indicandone il suo nome nell'apposito spazio. In questo caso come Classe documento abbiamo
scelto il nome "trovaanello"
per cui andremo a creare un nuovo documento ActionScript che salveremo subito, nella stessa cartella in cui abbiamo salvato il progetto grafico
flash (.fla), chiamandolo "trovaanello.as" (l'estensione .as viene aggiunta automaticamente).
Una classe ActionScript è composta da tre parti fondamentali: dalla direttiva "package" che comprende tutto il codice, dalla creazione della classe
come estensione del Movie principale, e dalla Function iniziale col nome della stessa classe seguendo questa struttura:
package {
public class trovaanello extends MovieClip {
public function trovaanello(){
}
}
}
Tutte le altre function devono essere comprese all'interno della classe.
Nel "package" devono essere chiamate tutte le classi esterne che sono le classi madri dei comandi che vengono utilizzati nell'ActionScript. Per
esempio il pacchetto flash.display contiene le classi principali utilizzate da Flash Player per creare contenuto grafico. L'utilizzo dell'asterisco indica
come al solito che si vogliono prendere in considerazione tutte le classi. La direttiva per l'importazione delle classi esterne è "import"
Subito dopo creiamo la classe "trovaanello"che estende il MovieClip a cui fa riferimento la chiamata dallo stage.
I clip filmato e i pulsanti, per essere posizionati e manipolati dall'ActionScript devono essere assegnati ad una variabile. Nel corso della
programmazione verranno utilizzate poi le variabili. Per rendere le variabili disponibili all'interno di una classe devono essere dichiarate all'inizio
dopo l'apertura della classe. Le variabili dichiarate all'interno delle funzioni invece saranno tutte "locali" cioè valide solo all'interno delle function
stesse.
I due caratteri "//" permettono di inserire dei commenti: tutto ciò che è inserito dopo questi due segni sul rigo non viene eseguito come non viene
eseguito anche tutto ciò che si trova scritto fra le coppie di caratteri "/*
*/" anche se si trovano su più righe (utile per commenti multilinea).
Come si potrà notare analizzando il codice (si è preferito utilizzare una immagine dello stesso per evidenziare il codice del linguaggio - parte in blu
- i valori assegnati - parti in nero - e i commenti - parti in grigio -) vengono create le variabili per i due pulsanti (puls_gioca e puls_continua;
puls_esci alla fine non è stato utilizzato!), le clip animate dei tre cappelli (cil1, cil2 e cil3), le barrette del punteggio (corr, err), tre variabili di tipo
movie clip che verranno utilizzate nel momento di scambio di posto dei cappelli per conservare memoria del contenuto dei singoli cappelli
(tempcil0, tempcil1, tempcil2). Nel corso del gioco poi devono essere visualizzate alternativamente 3 scritte e siccome per poterle disabilitare
devono essere visibili altrimenti danno errore, bisogna utilizzare una variabile da impostare a 1, a 2 o a 3 a seconda se la visualizzazione corrente
interessa il messaggio 1, oppure il messaggio 2 ecc.. Se non è visualizzato nessun messaggio, assumerà il valore 0. In gergo questo tipo di variabile
è detta flag ed ecco il nome "flagscritte" e più in basso ci sono le variabili delle scritte (scrtta1, scritta2, scritta3). Vi sono poi 4 Timer; il timer è un
elemento di programmazione che temporizza l'esecuzione del codice ed ha due parametri: il "delay" cioè la durata di ogni intervallo di esecuzione e
il "currentCount" che è il numero di volte delle esecuzioni (Timer (1000, 6) significa che il codice viene esguito ogni mille millesimi di secondo, per
6 cicli-volte). Tre Timer sono dedicati allo scambio tra i cappelli (scambio1 per lo scambio tra il cappello 1 e il cappello 2, scambio 2 per lo
scambio tra il cappello 2 e il cappello 3, scambio 3 per lo scambio tra il cappello 1 e il cappello 3). Il timer "ritardo" invece serve per far eseguire 6
scambi ad intervalli di un secondo l'uno dall'altro. La variabile premio e la variabile ritenta servono rispettivamente per la visualizzazione della
coppa in caso di vittoria e del messaggio di consolazione in caso di perdita.
"pos" e "scambi" sono due array (serie di variabili); il primo contiene i cilindri e siccome gli array cominciano con valore 0 avremo che pos[0] è
uguale a cil3, pos[1] è uguale a cil2 e pos[2] è uguale a cil1. "scambi" invece contiene i tipi dii scambio che si possono fare coi tre cappelli
scambiandone due per volta: gli scambi possibili sono tre (il primo col secondo, il secondo col terzo, il primo col terzo). Come si vede scambi
contiene 6 valori (due volte 1, due volte 2, due volte 3); questo vuol dire che si faranno due scambi di tipo 1,due scambi di tipo 2, due scambi di tipo
3. Ogni volta però gli elementi di questo array verranno mescolati e quindil'ordine degli scambi sarà sempre diverso.
Veniamo ora al codice della funzione di avvio della classe "trovaanello"; questa funzione viene eseguita automaticamente all'avvio.
Il comando addChild(nome elemento) permette di visualizzare un elemento sullo stage e l'uso di nome_elemento.x=numeropixel e
nome_elemento.y=numeropixel permettono di posizionare l'elemento stesso alle coordinate volute.
nomeclip.gotoAndPlay(numeroframe) permette di portare la testina di lettura dell'animazione della clip animata al numero del frame indicato.
Per far si che un oggetto sia sensibile ad un evento (per esempio il clic del mouse) si usa la sintassi:
nomeclip.addEventListener(tipodievento.evento, funzionedaeseguire) per esempio
puls_gioca.addEventListener(MouseEvent.CLICK, gioca); significa:se si fa clic sul pulsante "gioca" vai ad eseguire la function gioca.
Quindi all'avvio del gioco viene posizionato il pulsante gioca e viene attivato, vengono posizionati i 3 cilindri ed attivati: si può quindi avviare il
gioco, si può fare clic sui cilindri (l'evento manda alle function alzacil1, alzacil2, alzacil3 che come si comprende dal nome lanciano l'animazione
del sollevamento del cappello. Nelle clip del cappello infatti al frame 1 bisogna inserire l'azione stop(); in modo che posizionato al frame 1 la clip si
fermi mentre portandolo al frame 2 parta per eseguire tutti i frame fino a tornare all'1 dove si fermerà di nuovo.
Unica possibilità quindi per operare è quella di fare clic sul pulsante gioca ed andare alla function gioca.
La function mostra i contatori dei punteggi posizionandoli al primo frame e fermandoli (gotoAndStop(1)), rimuove il pulsante gioca sostituendolo
col pulsante continua a cui assegna l'evento CLICK per mandarlo alla function avanti. Quindi va alla function avvio_gioco.
Passando a questa function per prima cosa viene chiamata la piccola function di rimozione di eventuali scritte (la prima volta che si passa per questa
funzione non ve ne sono ma poi ve ne saranno nel corso del gioco perchè da questa funzione si ripassa ad ogni item), poi vegono avviate le tre
animazioni dei cilindri che si alzano per mostrare dove è l'anello (per avviare basta portare ognuna al secondo framecosì continuano fino a tornare al
primo frame dove è presente il comando stop();), viene poi chiamata la funzione mescola che mescolerà i tipi di scambio dei cappelli (analizzeremo
la funzione in seguito), assegna al timer "ritardo" la funzione "timerritardo" da eseguire al suo start, disattiva la risposta al clic del pulsante continua
in modo che non risponda al clic mentre è in funzione lo scambio e la richiesta di indovinare, viene resettato il timer (la prima volta non servirebbe
ma questa funzione verrà chiamata ad ogni nuovo item e dalla seconda in poi è essenziale l'azzeramento), viene avviato il timer che ricordiamo ha
due elementi: il "delay" cioè la durata di ogni intervallo di esecuzione e il "currentCount" che è il numero di volte delle esecuzioni
il currentCount del timer contiene di volta in volta il numero di ripetizioni fatto dal timer e viene incrementato ad ogni ciclo quindi progredirà con
valori 1-2-3-4-5-6;
ogni volta viene analizzato il contenuto della variabile array scambi[ valore corrente di currentCount] a seconda del contenuto viene chiamata la
function corretta (una delle tre possibili). Quando il contatore arriva a 6 termina lo scambio cappelli e viene chiamata la funzione avviacontrollo.
Questa function, attivata dopo che è avvenuto lo scambio dei cappelli, non fa altro chevisualizzare la scritta1 (invito a fare clic sul cappello con
l'anello sotto), mettere a 1 il flag delle scritte, posizionare la scritta stessa alle giuste coordinate, riattivare la rilevazione del clic sui cappelli. Il clic
su uno dei cappeli avvierà poi il controllo della correttezza e il prosieguo del gioco.
Ecco quindi la function che alza il cappello 1 e che controlla la vittoria di un item (il cili1 è sempre quello che contiene l'anello).
La function avvia il sollevamento del cappello portando la testina della linea temporale della clip filmato al secondo frame (gotoAndPlay(2)), fa
avanzare di un frame il contatore delle risposte corrette leggendo il numero del frame corrent (corr.currentFtrame) ed aggiungendoci uno, chiama la
funzione della rimozione delle scritte, visualizza la scritta3 (esatto ......), pone il flag delle scritte a 3, posiziona la scritta sul bordo del tavolo, attiva
la rilevazione del clic del pulsante continua (che era stato disabilitato durante la fase di mescolamento e di attesa del clic su un cappello), chiama la
function che disattiva la rilevazione del clic sui cappelli "disattiva()" in modo che si possa avere un solo evento o corretto o errato, si controlla se il
contatore del punteggio vincente ha raggiunto il massimo (fine del gioco), nel caso il controllo dia risposta vera viene chiamata la funzione
vittoria() che presenterà la coppa e permetterà di riavviare il gioco.
E' ovvio che le altre due function dei cappelli funzioneranno allo stesso modo con le varianti della scritta che presentano (errato....), dell'aumento
del punteggio degli errori, e del controllo della fine del gioco sul punteggio degli errori con la chiamata alla funzione sconfitta() nel caso il controllo
dia risultato vero.
Analizziamo ora le function dello scambio di posizione dei cappelli. Come già detto consideriamo l'array delle posizioni: all'avvio pos[0] (quello a
sinistra) conterrà la clip cil3, pos[1] (quello centrale) conterrà la clip cil2, pos[2] (quello a destra) conterrà la clip cil1 quella con l'anello.
Prendiamo ora in considerazione lo scambio di posto tra pos[0] e pos[1]: una volta scambiati avremo che pos[1] starà a sinistra e pos[0] starà al
centro. Stando però così le cose in uno scambio successivo non riuscirei a fare riferimento in modo corretto alla posizione di sinistra nè a quella di
centro. Bisogna fare in modo che ogni volta, una volta effettuato lo scambio, il cilindro a sinistra torni ad essere pos[0] e quello centrale torni ad
essere pos[1], in modo che ad un successivo passaggio la funzione possa essere rieseguita correttamente.
Per farlo utilizziamo le variabili temporanee di appoggio tempcil0 e tempcil1 in questo modo: all'avvio assegnamo a tempcil0 il contenuto di pos[0]
(cioè cil3) e a tempcil1 il contenuto di pos[1] cioè cil2; una volta effettuato lo scambio e che cioè cil2(tempcil1) si trova a sinistra e cil3(tempcil0) si
trova al centro, faccio le riassegnazioni: a tempcil1 che si trova a sinistra riassegno pos[0] e a tempcil0 che si trova al centro riassegno pos[1] così le
variabili pos[0] e pos[1] si ritrovano al posto di partenza mentre il loro contenuto è stato scambiato e quindi sono pronti ad un successivo scambio.
Logicamente questo ragionamento è fatto per ogni tipo di scambio.
Commentando le varie linee delle due funzioni avremo prima l'assegnazione alle variabili tempcil0 e tempcil1 del contenuto di pos[0] e pos[1],
l'attivazione dell'evento timer a cui si assegna la funzione "timerscambio1", il reset del timer e il suo avvio. Quando si avvia il timer esegue il codice
contenuto nella funzione "timerscambio1".
In questa seconda funzione avviene lo spostamento di pos[0] che dalla sua posizione (140 sull'asse x) attraverso i 14 step del timerche aggiunge a
140 ilnumero dello step corrente moltiplicato per 10 (quindi al primo step sarà 150 cioè (140 + 1*10), al secondo step sarà 160 cioè (140 + 2*10) e
così via). Contemporaneamente per pos[1] avviene la stessa cosa ma i valori vengono detratti e quindi dalla posizione 280 passerà alla posizione
140. Al termine c'è il controllo se il timer ha finito (se si èallo step 14): se è finito si ha il riassegnamentoper pos[0] e pos[1].
Logicamente tutto questo, con le opportune varianti, avverrà anche per il secondo tipo di scambio e per il terzo.
Vediamo ora le varie funzioni di servizio:
Mescola() prende la sequenza dei tipi di scambi[] (ricordiamo che sono di tre tipi 1-2-3) che inizialmente è impostata a (1, 2, 3, 1, 2, 3) e la mescola.
Ricordiamo che l'array scambi impostato all'inizio ci dice che scambi[0] contiene il valore 1, scambi[1] contiene il valore 2, scambi[2] contiene il
valore 3, scambi[3] contiene il valore 1, scambi[4] contiene il valore 2, scambi[5] contiene il valore 3.
Ecco il funzionamento della function: vengono inizializzate tre variabili locali di tipo numerico (p1 che servirà come variabile di appoggio per
permettere di scambiare posizione a due valori, numCas che conterrà di volta in volta un numero casuale da 0 a 5, m che funge da contatore al ciclo
for...), si avvia il ciclo for assegnando al contatore m il valore 0, il ciclo andrà avanti fino a quando m sarà minore di 6 (quindi il ciclo sarà eseguito
sei volte), ad ogni passaggio la variabile m viene incrementato di 1 (m++), si pone in numCas un numero casuale compreso tra 0 e 5
(Math.round(Math.random()*5), si mette il contenuto di scambi[m] (al primo passaggio sarà scambi[0], al secondo scambi[1] ...) nella varibile p1,
dentro scambi[m] invece si mette il valore contenuto da scambi[numCas] (quindi uno dei sei valori dell' array) e dentro la stessa variabile
scambi[numCas] si mette il valore precedentemente messo in p1. In questo modo si scambiano i valori tra due variabili.
Nella funzione vittoria() chiamata quando si raggiunge il punteggio di 10 risposte esatte, viene rimosso il pulsante continua, vengono rimosse
eventuali scritte, il flag delle scritte viene messo a 0(nessuna scritta visualizzata), viene visualizzata la coppa ("premio") viene posizionata alle
giuste coordinate, viene assegnato un evento CLICK alla coppa che attiva la funzione ricomincia().
Nella funzione ricomincia() che si attiva quando si fa clic sulla coppa, viene rimossa la coppa, vengono rimossi i contatori dei punteggi, viene
visualizzato e posizionato il pulsante gioca, gli viene assegnato l'evento click con la chiamata alla funzione gioca (da cui siamo partiti per il gioco).
Per la funzione sconfitta si ha lo stesso funzionamento solo che al posto della coppa viene visualizzato una clip con la scritta che invita a ritentare.
La funzione rimuoviscritte chiamate tante volte nel corso del codice fa un controllo del flag attivato: se vale 1 vuol dire che è attiva scritta1 e quindi
la rimuove... e così via
La chiamata alla funzione avanti non fa altro che chiamare la funzione avvio_gioco(). Si fa notare che la funzione avanti risponde ad un evento del
mouse e quindi può essere chiamata solo da un clic del mouse mentre la funzione avvio_gioco() può essere chiamata direttamente da qualsiasi punto
del codice ma non da un clic del mouse: ecco perchè da una function ne viene chiamata un'altra in questo modo si evita di duplicare la stessa
funzione (una chiamata dal clic del mouse ed una chiamata direttamente per eseguire le stesse operazioni)
La function disattiva serve per togliere la rilevazione dell'evento CLICK sui cappelli durante il loroscambio ciclico.