1. Introduzione
  2. Iniziamo
  3. Nemici Multipli
  4. Game Over
  5. Punteggi e Orologio
  6. Tanti Piccoli Miglioramenti
  7. Usiamo la Tastiera
  8. Aggiungere un Preloader (Parte 1 - Parte 2)
  9. Aggiungere Musica ed Effetti Sonori
  10. Livelli Multipli
  11. Salvare e Caricare Informazioni
  12. Garbage Collection

Due Parole prima di Iniziare

Un sacco di sviluppatori Flash hanno trovato il passaggio da Actionscript 2 ad Actionscript 3 decisamente traumatizzante. Al contrario, molti programmatori di altri linguaggi hanno trovato Actionscript 3 senza dubbio intuitivo, odiando al tempo stesso il suo predecessore.

Questa guida non richiederà la conoscenza di Actionscript 2, ne tantomeno l’aver usato mai Flash nella propria vita. Troverai tutto decisamente semplice nel caso tu conosca le basi di qualche altro linguaggio di programmazione (parlo di variabili, if, loops, funzioni e così via). Nel caso non le conoscessi già non ti preoccupare ugualmente.

La guida cercherà inoltre di rendere chiare le differenze tra Actionscript2 ed Actionscript3, ma non in modo approfondito dato che, in un certo senso, stiamo partendo da zero. L’idea per questo “Avoider Game” è nata nel sito di Frozen Haddock che tra l’altro mi ha permesso di riscrivere la sua guida in versione 3.0. Un grazie a Frozen Haddock!

Ovviamente, date le differenze tra Actionscript2 e 3, questo non sarà un porting diretto del tutorial. L’ho ridisegnato per seguire le cosidette “buone maniere” nella programmazione in Actionscript3. Sto parlando di:

  • Un Frame
  • Un Layer
  • Nessun Oggetto nello Stage
  • Niente Codice nella Timeline
  • Niente Codice in nessun Simbolo

(Nota: se non avete mai creato un gioco in Flash prima d’ora, tutto questo potrebbe non avere alcun senso. Non vi preoccupate, è un ottima cosa!)

Queste regole, probabilmente, potrebbero non essere completamente osservate quando ci occuperemo di mostrare a schermo un preloader per il nostro gioco. Ma ne parleremo a tempo debito.

Nella creazione del gioco utilizzeremo Classi, Eventi e programmazione orientata agli oggetti, strumenti eleganti che semplificheranno le nostre operazioni. Ma adesso sto esagerando, torniamo a noi ;)

In questa prima parte del tutorial, faremo in modo di impostare il nostro ambiente correttamente e creeremo le cosiddette “meccaniche di gioco” basilari.  Per capire quanto basilari, cliccate sull’immagine di seguito per visualizzare un esempio.

AvoiderGame_Part1_200

Il gioco, com’è giusto che sia, sarà molto diverso e più sofisticato alla fine della dodicesima parte di questa guida. ;)


Il Setup

Ok, ci siamo. Avviamo la nostra copia di Flash (nel mio caso CS3, ma anche con le versioni future non ci sono problemi) e selezioniamo “File > Nuovo > File Flash (Actionscript 3.0)”. Selezioniamo quindi “File > Salva” e creiamo una nuova cartella in un percorso a nostro piacimento: qui memorizzeremo tutti i files del gioco. Un consiglio che posso darvi è quello di usare le proprie iniziali per poter condividere il tutto con le altre persone in modo più facile.

Per esempio, usando come titolo “AvoidersGame”, due possibilità potrebbero essere:

  • AvoidersGame-FM (Francesco Malatesta)
  • AvoidersGame-MJW (Michael James Williams)

e così via.

Dentro questa cartella, successivamente, creiamone un’altra, chiamata “Classi”. Torniamo alla cartella precedente, la principale, e salviamo qui il nostro file *.fla (mi raccomando, nella cartella principale e non nella cartella “Classi”).

AvoiderGame_Part1_04

Ora ci sono alcune impostazioni che dobbiamo sistemare prima di iniziare con lo sviluppo vero e proprio del gioco. Dal menù selezioniamo “File > Impostazioni Pubblicazione”: selezioniamo la scheda “Flash” e poi “Impostazioni…” al fianco della lista delle versioni Action Script.

AvoiderGame_Part1_03

Clicca sul segno “+” vicino a “Percorso della Classe” e scrivi “./Classi” nella textbox che appare (ovviamente sostituisci “Classi” con un altro nome qualora la cartella che hai creato precedentemente non si chiami così ;) ). Questa nostra operazione serve a far capire al Flash che vogliamo memorizzare tutto il codice necessario al gioco nella cartella che abbiamo creato. In questo modo, nel caso non venga trovato del codice dal programma, verrà cercato qui.

AvoiderGame_Part1_100

Oltre questo, verifica che “Dichiara automaticamente istanze sullo stage” sia già selezionato.

Ora ci occuperemo invece di modificare i primi parametri del gioco. Dopo essere usciti da questa schermata ci ritroveremo nell’interfaccia principale. Selezioniamo il pulsante affianco a “Dimensioni:”. Frozen Haddock aveva scelto una grandezza di 300×300 pixels. Noi questa volta, presi dal fascino del vecchio stile 4:3, utilizzeremo una risoluzione di 400×300. Il background che sceglieremo sarà di colore grigio.

