Realizzare Asteroids [parte 4]

La caratteristica che rese famoso l’originale gioco Asteroids rilasciato da Atari nel 1979 è l’inerzia.

Un corpo nello Spazio conserva il suo stato di quiete o di moto rettilineo uniforme fino a che non interviene una forza esterna a modificarne lo stato. I programmatori del gioco originale furono dei geni a prevedere questo comportamento in un gioco ambientato nello Spazio.

Per applicare un comportamento simile alla nostra astronave non ci basta più il valore della velocità e quello della rotazione, dovremo conservare anche i valori di spinta orizzontale e verticale.

Quando l’utente premerà il tasto freccia su sulla tastiera modificherà i valori di spinta in base alla direzione cui punta l’Astronave. Per rallentare dovrà girare l’Astronave nella direzione contraria a quella in cui si muove e accelerare.

Ricalcolare i valori di seno e coseno ogni volta che l’utente accelera potrebbe richiedere uno sforzo eccessivo a Flash Player, così ho deciso che la prima cosa da fare è precalcolare i valori che ci serviranno.

Precalcolare i valori di sin e cos

Apriamo la Classe Player.as e cominciamo a modificarla. Eliminiamo la dichiarazione della Variabile _speed, che non useremo più, e inizializziamo quattro nuove Variabili:

private var _boostX:Number;
private var _boostY:Number;
private var _sinArray:Object = {};
private var _cosArray:Object = {};

Le Variabili _boostX e _boostY rappresentano la spinta orizzontale e la spinta verticale dell’Astronave in ogni istante.

I due Array _sinArray e _cosArray servono a memorizzare il seno e il coseno dei vari angoli così da non doverli calcolare ogni volta.

All’interno del Metodo Costruttore dobbiamo inserire i valori iniziali di queste Variabili, il Metodo Costruttore adesso ha questo aspetto:

public function Player(x:int = 100,y:int = 100,color:uint = 0x006699) {
    _color = color;
    this.x = x;
    this.y = y;
    _boostX = 0;
    _boostY = 0;
    precalcola();
    this.addChild(new Astronave(_color, 16));
}

Le Variabili _boostX e _boostY hanno valore zero perché l’Astronave all’inizio del gioco si trova in uno stato di quiete. Il Metodo precalcola serve a calcolare tutti i valori da memorizzare negli Array _cosArray e _sinArray, inseriremo questo Metodo nella stessa Classe:

private function precalcola() {
    for (var i = 0; i <= 360; i+=10) {
        _sinArray[i] = Math.round(Math.sin(g2r(i-90))*1000)/1000;
        _cosArray[i] = Math.round(Math.cos(g2r(i-90))*1000)/1000;
    }
}

Utilizzeremo i valori precalcolati invece di utilizzare Math.cos e Math.sin.

Metodi “accelera” e “decelera”

Visto che non abbiamo più una Variabile _speed nella Classe Player dobbiamo evitare di riferirci a questa dall’interno di altre Classi. All’interno del Metodo goOn è necessaria una piccola modifica. Ecco come diventa il Metodo goOn:

private function goOn(e:TimerEvent) {
    if (_keyDown[39]) {
        _p.ruota('orario');
    } else if (_keyDown[37]) {
        _p.ruota('antiorario');
    }
    if (_keyDown[38]) {
        _p.accelera();
    } else {
        _p.decelera();
    }
    _p.muovi();
}

Adesso torniamo alla Classe Player e inseriamo questi due Metodi:

public function accelera() {
    var r = (this.rotation+360)%360;
    _boostX += _cosArray[r];
    _boostY += _sinArray[r];
}
public function decelera() {
}

Il Metodo accelera modifica la spinta orizzontale e la spinta verticale dell’Astronave, per utilizzare questi valori dobbiamo modificare anche il Metodo muovi:

public function muovi() {
    this.x += _boostX;
    this.y += _boostY;
    this.x = Math.abs((this.x+stage.stageWidth)%stage.stageWidth);
    this.y = Math.abs((this.y+stage.stageHeight)%stage.stageHeight);
}

