Elimina un'immagine con un effetto vento personalizzato

Due volte al mese, rivisitiamo alcuni dei post preferiti dei nostri lettori da tutta la storia di Activetuts +. Questo tutorial è stato pubblicato per la prima volta nel marzo 2010.

In questo tutorial, creeremo una classe personalizzata che spezza un'immagine in mille pezzi e simula un vento che li respinge. Ho creato questo progetto esclusivamente con AS3 e FlashDevelop - Flash non richiesto!


Anteprima del risultato finale

Diamo un'occhiata al risultato finale su cui lavoreremo. Vai avanti e fai clic ovunque all'interno del file SWF:


Introduzione rapida a FlashDevelop

FlashDevelop è un editor di codice gratuito per Flash e Flex. Puoi usarlo per modificare i tuoi file di classe quando lavori con il software Flash, oppure puoi creare un progetto AS3 che non richiede affatto Flash - ed è esattamente ciò che faremo in questo tutorial.

Quindi scarica FlashDevelop e installalo. Sfortunatamente, FlashDevelop funziona solo su Windows. Le alternative Mac includono FDT e Flex Builder, anche se nessuno dei due è gratuito. Puoi usare Flash in sé e ti spiegherò come farlo mentre procediamo.


Passaggio 1: crea un nuovo progetto

Apri FlashDevelop e fai clic su Progetto> Nuovo progetto?


Passaggio 2: configurazione

Scegli Actionscript 3> Progetto AS3. Per il nome del progetto inserito in "WindEffect". Per la posizione, fare clic e accedere alla cartella in cui si desidera salvarla. Lasciare selezionata la casella di controllo "Crea directory per progetto" e fare clic su OK.

Se si desidera utilizzare Flash CS3 / CS4, creare un nuovo file Flash e impostare la larghezza e l'altezza dello stage su 550x250px, impostare il colore dello sfondo su nero. Chiamalo "windEffect.fla" e salvalo ovunque ti piaccia.


Passaggio 3: sposta l'immagine sorgente

Per FlashDevelop, apri la directory del progetto e copia o trascina windEffect.jpg dal download sorgente (collegato nella parte superiore della pagina) nella cartella \ bin \.

Per Flash, copia o trascina windEffect.jpg dal download di origine nella stessa cartella in cui hai windEffect.fla.


Passaggio 4: installare TweenLite

Utilizzeremo TweenLite di Greensock per l'interpolazione. Puoi scaricare l'ultima versione del componente qui; L'ho incluso anche nel download sorgente.

Per FlashDevelop, vai avanti e copia o trascina greensock.swc dal download sorgente nella cartella \ lib \ per questo progetto.

Da FlashDevelop, fare clic su Visualizza> Gestione progetti


Passaggio 5: Libreria esterna

Sempre in FlashDevelop, fai clic sul segno "+" a sinistra della cartella lib per espanderlo. Fare clic con il tasto destro del mouse su greensock.swc e selezionare Aggiungi alla libreria.

Per Flash, copia o trascina la cartella \ com \ dal download di origine nella stessa cartella del file windEffect.fla.


Passaggio 6: la classe del documento

Per FlashDevelop, riaprire il project manager (fare riferimento al passaggio 4), espandere la cartella \ src \ e fare doppio clic su Main.as. Sotto le importazioni e subito sopra la definizione della classe, aggiungere il seguente tag metadata per impostare le proprietà dello stage:

[SWF (larghezza = 550, altezza = 250, frameRate = 30, backgroundColor = 0)]

All'interno del metodo init () dopo il punto di inserimento del commento, aggiungere il seguente codice:

 stage.scaleMode = StageScaleMode.NO_SCALE; // non estendere l'effetto var di stage: WindEffect = new WindEffect ('windEffect.jpg'); // creeremo presto la classe WindEffect addChild (effect);

Questo è tutto per la classe del documento principale.