Per quanto riguarda il framerate, invece, imposteremo un valore di 24 fps.

AvoiderGame_Part1_205

Bene, e il setup è finalmente andato ;) Ora dobbiamo creare il nostro primo “nemico”.


Creiamo il Nemico.

Nel gioco che andremo a creare il nemico sarà l’oggetto che noi (il giocatore) dovremo evitare per non terminare la partita in Game Over. Quindi disegniamolo prima di dargli la vita! Dal menù scegliamo “Inserisci > Nuovo Simbolo” e, nella box che apparirà, diamogli il nome di “Enemy” (e che nemico!) impostando il tipo dell’oggetto come “Clip Filmato”. Dopo questi passaggi, la libreria mostrerà la new entry.

AvoiderGame_Part1_06

Note: se per caso non dovessi vedere la libreria a lato, verifica che sia selezionata dal menù “Finestra > Libreria”.

Di default dovremmo essere già in grado di modificare il nostro nemico. Puoi vedere quello che stai modificando tramite la barra in alto, appena sopra la finestra dello stage.

AvoiderGame_Part1_08

Nel caso tu non stia modificando l’oggetto “Enemy” per un qualsiasi motivo, basterà cliccare due volte su “Enemy” nella libreria (oppure cliccandoci con il pulsante destro del mouse per poi selezionare “Modifica”). Ora devi disegnare il tuo nemico. Frozen Haddock aveva scelto uno smile per il suo nemico. Chissà perchè, magari per i suoi banner pubblicitari. Comunque sia, chiacchiere a parte, noi faremo lo stesso. Per comodità con alcune parti di questo tutorial, assumerò che tu stia disegnando qualcosa di simile al mio nemico.

Se non sei abituato a disegnare in flash, ti consiglio di dare un occhiata qui: http://tutorio.us/?p=14

Ecco il nostro risultato:

AvoiderGame_Part1_10 AvoiderGame_Part1_11 AvoiderGame_Part1_12 AvoiderGame_Part1_13

Wow. Ci siamo.

Ma c’è ancora qualcosa da fissare. La vedi quella croce in alto a destra nell’immagine? All’altezza dell’occhio.. facci caso. È quello che può essere definito come il “punto di registrazione”. Quando noi scriveremo del codice riguardante il nostro nemico e, per esempio, diremo al programma di “posizionare il nemico al punto X,Y” il sistema prenderà quel punto preciso, segnato dalla croce, come riferimento.

Lo so, è difficile da capire e vi assicuro che lo è anche a parole. Con la pratica capirete tutto meglio.

Comunque sia, sposterò questo punto di registrazione al centro dell’immagine. Come fare? Ecco qui il metodo:

  • Per prima cosa verifichiamo di essere in fase di modifica del nostro oggetto.
  • Ci apparirà questo tipo di selezione.

AvoiderGame_Part1_14

  • Cliccando su “Elabora > Raggruppa” raggrupperete tutto il vostro disegno in un unica entità. In questo modo, quando lo sposterete nell’area di disegno, lo sposterete tutto insieme e non parte per parte. (Facendo questa cosa precedentemente, per esempio, avreste potuto trascinare solamente l’occhio o la bocca)

AvoiderGame_Part1_15

  • Rechiamoci quindi al pannello dell’allineamento. Se non lo vediamo, controlliamo nel menù la voce  “Finestra > Allinea” oppure premiamo Ctrl + K. Appena appare, clicchiamo sui due pulsanti di allineamento centrale, come in figura:

AvoiderGame_Part1_17

In questo modo avremo regolato tutto ciò che ci serve e impostato l’allineamento corretto del nostro nemico. Ora che abbiamo terminato il design del nostro antagonista possiamo anche uscire dalla modalità di modifca: è un buon momento, sicuramente, per salvare il nostro lavoro selezionando nel menù “File > Salva”.


Prima di continuare: Posso capire che questo articolo è molto lungo. Nonostante cerchi di essere più chiaro possibile, non vi fate mettere fretta da niente. Provate e riprovate ogni singola meccanica per fare in modo di comprenderla perfettamente.


Le Istruzioni per il nostro Nemico

Beh, fino ad adesso non abbiamo fatto un granchè rispetto a quelle che sono le solite cose che si facevano anche nelle versioni flash precedenti. Abbiamo avviato il nostro programma, abbiamo creato il clip per il nostro nemico.. ora arriva un po’ di codice, finalmente. Nello specifico, realizzeremo il codice per gestire il comportamento del nostro nemico nell’area di gioco.

Come già detto in precedenza, questo codice non andrà né nella linea temporale e nemmeno nel codice delle azioni del clip appena creato. Stavolta, invece, il nostro codice andrà in un file esterno. I benefici nell’adottare una soluzione simile si possono subito intuire:

  • Il codice è separato dall’artwork ed in questo modo puoi fornire gli artwork senza dover fornire anche il codice.
  • Allo stesso modo, puoi fornire ad un programmatore il codice senza dover andare a cercare l’artwork corrispondente.
  • Se hai più programmatori al lavoro sullo stesso progetto, è ancora più facile mettere tutto insieme alla fine del lavoro.

