Pagine    Articoli    Prodotti    Forum    Cerca  
Nickname

Password


Non sei registrato?
Registrati a GPI qui!

Puoi anche attivare un vecchio utente GPI e chiedere una nuova password.
I Team

Mappa Team
I nostri utenti

Mappa Utenti
  Programmare un videogame Flash con Starling #5
Pubblicato da Andrea Venturi il 2012-12-05 20:44:41

“Eppur si muove”

 

L’argomento di questo breve tutorial riguarda una tecnica ampiamente usata nelle animazioni dagli anni 40 in poi e resa popolare in ambito videoludico da Moon Patrol nel 1982.

 

Come tutti avete ben capito, in questo tutorial parleremo del movimento parallasse (parallax scrolling).

 

Momento teoria

Cos'é il movimento di parallasse?

Una tecnica per dare un senso di scorrimento alla scena tramite l’utilizzo di immagini in movimento posizionate su livelli paralleli.

 

Quindi per sviluppare questa tecnica serve per prima cosa definire i livelli su cui giacciono le immagini (detti livelli di parallasse).

Applicare del movimento a questi livelli, ovviamente tutti nella stessa direzione e con modulo sempre minore in proporzione alla distanza dal punto di vista dell'utente.

 

Parallax

 

In parole semplici il livello più vicino all'osservatore si muoverà più velocemente rispetto a quello più lontano.

 

Per dare continuità al movimento, su ogni livello sono presenti due immagini continue ed uguali (nel nostro esempio il cielo stellato).
Ogni frame che viene disegnato si spostano le immagini e se ne controlla la posizione raggiunta, perchè quando la prima immagine avrà superato il bordo della visuale, quindi la visuale sarà interamente occupata dalla seconda immagine, riposizionate le due immagini nella posizione iniziale.

 

In questo modo andremo a creare un loop che darà l’impressione di continuità del movimento.

 

Per questo gioco useremo due livelli, il primo (quello più lontano dal punto di vista dell’utente) lo sfondo stellato del menù che si muoverà più lentamente, il secondo (quello più vicino) dei pianeti che si muoverà più velocemente.

 

 

 

Mano al codice

 

Prima di tutto sono andato ad aggiungere l'immagine del pianeta dentro la Texture Atlas.

 

SUN 

 

Nel mio esempio si chiama SUN.

 

Ho fatto rigenerare la png e l'xml, così è tutto pronto per iniziare.

 

Creiamo la classe BGLayer che estente Sprite nella cartella ogg.

 

Andiamo a creare quattro proprietà:

 

private var img1:Image;
private var img2:Image;
private var _livello:int;
private var _parallax:Number;

le due Image per i livelli di parallasse, un int che useremo per indicare quale livello di parallasse stiamo gestendo e un Number per memorizzare un fattore moltiplicativo che vedremo più avanti.

 

Il costruttore lo creiamo in modo tale da prendere un argomento di tipo int, valore che utilizzeremo per inizializzare la proprietà _livello.

 

Come sempre assegnamo un listener all'evento ADDED_TO_STAGE.

 

public function BGLayer(layer:int)
{
        super();
        _livello = layer;
        addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}

Nella gestione dell'evento andiamo a testare che livello stiamo creando e in base a questa informazione andiamo a disegnare e posizionare lo sfondo stellare (livello 1) o i pianeti (livello 2).

 

private function onAddedToStage(e:Event):void
{
        removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
        if (_livello == 1)
        {
                img1 = new Image(Assets.getAtlas().getTexture("BGMENU"));
                img2 = new Image(Assets.getAtlas().getTexture("BGMENU"));
                
                img1.x = 0;
                //una di seguito all'altra
                img2.x = img1.width;
                
                //allineo in basso allo schermo
                img1.y = stage.stageHeight - img1.height;
                img2.y = stage.stageHeight - img1.height;
        }
        else
        {
                img1 = new Image(Assets.getAtlas().getTexture("SUN"));
                img2 = new Image(Assets.getAtlas().getTexture("SUN"));
                
                //scalo della metà
                img1.scaleX = 0.5;
                img1.scaleY = 0.5;
                //posiziono appena fuori dello stage
                img1.x = stage.stageWidth + img1.width;
                //posiziono il primo nella meta' sopra dello schermo
                img1.y = stage.stageHeight >> 4;
                
                
                //scalo di 3/4
                img2.scaleX = 0.75;
                img2.scaleY = 0.75;
                //posiziono di uno stage (di lunghezza) dopo il primo pianeta
                img2.x = img1.x + (stage.stageWidth)+img2.width;
                //posiziono nella metà inferiore dello schermo
                img2.y = stage.stageHeight * 0.75;
                //ruoto
                img2.rotation = 90;
        }
        
        addChild(img1);
        addChild(img2);
}