Per Flash, crea una nuova classe Main.as nella stessa cartella del tuo progetto. Assicurati che la classe Main.as si trovi nella stessa cartella del fla. & cartella com. Aggiungi le seguenti linee:

pacchetto import flash.display.Sprite; import flash.display.StageScaleMode; import flash.events.Event; public class Main extends Sprite public function Main (): void if (stage) init (); else addEventListener (Event.ADDED_TO_STAGE, init);  funzione privata init (e: Event = null): void removeEventListener (Event.ADDED_TO_STAGE, init); stage.scaleMode = StageScaleMode.NO_SCALE; // non estendere l'effetto var di stage: WindEffect = new WindEffect ('windEffect.jpg'); // creeremo presto la classe WindEffect addChild (effect); 

Apri Flash e assegna "Main" come classe Document.

(Non sei sicuro di cosa si tratta? Leggi questa breve introduzione all'uso di una classe di documenti.)

Se provi a farlo adesso, riceverai un errore poiché non abbiamo ancora creato la classe WindEffect. Assicurati di salvare il file e lasciarlo per ora.


Passaggio 7: creare la classe WindEffect

Per FlashDevelop, fare clic su Visualizza> Gestione progetti, fare clic con il tasto destro del mouse sulla cartella \ src \ e selezionare Aggiungi> Nuova classe.


Passaggio 8: impostazione della classe

Assegna un nome alla classe WindEffect, fai clic sul pulsante Sfoglia per la classe base e inserisci flash.display.Sprite. Premi OK per completare.


Passaggio 9: importazione di altre classi

Aggiungi tutte le importazioni necessarie all'interno delle parentesi del pacchetto subito sotto 'import flash.display.Sprite;' e prima della definizione della classe. Fai clic su Salva.

import com.greensock.easing.Strong; import com.greensock.TweenLite; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Loader; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Point; import flash.geom.Rectangle; import flash.net.URLRequest;

Per Flash, crea un nuovo file ActionScript, chiamalo "WindEffect.as" e salvalo nella stessa directory che hai utilizzato. Dovrebbe essere proprio accanto al fla. file, cartella com e Main.as.

Aggiungi il seguente codice:

package import com.greensock.easing.Strong; import com.greensock.TweenLite; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Loader; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Point; import flash.geom.Rectangle; import flash.net.URLRequest; public class WindEffect estende Sprite public function WindEffect () 

Passaggio 10: aggiunta di una variabile di istanza

Aggiungi una variabile privata chiamata "_pictureArray". Questa è l'unica variabile che avremo in questa classe. Il suo scopo principale è quello di mantenere i riferimenti a tutti i piccoli sprite che contengono i piccoli pezzi della foto una volta che sono stati suddivisi.

Aggiungi la seguente riga di codice tra parentesi
della classe:

public class WindEffect estende Sprite // questo ospiterà tutti i pezzi dell'immagine che animeremo. private var _pictureArray: Array; 

Passaggio 11: aggiungere il costruttore

Aggiungere le seguenti righe dopo la dichiarazione _pictureArray:

public class WindEffect estende Sprite // questo ospiterà tutti i pezzi dell'immagine che animeremo. private var _pictureArray: Array; funzione pubblica WindEffect ($ url: String) // chiamiamo semplicemente l'immagine di carico nel costruttore loadPicture ($ url); 

Passaggio 12: accedi all'immagine

All'interno del metodo loadPicture () chiamato dal metodo del costruttore, istanziamo un loader per caricare windEffect.jpg. Aggiungiamo anche un listener di eventi COMPLETO per ascoltare quando il caricamento è completo.

Aggiungere le seguenti righe di codice dopo il metodo WindEffect (). (Nota che il parametro "$ url" è il percorso dell'immagine che stiamo caricando passato da Main.as.)

private function loadPicture ($ url: String): void // creiamo un loader con gli ascoltatori per caricare l'immagine sorgente che stiamo usando. // e quindi carichiamo l'immagine. var loader: Loader = new Loader; loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onLoadComplete); // quando è caricato, chiama la funzione onLoadComplete () loader.load (new URLRequest ($ url)); 

Passaggio 13: caricamento

Dopo che l'immagine è stata importata correttamente, viene chiamato questo metodo. Aggiungi le seguenti righe di codice dopo il metodo loadPicture () e salva il file.

funzione privata onLoadComplete (e: Event): void // per test addChild (e.target.content); 

Step 14: Test One

Vai avanti e premi CTRL + Invio sulla tua tastiera. Dovrebbe funzionare e l'immagine dovrebbe trovarsi nell'angolo in alto a sinistra dello stage.

Ora che abbiamo verificato il corretto caricamento, rimuovi il metodo addChild e sostituiscilo con il seguente codice:

createEffect (e.target.content);

La tua classe WindEffect dovrebbe essere simile a questa:

package import com.greensock.easing.Strong; import com.greensock.TweenLite; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Loader; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Point; import flash.geom.Rectangle; import flash.net.URLRequest; [SWF (larghezza = 550, altezza = 250, frameRate = 30, backgroundColor = 0)] public class WindEffect estende Sprite private var _pictureArray: Array; funzione pubblica WindEffect ($ url: String) loadPicture ($ url); 
 private function loadPicture ($ url: String): void var loader: Loader = new Loader; loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onLoadComplete); loader.load (new URLRequest ($ url));  funzione privata onLoadComplete (e: Event): void createEffect (e.target.content); 

Passaggio 15: impostare le variabili

Il metodo createEffect () prenderà il parametro image che è essenzialmente un bitmap e lo suddividerà in 1250 pezzi.

Per prima cosa calcoliamo le posizioni x e y per centrare l'immagine sul palco. Li salviamo in variabili locali chiamate centerWidth e centerHeight.

Dato che la dimensione dell'immagine che stiamo usando è 300x100, ho deciso di dividere l'immagine 50 volte in orizzontale e 25 volte in verticale. Questi valori hanno dato un risultato abbastanza decente con prestazioni ottimali. Li salviamo in variabili locali, che ho chiamato "numberOfColumns" e "numberOfRows".

Salviamo il risultato della divisione della larghezza dell'immagine per numberOfColumns in "sizeWidth" e il risultato della divisione dell'altezza dell'immagine di numberOfRows in "sizeHeight."

La variabile "numberOfBoxes" contiene numberOfColumns moltiplicate per numberOfRows.

Successivamente istanziamo _pictureArray in modo che possiamo iniziare a inserire piccoli sprites in esso. Aggiungi le seguenti righe di codice dopo il metodo onLoadComplete ():

funzione privata createEffect ($ bitmap: Bitmap): void // centra l'immagine orizzontalmente. var centerWidth: Number = (stage.stageWidth - $ bitmap.width) * .5; // centra l'immagine verticalmente. var centerHeight: Number = (stage.stageHeight - $ bitmap.height) * .5; var numberOfColumns: uint = 50; var numberOfRows: uint = 25; var sizeWidth: uint = $ bitmap.width / numberOfColumns; var sizeHeight: uint = $ bitmap.height / numberOfRows; var numberOfBoxes: uint = numberOfColumns * numberOfRows; _pictureArray = []; 

Passaggio 16: Cicli annidati

Dopo aver istanziato _pictureArray, aggiungeremo due anelli, uno dentro l'altro. Il primo ciclo gestirà lo spostamento della posizione x e passerà attraverso tutte le colonne, mentre il secondo ciclo si sposterà sulla posizione y e passerà attraverso tutte le righe.

Aggiungi le seguenti righe di codice all'interno del metodo createEffect () subito dopo aver istanziato _pictureArray, quindi salva il file:

per (var i: uint = 0; i < numberOfColumns; i++)  //these loops are what splits the image into 1250 pieces. for (var j:uint = 0; j < numberOfRows; j++)  //let's see what it does. trace ('i:' + i, 'j:' + j);  

Passaggio 17: test due

Prova il film premendo CTRL + Invio.

Come puoi vedere, per ogni io c'è un ciclo completo di j. Questo è chiamato "loop di nidificazione". Ciò significa che io che rappresenta l'asse x rimane su un valore mentre il secondo ciclo itera per l'asse y.

In parole semplici, iniziamo con x = 0, y = 0; quindi l'iterazione successiva è x = 0, y = 1; quindi x = 0, y = 2 e così via.

Quando si raggiunge la fine, il primo ciclo aumenta di 1 e quindi attraversa nuovamente il secondo ciclo: x = 1, y = 0; x = 1, y = 1, x = 1, y = 2, ecc. Questo va avanti fino al completamento del primo ciclo.

Vedrai cosa succede quando lo applichiamo ad alcune manipolazioni di bitmap nelle righe successive.


Passaggio 18: divisione dell'immagine

Dall'interno del secondo ciclo, andare avanti e rimuovere la funzione di traccia che abbiamo usato per il test. Ogni volta che eseguiamo il ciclo, dobbiamo creare una piccola immagine con la larghezza di "sizeWidth" e l'altezza di "sizeHeight".

Questa piccola immagine scatterà istantaneamente una piccola parte dell'immagine a partire dall'angolo in alto a sinistra e passerà in basso a destra. Il "tempBitmapData" è dove disegneremo la piccola parte dell'immagine. "SourceRect" è il rettangolo che useremo per specificare quale parte dell'immagine verrà copiata.

Aggiungi le seguenti righe all'interno del secondo ciclo e salva il file:

// 1 bitmapdata temporanea var tempBitmapData: BitmapData = new BitmapData (sizeWidth, sizeHeight); // 1 rettangolo temporaneo (x, y, larghezza, altezza) // passiamo i * sizeWidth per il parametro x e i * sizeHeight per il parametro y // e per sizeWidth e sizeHeight per i parametri width e height. var sourceRect: Rectangle = new Rectangle (i * sizeWidth, j * sizeHeight, sizeWidth, sizeHeight); trace (sourceRect); // per il test

Step 19: Ancora più test

Prova il film Quello che fa ora è creare un rettangolo che aggiusta le sue posizioni xey ogni iterazione.

Come puoi vedere, il primo esempio mostra x = 0, y = 0 e il successivo è x = 0, y = 4. Questo è ciò che usiamo per i confini dello scatto istantaneo tratto dall'immagine sorgente. Rimuovi la funzione di prova quando sei pronto per andare avanti.


Passaggio 20: BitmapData.copyPixels ()

Quindi usiamo il metodo BitmapData.copyPixels () per copiare una piccola parte dell'immagine basata su sourceRect. I parametri per questo metodo sono l'immagine bitmap da copiare, l'area del rettangolo da copiare e il punto di destinazione in cui verrà copiato.

Aggiungi la seguente riga di codice sotto la dichiarazione sourceRect.

tempBitmapData.copyPixels ($ bitmap.bitmapData, sourceRect, new Point);

Creiamo quindi una Bitmap temporanea per ospitare i BitmapData che abbiamo appena copiato e uno Sprite temporaneo per ospitare Bitmap.

Quindi spingiamo un riferimento di ciascun Sprite su _pictureArray per un accesso successivo. Dopodiché aggiungiamo lo Sprite allo stage con la stessa coordinata di dove l'abbiamo copiato, ricreando così l'immagine originale.

Quindi, spostiamo l'immagine di centerWidth e centerHeight per centrarla correttamente sul palco.

Aggiungi le seguenti righe di codice e, ancora una volta, salva il file:

// creiamo quindi una bitmap temporanea per ospitare i bitmapdata che abbiamo appena copiato. var tempBitmap: Bitmap = new Bitmap (tempBitmapData); // e 1 sprite temporaneo per ospitare la bitmap per abilitare l'interattività. var tempSprite: Sprite = new Sprite; // aggiungiamo semplicemente ogni scatola all'interno del proprio sprite per abilitare l'interattività poiché i bitmap non sono interattivi. tempSprite.addChild (tempBitmap); // ogni sprite viene aggiunto alla matrice _pictureArray per l'accesso successivo. _pictureArray.push (tempSprite); // quindi posiziona ciascuno di loro sul palco. // Aggiungiamo la larghezza centrale e l'altezza centrale in modo che l'immagine si concentri sul palco. tempSprite.x = i * sizeWidth + centerWidth; tempSprite.y = j * sizeHeight + centerHeight; addChild (tempSprite);

Passo 21: Test tre

Vai avanti e prova di nuovo. Dovresti vedere l'immagine correttamente posizionata sul palco. Non sembrerà nemmeno che sia stato diviso in 1250 pezzi.

Subito dopo la parentesi di chiusura del secondo ciclo, prima di chiudere il metodo, aggiungere la seguente riga di codice:

stage.addEventListener (MouseEvent.CLICK, blowWind);

Aggiungiamo un listener di eventi sul palco per ascoltare MouseEvent.CLICK. Questo attiverà l'animazione eseguendo la funzione blowWind (), che creeremo nel passaggio successivo.

La tua classe WindEffect dovrebbe essere simile a questa:

package import com.greensock.easing.Strong; import com.greensock.TweenLite; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Loader; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Point; import flash.geom.Rectangle; import flash.net.URLRequest; public class WindEffect estende Sprite private var _pictureArray: Array; funzione pubblica WindEffect ($ url: String) loadPicture ($ url);  private function loadPicture ($ url: String): void var loader: Loader = new Loader; loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onLoadComplete); loader.load (new URLRequest ($ url));  funzione privata onLoadComplete (e: Event): void createEffect (e.target.content);  funzione privata createEffect ($ bitmap: Bitmap): void var centerWidth: Number = (stage.stageWidth - $ bitmap.width) * .5; var centerHeight: Number = (stage.stageHeight - $ bitmap.height) * .5; var numberOfColumns: uint = 50; var numberOfRows: uint = 25; var sizeWidth: uint = $ bitmap.width / numberOfColumns; var sizeHeight: uint = $ bitmap.height / numberOfRows; var numberOfBoxes: uint = numberOfColumns * numberOfRows; _pictureArray = []; per (var i: uint = 0; i < numberOfColumns; i++)  for (var j:uint = 0; j < numberOfRows; j++)  var tempBitmapData:BitmapData = new BitmapData (sizeWidth, sizeHeight); var sourceRect:Rectangle = new Rectangle (i * sizeWidth, j * sizeHeight, sizeWidth, sizeHeight); tempBitmapData.copyPixels ($bitmap.bitmapData, sourceRect, new Point); var tempBitmap:Bitmap = new Bitmap (tempBitmapData); var tempSprite:Sprite = new Sprite; tempSprite.addChild (tempBitmap); _pictureArray.push (tempSprite); tempSprite.x = i * sizeWidth + centerWidth; tempSprite.y = j * sizeHeight + centerHeight; addChild (tempSprite);   stage.addEventListener (MouseEvent.CLICK, blowWind);   