Arrivati a questo punto, i programmatori abituati ad usare l’Actionscript2 iniziano a comprendere quanto possa essere diverso (e a volte anche complicato) il passaggio all’uso di Actionscript3. Essenzialmente, il perché si ritrova nella necessità di scrivere molto più codice rispetto alla normale abitudine.

Vi invito tuttavia a riflettere su una cosa importante: nonostante il numero maggiore di linee di codice, vi assicuro che il tutto non è assolutamente difficile da capire e questo metodo di scrittura darà i suoi frutti nel tempo a venire.

(Nota Personale: Questo aiuta sicuramente a capire alcune dinamiche di un linguaggio di programmazione più classico, dato che certe dinamiche presenti in AS3 che adotteremo possono essere riviste, più o meno, senza problemi con altri linguaggi di programmazione!)

Iniziamo a scrivere il nostro codice. Salviamo il file Actionscript nella famosa cartella “Classi” da noi creata precedentemente. Ecco cosa dobbiamo scrivere innanzitutto:

package
{

}

La parola chiave package semplicemente dice che, tutto ciò che verrà scritto tra queste parentesi graffe farà parte, appunto, di un… pacchetto! (esatto, niente spiegazioni astruse) In questo caso, del “pacchetto” relativo al nemico.

Come parte di questo package ora dobbiamo definire la classe vera e propria del nemico, che chiameremo Enemy, tramite la parola chiave class. La classe del nemico sarà il centro focale per determinare il comportamento e le caratteristiche di questo tipo di entità.

package
{
  public class Enemy extends MovieClip
  {

  }
}

Ma basta paroloni e analizziamo tutto questo codice piano piano:

Come abbiamo già detto, tutto quello che riguarda il nostro nemico verrà racchiuso in questa classe, Enemy. La parola chiave public serve a dire al nostro programma che questa classe potrà far accedere a se stessa altre porzioni di codice.

Così come troverete classi di tipo Public, infatti, troverete classi o parti di classi Internal con funzioni che non hanno bisogno di accesso o che usano questo metodo per ragioni di sicurezza. Questo giusto per farvi capire, andiamo avanti!

Notiamo altre parole: extends MovieClip. A parte le varie spiegazioni precise e di settore che posso dare, per i neofiti tutto questo può significare semplicemente “Esiste una classe di tipo MovieClip con determinati attributi e funzioni. La classe Enemy, che estende la classe MovieClip, ha tutte le capacità di MovieClip più le altre sviluppate a parte”. Una sorta di “potenziamento” della classe MovieClip.

A cosa serve tutto questo? Considerate, giusto come esempio, che la classe MovieClip, che rappresenta un filmato, ha tutte le funzioni pronte per la riproduzione del filmato stesso: una funzione per andare al frame successivo, una funzione per il frame e così via. Se dovessimo utilizzare le stesse cose (e le utilizzeremo) per il nostro nemico, che senso ha riscrivere tutte le volte tutto il codice da capo? A voi le conclusioni ;)

Nonostante la classe MovieClip sia decisamente importante, Flash ha bisogno di sapere dove trovarla. Nessun problema, infatti abbiamo aggiunto la semplice linea di codice import flash.display.MovieClip; che si occuperà di ritrovare la classe che serve.

package
{
  import flash.display.MovieClip;
  public class Enemy extends MovieClip
  {

  }
}

Infine, dobbiamo definire ciò che è comunemente definita la “funzione costruttore”, ovvero quella funzione che viene eseguita tutte le volte che l’oggetto di tipo Enemy viene creato. Come si aggiunge? Basta creare una funzione senza alcun tipo di valore dello stesso nome della classe. Ovviamente deve essere pubblica, in quanto sarà eseguita sempre (tranne in casi rari o particolari) dall’esterno della classe.
package
{
  import flash.display.MovieClip;
  public class Enemy extends MovieClip
  {
    public function Enemy()
    {

    }
  }
}

Da notare che, essendo una funzione e non una classe, affianco al nome della detta funzione abbiamo le parentesi tonde aperte e chiuse.

Bene! Ora abbiamo lo scheletro della nostra classe Enemy!

Quello che dobbiamo fare adesso è collegare la classe al nostro artwork precedentemente creato. Salviamo le modifiche e torniamo all’editor, sullo stage, nel file .FLA (uscendo quindi dal file AS). Dalla libreria, selezioniamo l’artwork che ci serve e clicchiamoci col pulsante destro del mouse: selezioniamo la voce “Proprietà”. Clicchiamo sul pulsante “Avanzato” per rivelare le impostazioni più avanzate del nostro clip, nello specifico la scheda “Concatenamento”. Ora:

  • Controlliamo che la voce “Esporta per Actionscript” sia selezionata.
  • Controllate che la textbox “Classe” legga il valore “Enemy”.

Se l’operazione andrà a buon fine, vi sarà un segno di spunta affianco alla textbox. Comparirà inoltre un’icona di una matita che, se selezionata con il mouse, apre il file AS con la classe interessata. Questa sarà la nostra conferma definitiva.