A questo punto abbiamo una completa gestione dell’inerzia. Questo è il risultato fino a questo punto:

No flash, please!

Purtroppo Adobe Flash Player non è più benvoluto come una volta, per questo motivo ho disabilitato tutte le applicazioni Flash presenti sul sito. Se vuoi puoi comunque scaricare il file SWF che si trovava qui, clicca qui per far partire il download

Gestione dell’attrito

Sebbene il risultato ottenuto sia abbastanza buono, vorrei completare questa lezione inserendo una gestione dell’attrito. In pratica si tratta di rallentare il moto dell’Astronave per evitare che una spinta iniziale dia inizio ad un moto senza fine.

Alcuni amici mi hanno fatto notare che se l’Astronave si trova nello Spazio non dovrebbe esserci nessun attrito… ho risposto che l’Astronave si trova in un campo di meteoriti e sicuramente intorno a lei non c’è il vuoto, ma del sottile pulviscolo, quindi l’idea di aggiungere attrito non è troppo assurda.

Ad ogni modo, il sistema che ho pensato di adottare è questo:

public function decelera() {
    _boostX *= 0.95;
    _boostY *= 0.95;
}

In pratica la spinta orizzontale e quella verticale si riducono progressivamente del 5%, fino a raggiungere valori prossimi allo zero.

Ecco cosa abbiamo fino ad ora:

No flash, please!

Purtroppo Adobe Flash Player non è più benvoluto come una volta, per questo motivo ho disabilitato tutte le applicazioni Flash presenti sul sito. Se vuoi puoi comunque scaricare il file SWF che si trovava qui, clicca qui per far partire il download

Questo mi sembra un movimento abbastanza soddisfacente, ho deciso di tenerlo e nel prossimo tutorial andremo finalmente avanti con gli altri elementi.

Se volete, potere scaricare tutti i file creati fino a questo punto utilizzando il form qui sotto:

Inserisci nome e indirizzo email per iscriverti alla mia newsletter e ricevere il file immediatamente.
In breve: i dati inseriti in questo modulo saranno utilizzati per inviarti il link per scaricare il file che desideri, saranno conservati da un servizio esterno che si chiama MailChimp e in qualsiasi momento potrai cancellare la tua iscrizione al seguente link: https://danielealessandra.us7.list-manage.com/unsubscribe?u=546bebc381e525372d2120083&id=326af7d230.

Puoi leggere l'informativa completa cliccando sul link Privacy Policy che trovi dovunque su questa pagina, e comunque visitando in qualsiasi momento l'indirizzo https://www.danielealessandra.com/privacy-policy/
Ho letto e accetto l’informativa sulla privacy.

Potrebbero interessarti anche...

3 Risposte

  1. Andrea Marchioni ha detto:

    Ciao Daniele,
    ho un altra domanda, perche` in questa riga

    _sinArray[i] = Math.round(Math.sin(g2r(i-90))*1000)/1000;
    _cosArray[i] = Math.round(Math.cos(g2r(i-90))*1000)/1000;moltipliche per 1000 e poi dividi per 1000 ??grazie per la tua disponibilita`Andrea

    • Daniele Alessandra ha detto:

      Questa è un po’ sporca, ma mi serve arrotondare a massimo tre cifre decimali…

      Numero casuale -> Moltiplicato mille -> Arrotondato -> Diviso mille

      Se viene generato un numero troppo lungo, ad esempio:

      2,3691472581234569871236978

      In questo modo diventa semplicemente:

      2,369

      Più facile da gestire, meno sforzo per tutti…

      • Andrea Marchioni ha detto:

         Grazie Daniele per la risposta,
        Sono andato in debug e ho visto che la funzione Round quando lavora con numeri decimali tipo : 0.17364817766693036 restituisce zero e ora capisco il perche` tu hai dovuto fare questo work around.
        Scusa potevo mettermi ieri in debug e capirlo da me senza disturbarti ma ero impegnato su altri parti del gioco.
        Grazie moltissimo per la tua disponibilita` ripeto il lavoro che hai fatto e` utilissimo per me.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.