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

Ci siamo quasi… siamo all’undicesima lezione e a breve avremo finito al 100% il nostro primo gioco in Flash. La volta scorsa abbiamo aggiunto un elemento davvero importante: la progressione. Inserendo nuovi livelli abbiamo fatto in modo di creare delle situazioni in cui il giocatore non riesce a terminare il gioco in una sola volta.

Oggi introdurremo un concetto molto utile: il salvataggio di informazioni per poterle riusare successivamente in futuro. Ovviamente applicheremo questa nozione al nostro gioco, memorizzando (per ogni utente che gioca) il suo punteggio migliore. Per raggiungere il nostro obiettivo useremo un oggetto specifico, chiamato SharedObject.

Come realizzare il tutto? Continuate a leggere il nostro articolo.

Prendete i file di backup della lezione precedente (nell’articolo precedente) oppure prendete i vostri file di backup e partiamo!


Una cosa Davvero Semplice

Fortunatamente per voi, posso dire da subito che la realizzabilità di questa caratteristica è davvero semplice rispetto a tante altre: prevedo un articolo più corto delle volte precedenti. Partiamo subito con il lavoro e apriamo il nostro file .fla.

Nella libreria, aprite la GameOverScreen ed entrate quindi in modalità modifica. Aggiungete due box per il testo: una sarà statica, e riporterà qualcosa come “Punteggio Migliore: “, l’altra invece dinamica ospiterà, appunto, il punteggio migliore (numerico). Dategli come nome d’istanza “bestScore”.

AvoiderGame_Part11_01

Qualcosa del genere, per intenderci ;)

I dati che noi salveremo grazie all’oggetto SharedObject verranno salvati in una cartella ben precisa del sistema operativo. Per salvare o accedere a questi dati, come già detto, useremo l’oggetto SharedObject in svariati modi. Per fare le cose in maniera più semplice, aggiungeremo tutto il codice necessario nel file GameOverScreen.as.

Per prima cosa quindi importiamo l’oggetto SharedObject e dichiariamone un istanza a livello di classe:

package
{
  import flash.display.MovieClip;
  import flash.display.SimpleButton;
  import flash.events.MouseEvent;
  import flash.text.TextField;
  import flash.ui.Mouse;
  import flash.net.SharedObject;
  public class GameOverScreen extends MovieClip
  {
    public var sharedObject:SharedObject;

Il passo successivo è “collegare” quest’oggetto al contenuto presente sul nostro hard disk. Ovviamente considerate che, come il nome può suggerire, questo è un oggetto “condiviso”. Vuol dire che può essere utilizzato anche da altre applicazioni, per cui dovete scegliere un nome ben preciso che difficilmente verrà usato da altri. Noi per esempio abbiamo deciso “mjwScores”. Traduciamo il ragionamento in codice ed ecco cosa abbiamo:
public function GameOverScreen()
{
  Mouse.show();
  restartButton.addEventListener( MouseEvent.CLICK, onClickRestart );
  sharedObject = SharedObject.getLocal( "mjwScores" );
}

Notate che, a sinistra dell’uguale abbiamo “sharedObject” con la s piccola, mentre a destra “SharedObject” con la S grande. So che probabilmente l’avete già capito, ma ricordate che a sinistra abbiamo l’oggetto, mentre a destra abbiamo la classe ;)

getLocal è invece una funzione: proprio come abbiamo potuto realizzare delle variabili statiche (utilizzabili senza creare un istanza della classe) possiamo trovare delle funzioni statiche. Il parametro che passiamo tra le parentesi è una stringa indicante il nome dell’identificativo del nostro punteggio. “mjwScores”, appunto.

Piccola Nota: ritornando un secondo al discorso di prima, non scervellatevi troppo se il nome scelto per memorizzare i dati non sembra così “originale”: considerate che flash esegue un controllo sia sul nome della variabile che sull’URL della pagina dove si trova il vostro gioco ;) Siti come Newgrounds e Kongregate hanno inoltre dei sistemi di protezione ulteriori.