Chiudiamo la finestra cliccando su “Ok”.

Ora che abbiamo associato il codice all’artwork, possiamo lavorare tranquillamente sul codice del comportamento del nostro nemico. Inizieremo con qualcosa di molto basilare, legato al posizionamento del nemico all’inizio del gioco.

Quindi abbiamo pensato di:

  • Far apparire il nemico in cima allo schermo quando viene creato.
  • Farlo scendere pian piano in verticale verso il basso.

Possiamo subito sviluppare il primo punto: tornando al nostro codice della classe Enemy, infatti, possiamo aggiungere delle istruzioni nel nostro metodo costruttore (eseguito appunto quando l’oggetto viene creato).

package {
  import flash.display.MovieClip;
  public class Enemy extends MovieClip {
    public function Enemy() {
      x = 100;
      y = 0;
    }
  }
}

Dato che la classe MovieClip ha le proprietà x ed y, la classe Enemy le eredita automaticamente.

Tutti coloro che hanno familiarità con il sistema delle Coordinate Cartesiane ora mi diranno: “Fra, pensavo che il nemico doveva apparire in cima alla schermata! Invece hai impostato la coordinata y a zero!”. Succede spesso in informatica. Imparate questa nuova nozione: l’asse Y è ribaltato. Il punto di coordinate 0,0 infatti si troverà in alto a sinistra, e man mano che scenderemo la coordinata Y aumenterà. Qui di seguito una piccola immagine d’esempio per far comprendere meglio il concetto.

AvoiderGame_Part1_20

Niente panico, ti ci abituerai.

Ok, ora che abbiamo scritto il codice di posizionamento del nostro nemico, dobbiamo gestire il suo movimento verso il basso! Per fare questo creeremo un nuovo metodo nella classe Enemy, come spiega il codice di seguito:

package
{
  import flash.display.MovieClip;
  public class Enemy extends MovieClip
  {
    public function Enemy()
    {
      x = 100;
      y = 0;
    }

    public function moveDownABit():void
    {
      y = y + 3;
    }
  }
}

Spieghiamo il tutto con calma: per prima cosa notiamo function moveDownABit():void: in poche parole una funzione, chiamata appunto “moveDownABit”. Non essendo il metodo costruttore, ovviamente, dobbiamo provvedere a specificare per forza qualcosa per quanto riguarda il valore di ritorno. Il valore di ritorno è indicato con il nome del tipo: se la funzione ritorna un numero (vedi per esempio la somma di due numeri) allora ritornerà un valore di tipo numerico. Oppure, se non deve ritornare niente direttamente, possiamo usare altre parole chiave apposta.

Nel nostro caso, dopo che effettua la mossa del nostro nemico, non deve ritornare niente. Per questo motivo possiamo usare la parola chiave void per specificare la situazione. Basterà inserire il tipo dopo il nome della funzione, preceduto da il segno dei due punti. Quindi:

moveDownABit():void

Più di così non potevo esser chiaro :D

L’ultima riga da analizzare è semplice da capire: y = y + 3; qui non facciamo altro che incrementare di tre (pixel in questo caso) la coordinata y. Niente di più, niente di meno. Ora il codice per il nostro Enemy è pronto, quello che rimane da fare è creare un oggetto di questo tipo e utilizzarlo ;)


Creiamo l’Oggetto Nemico

Salviamo il nostro file Enemy.as e torniamo al nostro file .FLA. Il nostro prossimo passo è quello di implementare un nemico a tutti gli effetti nel gioco; fino ad adesso abbiamo avuto a che fare con quello che si può definire il “template” di un nemico, non col nemico stesso. Una sorta di “traccia” se così vogliamo chiamarla per rendere chiaro il concetto ai profani. In poche parole, abbiamo avuto a che fare con la classe.

È importante ricordare che Flash ha iniziato la sua vita come tool per le animazioni: di certo non si pensava di arrivare a certi livelli. Nonostante uno sviluppo enorme durante questi anni, ogni cosa che viene creata con Flash viene visto, alla base, come un oggetto MovieClip. Come è avvenuto per il nostro Enemy, anche MovieClip ha un costruttore che viene eseguito ad ogni creazione di un oggetto di questo tipo.

Quello che faremo ora sarà estendere ancora di più questo MovieClip, tramite la creazione di una classe che gestisca l’intero gioco. Ovviamente, penso iniziate ad immaginare il fatto che creeremo un nuovo file Actionscript 3 per lo scopo.

Stavolta salviamolo come AvoiderGame.as e aggiungiamoci questo codice:

package
{
  import flash.display.MovieClip;
  public class AvoiderGame extends MovieClip
  {
    public function AvoiderGame()
    {

    }
  }
}

Vi è familiare vero? ;)

A parte i nomi, il codice è esattamente lo stesso utilizzato nel file Enemy.as. Un estensione della classe MovieClip. Salviamo le modifiche al file e torniamo ancora una volta al nostro file principale *.fla.

Adesso cerchiamo il pannello “Proprietà”. In genere si può visualizzare in basso nella schermata di flash (è quello che consente di decidere le impostazioni base del filmato, risoluzione e.c.c.).