Ovviamente il numero di livelli di parallasse, il loro posizionamento e soprattutto il loro comportamento può essere complicato a vostro piacimento.

Procediamo con il creare il setter e il getter per la proprietà _parallax

 

public function get parallax():Number
{
    return _parallax;
}
 
public function set parallax(value:Number):void
{
    _parallax = value;
}

Errori a parte questa classe si può considerare chiusa.

 

A questo punto serve una classe che gestisca il movimento dei livelli di parallasse, quindi andiamo a crearla sempre nella cartella ogg e chiamiamola BackGroud, facciamola estendere Sprite.

 

Questa classe deve avere tre proprietà: i due livelli di parallasse di tipo BGLayer e la velocità di globale tipo Number.

 

private var bgLayer1:BGLayer;
private var bgLayer2:BGLayer;
private var _speed:Number;

Creiamo il costruttore con il listener all'evento ADDED_TO_STAGE nel costruttore

 

public function BackGroud()
{
        super();
        addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}

e nella getione di questo evento, andiamo a istanziare e disegnare i due livelli di parallasse

 

private function onAddedToStage(e:Event):void
{
        removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
        
        bgLayer1 = new BGLayer(1);
        //indica che deve animarsi ad un quindicesimo della velocità dell'astronave
        bgLayer1.parallax = 0.02;
        addChild(bgLayer1);
        
        bgLayer2 = new BGLayer(2);
        //indica che deve animarsi dieci volte la velocità dello sfondo
        bgLayer2.parallax = 0.2;
        addChild(bgLayer2);
        
        addEventListener(Event.ENTER_FRAME, onEnterFrame);
}

da notare che il settaggio della proprietà parallax, la useremo come fattore moltiplicativo della velocità.

 

Per semplicità andremo ad impostare la velocità globale a 10; con velocità globale implicitamente indichiamo la velocità dell’astronave.

 

Quindi andiamo a scrive il getter e il setter della _speed

 

public function get speed():Number
{
        return _speed;
}
 
public function set speed(value:Number):void
{
        _speed = value;
}

ed infine andiamo a gestire l'evento Enter_Frame, dove andiamo a muovere i livelli di parallasse e qualora siano arrivati a fine corsa li riporteremo alla loro posizione iniziale

 

private function onEnterFrame(e:Event):void
{
        bgLayer1.x -= Math.ceil(_speed * bgLayer1.parallax);
        if (bgLayer1.x < -stage.stageWidth) bgLayer1.x = 0;
        
        bgLayer2.x -= Math.ceil(_speed * bgLayer2.parallax);
        if (bgLayer2.x < -(stage.stageWidth << 2)) bgLayer2.x = stage.stageWidth;
}

Per ammirare il nostro operato basterà andare nella classe StarField per aggiungere un'istanza di BackGroud, quindi apriamo la suddetta classe e creiamo la proprietà

 

private var bg:BackGroud;

e nella funzione drawScreen andiamo ad istanziarla e valoriziamo la speed

 

bg = new BackGroud();
bg.speed = 10;
addChild(bg);

A questo punto provate a compilare, in assenza di errori, premete su play per vedere lo sfondo fatto dai due livelli di parallasse.

 

 

.

.

.

 

 

Ma il tutorial non è finito, c’é qualcosa di non corretto, se riflettete bene ci siamo dimenticati qualcosa...

 

Un occhio attento noterebbe che anche quando sono sulla schermata del menù il BackGround si muove.

(mettete un trace per verificarlo)

 

Quindi bisogna intervenire!

 

Per prima cosa andiamo a togliere il listener dell'evento ENTER_FRAME nella funzione ADDED_TO_STAGE della classe BackGround.

 

Questo perchè non si devono muovere i livelli di parallasse se sono nel menù e dato che il gioco inizia sempre dal menù questa riga non serve, anzi ci fa sprecare risorse.

 

Andiamo a creare le due funzioni inizialize e disable, sempre nella classe backGround, per mettere e togliere il listener all'evento ENTER_FRAME

 

public function initialize():void
{
        addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
 
public function disable():void
{
        removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}

Come ultima cosa ritorniamo nella classe StarField e andiamo ad arricchire le funzioni inizialize con

 

bg.initialize();

e disable con

 

if (bg != null)
{
        bg.disable();
}

Fate attenzione alla guardia dell'if, vi ricordo che questa funzione viene chiamata prima che venga istanziata la proprietà bg, quindi quell’oggetto è null.

 

Compilate e provate.


Ed ecco il link al repositiry

Campagne crowfunding

Just One Line
Siamo presenti su

     
Copyright ©2016 - Manifesto - Privacy - Termini di Servizio - Community - Collaboratori - Contattaci