Ora che abbiamo l’accesso a questa risorsa sul nostro hard disk, mettiamoci qualcosa dentro! L’istanza del nostro SharedObject possiede una variabile chiamata “data” nella quale possiamo mettere tutto ciò che vogliamo. Nel codice di esempio potete capire al volo di cosa parlo:

public function setFinalScore( scoreValue:Number ):void
{
  finalScore.text = scoreValue.toString();
  sharedObject.data.bestScore = scoreValue;
}

Potete aggiungere al vostro oggetto quello che volete, semplicemente con la formula

sharedObject.data.nome_che_volete = valore_che_volete

Semplicissimo, vero? ;) Dovete tenere in mente una cosa però: fin quando non chiuderete il file swf (uscendo dal gioco o dalla pagina dove si trova) le modifiche non verranno salvate. Possiamo tranquillamente aggirare quest’ostacolo aggiungendo una semplice istruzione: sharedObject.flush().

public function setFinalScore( scoreValue:Number ):void
{
  finalScore.text = scoreValue.toString();
  sharedObject.data.bestScore = scoreValue;
  sharedObject.flush();
}

Questo permetterà istantaneamente il salvataggio dell’informazione. Ora che l’abbiamo salvata però dobbiamo mostrarla, altrimenti che lo usiamo a fare questo oggetto?
public function setFinalScore( scoreValue:Number ):void
{
  finalScore.text = scoreValue.toString();
  sharedObject.data.bestScore = scoreValue;
  bestScore.text = sharedObject.data.bestScore.toString();
  sharedObject.flush();
}

Salvando e testando il gioco, il migliore punteggio equivarrà sempre a quello della partita appena svolta.

AvoiderGame_Part11_02

La cosa non può rimanere così semplice, per cui dobbiamo pensare ad un approccio diverso! Il punteggio migliore deve essere aggiornato solo se realmente migliore di quello precedente! Per questo motivo dobbiamo aggiungere qualche controllo specifico nel metodo setFinalScore():

public function setFinalScore( scoreValue:Number ):void
{
  finalScore.text = scoreValue.toString();
  if ( scoreValue > sharedObject.data.bestScore )
  {
    sharedObject.data.bestScore = scoreValue;
  }
  bestScore.text = sharedObject.data.bestScore.toString();
  sharedObject.flush();
}

Come potete vedere “scoreValue” è il nostro punteggio attuale, che viene paragonato al punteggio migliore attualmente in memoria. Se è realmente maggiore, quindi il migliore, viene assegnato alla variabile data dell’oggetto sharedObject.

Altrimenti tutto rimane com’è e viene visualizzato il punteggio migliore precedente. Insomma, una cosa facile facile. Ecco il nostro risultato su schermo:

AvoiderGame_Part11_03

In linea di massima quindi funziona tutto, però c’è una cosa che dovete contare. Ragionate con me: eseguite per la prima volta il gioco, quindi non abbiamo nessun valore per il punteggio migliore! Cosa succede se, a fine partita, andiamo a controllare il punteggio precedente (che non esiste) ? ERRORE!

Nello specifico l’errore sarà il seguente:

 TypeError: Error #1010: A term is undefined and has no properties.

Che sbadati. Correggiamo immediatamente questo orrore!
public function setFinalScore( scoreValue:Number ):void
{
  finalScore.text = scoreValue.toString();
  if ( sharedObject.data.bestScore == null )
  {
    sharedObject.data.bestScore = scoreValue;
  }
  else if ( scoreValue > sharedObject.data.bestScore )
  {
    sharedObject.data.bestScore = scoreValue;
  }
  bestScore.text = sharedObject.data.bestScore.toString();
  sharedObject.flush();
}

Come potete vedere ho aggiunto un controllo, verificando innanzitutto se sharedObject.data.bestScore è uguale a null (ovvero è la prima volta che giochiamo). Quindi provvediamo a fare gli altri controlli precedentemente scritti. È cambiato molto poco in realtà :)

Testate tutto e provate, ora funzionerà alla perfezione. Chiudete tutto e riaprite il file, ri-testando il vostro gioco. Il punteggio migliore sarà ancora lì, memorizzato ;)