(nel caso non sia visibile, è sufficiente cercare la voce in “Finestra > Proprietà > Proprietà”)

Noterete una textbox con vicino scritto “Classe Documento”. Indovinate cosa ci dobbiamo scrivere? Esattamente, AvoiderGame, il nome della classe da noi creata precedentemente.

Nota Bene: può sembrare una cosa da poco, ma controllate SEMPRE le maiuscole e le minuscole dei nomi dei files e delle classi, perchè devono essere uguali al 100%. Per controllare che Flash trovi le giuste classi, usate sempre lo strumento della matita affianco al nome della classe dopo averlo digitato.

AvoiderGame_Part1_21

Clicca sull’Immagine per Ingrandire

Bene, stiamo andando alla grande! Ora possiamo modificare senza problemi il costruttore della classe principale e dirgli di creare un nemico all’avvio del gioco. Come fare? Semplice, dichiariamo una variabile di tipo Enemy :) Ecco il codice:

package
{
  import flash.display.MovieClip;
  public class AvoiderGame extends MovieClip
  {
    public function AvoiderGame()
    {
      enemy = new Enemy();
    }
  }
}

Mi raccomando anche qui alle maiuscole e le minuscole: come potete vedere il nostro oggetto si chiamerà “enemy”, ma la classe di riferimento è sempre quella, “Enemy” con la E maiuscola iniziale!

Al momento, la variabile “enemy” è accessibile solo dal costruttore. Terminata l’operazione del costruttore poi, cosa succede? Non avremmo praticamente niente e quindi abbiamo bisogno di dire a Flash che il nostro “enemy” deve essere disponibile per tutta la durata del gioco.

Questo è possibile aggiungendo la dichiarazione della variabile fuori dal metodo costruttore, rendendo a tutti gli effetti la variabile “enemy” proprietà della classe AvoiderGame. Notate come la programmazione ad oggetti inizia a dare una forma precisa e senza pieghe dell’intero gioco. Bando alle ciance, ecco il codice:

package
{
  import flash.display.MovieClip;
  public class AvoiderGame extends MovieClip
  {
    public var enemy:Enemy;

    public function AvoiderGame()
    {
      enemy = new Enemy();
    }
  }
}

Spieghiamo questa nuova istruzione (public var enemy:Enemy;):

  • public – ormai lo sai cosa vuol dire, vero?
  • var – indica che vogliamo dichiarare una variabile
  • enemy:Enemy – è traducibile come “l’oggetto (o variabile) che voglio creare si chiamerà enemy e farà riferimento alla classe Enemy (da notare la differenza maiuscolo minuscolo)

Ora che la variabile è definita nel contesto della classe AvoiderGame, sarà disponibile per tutta la classe e quindi per tutto il gioco (in quanto AvoiderGame è la classe principale del gioco stesso).

Bene, il nemico è stato creato, ora dobbiamo disegnarlo a schermo! Andiamo a modificare il costruttore della classe AvoiderGame ancora una volta:

    public function AvoiderGame()
    {
      enemy = new Enemy();
      addChild( enemy );
    }

Wow, e questo cos’è? Man mano che andiamo avanti veniamo a conoscenza di nuovi strumenti: stavolta è il turno di addChild, funzione che permette di “agganciare” gli oggetti allo stage, in modo tale da renderli visibili in tutto e per tutto.

Per essere precisi, questa funzione aggancia il filmato alla classe specificata dall’utente per il documento. Considerando che noi abbiamo scelto AvoiderGame come classe principale tutto ritorna: essendo AvoiderGame il filmato, agganceremo al filmato stesso il nostro benedetto “enemy”. Spero d’essere stato chiaro. Forse un po contorto ma voglio rendere ogni concetto nel miglior modo possibile.

Inoltre, man mano che andrete avanti capirete che certe cose (anzi, molte cose) sono più facili da fare che da spiegare ;)

Ma torniamo a noi, è tempo di provare! Salvate tutto il salvabile e selezionate dal menù “File > Anteprima Pubblicazione > Flash”. Questo teoricamente è quello che dovreste ottenere:

AvoiderGame_Part1_201

Wow… ehm. Cool.

Come inizio di sicuro non farà schifo, meglio di niente. Però quello che noi vogliamo è che il nemico parta da sopra rispetto alla finestra di gioco, non a metà strada in questo modo! Ecco come faremo per aggiustare il tutto. Tornate al costruttore della classe Enemy e giocate con il valore iniziale della coordinata y. Ecco un esempio:

    public function Enemy()
    {
      x = 100;
      y = -15;
    }

Cambiate il valore, fate qualche prova, ricambiate i valori se non va bene, e dopo poco dovremmo aver raggiunto il nostro risultato senza problemi ;)

E adesso, iniziamo a far muovere il nostro caro nemico.


Diamo Vita al Nemico

Nonostante abbiamo scritto il codice riguardante il movimento del nemico, non abbiamo scritto il codice che dice al nemico di farlo. L’idea base da cui partiremo è quella di eseguire determinate azioni (vedi il movimento) ogni tot di tempo.

A differenza della soluzione optata da Frozen Haddock, noi faremo uso di uno strumento utilissimo che ActionScript3 ci mette a disposizione: la classe Timer.