Passaggio 22: creazione dell'effetto vento

Inizia rimuovendo il listener di eventi MouseEvent.CLICK poiché è necessario che si verifichi una sola volta. Aggiungi le seguenti righe di codice dopo il metodo createEffect ():

funzione privata blowWind (e: MouseEvent): void stage.removeEventListener (MouseEvent.CLICK, blowWind); 

Abbiamo bisogno di esaminare tutti gli sprite che abbiamo assegnato a _pictureArray e animarli individualmente.

TweenLite viene applicato per animare tutti i pezzi verso destra come se il vento li stesse soffiando.

I parametri sono: la destinazione per l'interpolazione, la durata dell'interpolazione, un oggetto variabile che contiene tutte le proprietà, insieme ai valori che si desidera applicare all'interpolazione..

Per esempio: TweenLite.to (target, duration, x: 100, y: 100, rotazione: 30, facilità: Strong.easeIn, onComplete: trace, onCompleteParams: ['hello']).

Gli ultimi due parametri dell'esempio precedente vengono utilizzati per quando termina l'interpolazione. Il parametro onComplete chiama la funzione trace e il parametro onCompleteParams invia una matrice contenente la stringa "ciao" nella funzione di traccia.

Aggiungi le seguenti righe di codice subito dopo il listener dell'evento di rimozione:

per (var i: uint = 0; i < _pictureArray.length; i++)  TweenLite.to ( _pictureArray[i], getRandomInRange (.25, 2, false),  x: stage.stageWidth + 100, y:_pictureArray[i].y + getRandomInRange (-100, 100, false),// rotation: getRandomInRange (-90, 90), ease:Strong.easeIn, onComplete:removeSprite, onCompleteParams:[_pictureArray[i]]  ); 

Nell'attuale implementazione, quando chiamiamo TweenLite dal loop, assegniamo il target come _pictureArray [current iteration].

Per la durata assegniamo un valore per la lunghezza dell'interpolazione a un tempo casuale compreso tra 0,25 secondi e 2 secondi.

L'oggetto variabile contiene 5 proprietà:

  • x: stage.stageWidth + 100 che animerà la proprietà x dello sprite.
  • y: _pictureArray [i] .y + getRandomRange (-100,100, false) che otterrà la posizione y dello sprite corrente e aggiungerà un numero casuale compreso tra -100 e 100 per dare all'animazione un effetto di espansione.
  • rotazione: getRandomRange (-90,90) ruota lo sprite corrente ovunque tra -90 e 90 gradi.
  • facilità: Strong.easeIn il che fa sì che le gemelle inizino lentamente e improvvisamente accelerino.
  • onComplete: removeSprite che chiama il metodo removeSprite una volta che l'interpolazione è terminata e lo Sprite è fuori dallo schermo.
  • onCompleteParams che invia l'array [_pictureArray [current iteration]] come parametro per removeSprite.

Passaggio 23: removeSprite () Method

Questo metodo viene chiamato da TweenLite quando l'animazione per una particolare interpolazione è terminata. Rimuoviamo lo Sprite dall'elenco di visualizzazione, quindi non c'è confusione. Aggiungi le seguenti righe di codice dopo il metodo blowWind ():

funzione privata removeSprite ($ sprite: Sprite): void removeChild ($ sprite); 

Passo 24: Metodo getRandomInRange ()

Sono sicuro che tu abbia familiarità con questo (se no, Carlos Yanez ha scritto un suggerimento rapido sull'argomento.) La mia versione ha un'opzione di restituzione di numeri interi (int, uint) o float (frazioni).

Aggiungi le seguenti righe di codice. Se stai utilizzando FlashDevelop, puoi salvarlo come snippet personalizzato in modo che possa essere facilmente aggiunto a qualsiasi classe / progetto. L'ho dichiarato come metodo statico pubblico per la piena accessibilità.

funzione statica pubblica getRandomInRange ($ min: Number, $ max: Number, $ arrotondato: Boolean = true): Number if ($ arrotondato) ritorno Math.round (Math.random () * ($ max - $ min) + $ min); else restituisce Math.random () * ($ max - $ min) + $ min; 

Questo è tutto! Esegui il film. Se c'è qualcosa di sbagliato, controlla il tuo codice contro la classe WindEffect che ho incluso nel download sorgente.


Conclusione

La chiave per creare effetti interessanti è imparare e padroneggiare sia la manipolazione delle immagini che le classi di interpolazione di animazione come TweenLite. Non esitate a lasciare una nota per eventuali commenti, dubbi o suggerimenti. Grazie per aver letto!