AvoiderGame_Part11_04

Et voilà ;)


Dettagli sui Salvataggi

Penso che, da buoni sviluppatori che siete (o volete diventare), avete qualche curiosità riguardante questi salvataggi tramite lo SharedObject. Beh, in questa parte dell’articolo riporterò un po’ di informazioni sicuramente utili.

Per prima cosa, ecco dove i dati dell’oggetto vengono memorizzati:

  • WindowsXP: C:\Documents and Settings\nomeUtente\Application data\Macromedia\Flash Player\#SharedObjects
  • Windows Vista: C:\Utenti\nomeUtente\AppData\Roaming\Macromedia\Flash Player\#SharedObjects
  • Mac OS/X: ~/Library/Preferences/Macromedia/Flash Player/#SharedObjects/
  • Unix/Linux: ~/.macromedia/Flash_Player/#SharedObjects/

Queste sono le cartelle utilizzate di default.

Considerate, inoltre, che se contate di memorizzare una grande mole di dati potreste avere dei problemi: flash, infatti, permette al massimo una dimensione dei file memorizzati di 100KB per il vostro file .swf. Fortunatamente, abbiamo la possibilità di individuare per tempo questi errori.

Guardate di nuovo l’errore uscito precedentemente: è stato “lanciato” un TypeError:

 TypeError: Error #1010: A term is undefined and has no properties.

Prima di concludere questo articolo, quindi, impareremo ad utilizzare uno strumento decisamente utile per “rilevare” gli errori che vengono lanciati in determinati contesti: il blocco “try – catch”. È proprio dentro questo blocco che gestiamo la possibilità di ottenere degli errori. Prima il codice e poi la spiegazione:
public function setFinalScore( scoreValue:Number ):void
{
  finalScore.text = scoreValue.toString();
  try
  {
    if ( sharedObject.data.bestScore == null )
    {
      sharedObject.data.bestScore = scoreValue;
    }
    else if ( scoreValue > sharedObject.data.bestScore )
    {
      sharedObject.data.bestScore = scoreValue;
    }
    bestScore.text = sharedObject.data.bestScore.toString();
    sharedObject.flush();
  }
  catch ( sharedObjectError:Error )
  {
    trace( "Caught this error:", sharedObjectError.name, sharedObjectError.message );
  }
}

Ecco cosa succede: flash tenta di eseguire tutto il codice che si trova nel blocco “try”. Nel caso vengono fuori degli errori di molteplice natura, allora viene eseguito il codice che si trova nel blocco “catch”, che in questo caso serve solo (tramite trace) a riportare nella console di output il testo dell’errore.

Una soluzione abbastanza sicura, quindi. In più, nel caso ci dovessero essere dei problemi, aggiungiamo quest’altra riga di codice al blocco catch:

catch ( sharedObjectError:Error )
{
  trace( "Caught this error:", sharedObjectError.name, sharedObjectError.message );
  bestScore.text = "???";
}

In questo modo, nel caso ci siano dei problemi (raramente se ne verificheranno in questo caso) al posto del punteggio migliore ci ritroveremo dei punti interrogativi, per segnalare un problema in fase di lettura. Ripeto, sarà molto, molto raro che accada.

AvoiderGame_Part11_06

Una schermata che difficilmente vedremo.


Sfide

Oltre al punteggio migliore c’è anche altro che è possibile mostrare su schermo: il miglior tempo o magari anche il numero del livello più alto al quale siamo riusciti ad arrivare. Non dovrebbe essere difficile! O ancora, si potrebbe memorizzare il numero del livello attuale per riproporlo la prossima volta che il giocatore giocherà al nostro capolavoro!

Anche oggi ce l’abbiamo fatta. Ormai manca solo l’ultima lezione e dopodiché questa piccola ma piacevole avventura sarà terminata. Scaricate da Qui i file della lezione di oggi e aspettateci nel prossimo articolo, nel quale parleremo di uno strumento davvero potente: il Garbage Collector.

Ciao!

  • Share/Bookmark