Modifichiamo quindi il costruttore della classe principale (ormai avete capito che è AvoiderGame) in modo tale da creare una nuova istanza della classe Timer. Essendo una classe già scritta, non avremo bisogno di creare un nuovo file *.as. Ecco il codice:

    public function AvoiderGame()
    {
      enemy = new Enemy();
      addChild( enemy );

      gameTimer = new Timer( 25 );
    }

Notate che nell’istruzione gameTimer = new Timer( 25 ); c’è il valore 25 tra le parentesi. A differenza dell’altra classe abbiamo passato un parametro al metodo costruttore. In questo caso, il numero 25 indica il periodo del timer in millisecondi, ovvero ogni quanto il timer darà il segnale per poter fare qualcosa.

Quello che vogliamo è che il gameTimer, ogni 25 millesimi di secondo, muova il nostro personaggio. Per fare questo, proprio come avvenuto prima per “enemy” dobbiamo rendere la variabile gameTimer utilizzabile da tutta la classe principale:

package
{
  import flash.display.MovieClip;
  public class AvoiderGame extends MovieClip
  {
    public var enemy:Enemy;
    public var gameTimer:Timer;

    public function AvoiderGame()
    {
      enemy = new Enemy();
      addChild( enemy );

      gameTimer = new Timer( 25 );
    }
  }
}

Come potete notare, come successo per MovieClip, abbiamo importato le definizioni della classe timer tramite l’istruzione import flash.utils.Timer;

Se vi chiedete come faccia a sapere che si deve importare proprio flash.utils.Timer oppure flash.display.MovieClip, non vi preoccupate, ho controllato prima cosa dovevo importare e poi l’ho scritto. Insomma, non è un sapere “oscuro”.

Bene, adesso abbiamo un timer che fa qualcosa ogni 25 millesimi di secondo. Al momento non è connesso a nulla, quello che abbiamo è solamente il timer impostato con un periodo di 25 millisecondi. Ora diciamogli che deve muovere il nemico. Il codice è il seguente:

    public function AvoiderGame()
    {
      enemy = new Enemy();
      addChild( enemy );

      gameTimer = new Timer( 25 );
      gameTimer.addEventListener( TimerEvent.TIMER, moveEnemy );
    }

Abbiamo aggiunto questa riga, in cui usiamo il metodo “addEventListener”. A cosa serve quest’ultimo? Semplicemente, dice all’oggetto gameTimer di eseguire le azioni contenute nel metodo “moveEnemy” periodicamente.

Analizziamo meglio i parametri passati:

  • TimerEvent.TIMER : costante indicante che, appunto, l’azione da eseguire deve essere eseguita secondo il periodo specificato dal timer (25 millisecondi)
  • moveEnemy : è il metodo da eseguire.

Ma dove si trova questo metodo? Non temete, lo andiamo a definire ora. Per prima cosa importiamo la definizione degli eventi del Timer (ci serve per gli EventListener):

package
{
  import flash.display.MovieClip;
  import flash.utils.Timer;
  import flash.events.TimerEvent;
}

Ora dobbiamo definiamo il metodo vero e proprio:
  public class AvoiderGame extends MovieClip
  {
    public var enemy:Enemy;
    public var gameTimer:Timer;

    public function AvoiderGame()
    {
      enemy = new Enemy();
      addChild( enemy );

      gameTimer = new Timer( 25 );
      gameTimer.addEventListener( TimerEvent.TIMER, moveEnemy );
    }

    public function moveEnemy( timerEvent:TimerEvent ):void
    {

    }
  }

Come vedete, anche per moveEnemy abbiamo passato dei parametri tra parentesi. Il parametro timerEvent:Event è usato per passare le informazioni relative all’evento attraverso il quale si passa per arrivare alla funzione moveEnemy.

Ed ora, finalmente, l’ultimo passo.

Il nostro obiettivo era quello di far muovere il nemico. Abbiamo creato il timer con l’evento connesso, ora dobbiamo specificare cosa deve succedere precisamente ogni 25 millisecondi. A voi il codice:

    public function moveEnemy( timerEvent:TimerEvent ):void
    {
      enemy.moveDownABit();
    }

Esatto, stiamo usando l’oggetto “enemy” (nello specifico il metodo moveDownABit) permettendo così il suo movimento. Se dovessimo trasformare tutto questo in parole povere, potremmo dire che

Abbiamo creato un timer che ogni venticinque millisecondi esegue il metodo moveEnemy. A sua volta, il metodo moveEnemy contiene una chiamata a moveDownABit, dell’oggetto enemy, che muove il nemico sull’asse y. Come logica conseguenza di tutto ciò, ogni 25 millisecondi il nemico si muoverà di un tot specificato dal metodo moveDownABit.”

E anche stavolta spero d’esser stato chiaro.

Bene, adesso possiamo salvare tutto, e selezionare dal menù “File > Anteprima Pubblicazione > Flash”.

COSA? NON SUCCEDE NIENTE?

Tranquilli ragazzi. Ci siamo scordati di avviare il timer ;) (si, pensate a qualcosa tipo un cronometro.)

Per avviare il timer si richiama il metodo start dell’oggetto:

    public function AvoiderGame()
    {
      enemy = new Enemy();
      addChild( enemy );

      gameTimer = new Timer( 25 );
      gameTimer.addEventListener( TimerEvent.TIMER, moveEnemy );
      gameTimer.start();
    }

Salviamo tutto e proviamo il nostro lavoro. Ci siamo! Il nostro nemico si muove e segue la traiettoria specificata prima di sparire in fondo alla schermata.

Ora possiamo fare un altro passo avanti, aggiungendo un po di interattività. D’altronde parliamo di un gioco, mica di un filmato :D

Portiamo la capoccia nel gioco (un pò di interazione)

Dunque, per aggiungere un elemento di interattività nel nostro gioco introdurremo il personaggio comandato dal nostro giocatore, il nostro avatar. La procedura da seguire stavolta è molto simile a quella utilizzata per la creazione del nemico.

  • Creiamo un nuovo simbolo di tipo Clip Filmato, chiamato Avatar.
  • Disegnamolo (di certo non si creerà da solo)

AvoiderGame_Part1_23

Si, questo sarà il nostro avatar. Tenero, vero?

Citazione di Michael: “Non vi preoccupate se i vostri disegni non vi sembrano così belli come i miei. Dopotutto ho un GCSE in Graphic Design.”

Abbiamo il nostro disegno per l’Avatar, centrato nel punto di registrazione che ci serve. Abbiamo salvato il nostro file, cosa dobbiamo fare? Andiamo a creare un nuovo file ActionScript3 che salveremo nella cartella “Classi” che ormai conosciamo bene. Lo chiameremo Avatar.as.

Il contenuto del file?

package
{
  import flash.display.MovieClip;
  public class Avatar extends MovieClip
  {
    public function Avatar()
    {

    }
  }
}

Stessa spiaggia, stesso mare. Come potete vedere per l’avatar non è cambiato poi così tanto rispetto alla classe Enemy. A livello di struttura è tutto uguale! Ripetendo la procedura affrontata già per Enemy, effettuiamo il link dal simbolo nella libreria alla classe del file Actionscript3 appena creato.

Ma STOP. Decidiamo: cosa vogliamo far fare al nostro avatar? Dunque, per ora abbiamo deciso che seguirà il cursore del mouse. In un certo senso sarà un puntatore del mouse. Potendo gestire la posizione dell’avatar dalla classe principale, quindi, per ora qui abbiamo finito. Passiamo al file ActionScript3 della classe principale.

Ecco il codice come è cambiato (considerate da qua sotto le linee 4, 12 e 13):

  public class AvoiderGame extends MovieClip
  {
    public var enemy:Enemy;
    public var avatar:Avatar;
    public var gameTimer:Timer;

    public function AvoiderGame()
    {
      enemy = new Enemy();
      addChild( enemy );

      avatar = new Avatar();
      addChild( avatar );

      gameTimer = new Timer( 25 );
      gameTimer.addEventListener( TimerEvent.TIMER, moveEnemy );
      gameTimer.start();
    }

    public function moveEnemy( timerEvent:TimerEvent ):void
    {
      enemy.moveDownABit();
    }
  }

Se avviate il gioco adesso, noterete che l’avatar compare in alto a sinistra, la posizione base (0, 0). Per prima cosa quindi vogliamo che parta ovunque si trovi il cursore del mouse nell’istante iniziale del gioco. Flash ha due proprietà che possiamo usare per lo scopo: mouseX e mouseY. Le funzionalità di queste due proprietà… beh dai, penso che puoi indovinarle senza problemi.

Ora, ricordate ciò che abbiamo detto prima riguardo alle classi che “estendono” i MovieClip? Che hanno una proprietà “x” ed una “y” per la loro posizione. Da qui ad assegnare all’avatar la posizione del mouse sarà una passeggiata: basterà infatti assegnare i valori del mouse a quelli delle coordinate dell’avatar.

    public function AvoiderGame()
    {
      enemy = new Enemy();
      addChild( enemy );

      avatar = new Avatar();
      addChild( avatar );
      avatar.x = mouseX;
      avatar.y = mouseY;

      gameTimer = new Timer( 25 );
      gameTimer.addEventListener( TimerEvent.TIMER, moveEnemy );
      gameTimer.start();
    }

Appunto.

La proprietà “x” di avatar prenderà il valore della posizione attuale sull’asse x del mouse. Idem per l’asse y.

Se avviamo il nostro gioco, ora il nostro avatar apparirà esattamente nella posizione del mouse. Ora manca solo un’altra cosa: muovere l’avatar con il mouse.

Aggiorniamo il metodo moveEnemy della classe principale con questo codice:

    public function moveEnemy( timerEvent:TimerEvent ):void
    {
      enemy.moveDownABit();
      avatar.x = mouseX;
      avatar.y = mouseY;
    }

In questo modo il giocatore potrà muovere l’avatar nel livello. Ma attenzione ai nomi! moveEnemy adesso non sembra più molto adatto come appellativo per questo metodo. Cambiamolo in moveEnemyAndAvatar. Mi sembra più appropriato.
    public function moveEnemyAndAvatar( timerEvent:TimerEvent ):void
    {
      enemy.moveDownABit();
      avatar.x = mouseX;
      avatar.y = mouseY;
    }

E ricordiamoci di aggiornare anche l’aggiunta dell’EventListener:
      gameTimer.addEventListener( TimerEvent.TIMER, moveEnemyAndAvatar );

Salvate il gioco, avviate l’anteprima e gioite per la vostra gloria. Abbiamo creato qualcosa che inizia ad avere un accenno di interattività.

AvoiderGame_Part1_203

Diamo un senso alla parola “Avoider”

Il nostro gioco parte tranquillamente ma c’è qualcosa che ci turba. Quando il nostro simpatico avatar sbatte contro l’odiosa faccina sorridente, non succede nulla e tutto continua normalmente. Dobbiamo fare qualcosa per evitare ciò.

Come facciamo quindi a dire al sistema che “la faccina sorridente è un nemico”? Non elaboreremo metodi troppo complicati per questa prima parte della guida, ma ci occuperemo di un metodo molto utile (posseduto da tutti gli oggetti di tipo MovieClip o da tipi estesi del MovieClip) chiamato hitTestObject. Lo scopo di questo metodo è verificare se nell’istante dell’esecuzione del metodo il nostro MovieClip ne sta toccando un altro. Esattamente quello che serve per verificare la nostra prima “collisione”.

Ecco il codice che ci serve:

    public function moveEnemyAndAvatar( timerEvent:TimerEvent ):void
    {
      enemy.moveDownABit();
      avatar.x = mouseX;
      avatar.y = mouseY;

      if ( avatar.hitTestObject( enemy ) )
      {

      }
    }

Le nuove istruzioni inserite (il blocco if) dicono semplicemente: se l’oggetto avatar entra in collisione con l’oggetto enemy. allora esegui le istruzioni contenute nel blocco. Non essendoci niente tra le parentesi, al momento, non può accadere nulla.

Inoltre, dato che abbiamo aggiunto un sacco di logica in più rispetto a prima, dobbiamo rivalutare il nome del metodo. Prima era moveEnemy (muovi il nemico), poi moveEnemyAndAvatar (muovi il nemico e l’avatar). Sinceramente, non mi sembra il caso di adottare una blasfemia come moveEnemyAndAvatarAndAlsoCheckToSeeIfTheyHaveCollided ( muovi il nemico e l’avatar, inoltre controlla se questi due sono entrati in collisione).

Per questo utilizzeremo un metodo generico per identificare lo scoccare dell’intervallo del nostro timer. Un termine comune in questo ambito conosciuto come Tick. Cambiamo nome alla nostra funzione (ricordandoci di aggiornare il nome anche nell’aggiunta del Listener:

    public function onTick( timerEvent:TimerEvent ):void
    {
      enemy.moveDownABit();
      avatar.x = mouseX;
      avatar.y = mouseY;

      if ( avatar.hitTestObject( enemy ) )
      {

      }
    }

Sistemato questo problema torniamo a noi. Dicevamo, dovevamo fare qualcosa per fare in modo di terminare il gioco qualora l’avatar vada a sbattere contro il nemico. Possiamo adottare la soluzione più semplice: stoppare il timer del gioco appena un evento simile succeda. Ciò porterebbe a non eseguire più la nostra funzione onTick e quindi fermare il gioco.

Il codice è il seguente:

    public function onTick(event:TimerEvent):void {
      enemy.moveDownABit();
      avatar.x=mouseX;
      avatar.y=mouseY;

      if (avatar.hitTestObject(enemy)) {
        gameTimer.stop();
      }
    }

Salviamo tutto e proviamo il nostro gioco: non vi preoccupate, non siamo andati in crash, ma semplicemente abbiamo detto al sistema di stoppare tutto appena l’avatar entra in collisione con il nemico.

Conclusioni

Non credevo di riuscire ad arrivare alla fine di quest’articolo. Probabilmente neanche voi vero? Beh, abbiamo realizzato una prima basilare versione del nostro AvoiderGame. Di sicuro due cose ci sono chiare:

  • Il riconoscimento delle collisioni è TERRIBILE.
  • In futuro dovremo pensare a qualcosa come la pausa per non rendere odioso il nostro gioco.

Potete scaricare l’archivio con tutti i files per questo primo progetto da Qui.

Siamo andati abbastanza avanti, e tutto può sembrare molto difficile ed estremamente lungo. Certo, non è di certo una passeggiata quella che stiamo facendo, ma ora che abbiamo realizzato l’insieme delle “fondamenta” del nostro gioco (vedi la classe AvoiderGame) in futuro riusciremo a muoverci più agilmente ed avremo l’ambiente di sviluppo pronto.

Fate pratica delle varie tecniche spiegate e cercate di ottenere la padronanza di tutte quelle piccole azioni che se fatte velocemente dimezzano il tempo di lavoro.

Nei prossimi capitoli aggiungeremo delle features più avanzate: un orologio, la schermata di gameover, un sistema di punteggi, le vite del giocatore e tante altre cose interessanti.

Grazie per aver letto l’articolo e alla prossima parte!

Francesco Malatesta

  • Share/Bookmark