Blås et bilde unna med en tilpasset vind effekt

To ganger i måneden besøker vi noen av våre leseres favorittinnlegg fra hele historien til Activetuts +. Denne opplæringen ble først publisert i mars 2010.

I denne opplæringen vil vi lage en tilpasset klasse som bryter et bilde i tusen stykker og simulerer en vind som blåser dem bort. Jeg opprettet dette prosjektet rent med AS3 og FlashDevelop - Flash ikke nødvendig!


Endelig resultatforhåndsvisning

La oss se på det endelige resultatet vi skal jobbe for. Gå videre og klikk hvor som helst i SWF:


Rask Intro til FlashDevelop

FlashDevelop er en gratis kodeditor for Flash og Flex. Du kan bruke den til å redigere klassefilene dine når du arbeider med Flash-programvare, eller du kan opprette et AS3-prosjekt som ikke krever Flash i det hele tatt - og det er akkurat det vi skal gjøre i denne opplæringen.

Så last ned FlashDevelop og installer den. Dessverre går FlashDevelop bare på Windows. Mac-alternativer inkluderer FDT og Flex Builder, men ingen er gratis. Du kan bruke Flash selv, og jeg vil forklare hvordan du gjør dette når vi går.


Trinn 1: Opprett et nytt prosjekt

Åpne FlashDevelop og klikk Project> New Project?


Trinn 2: Oppsett

Velg Actionscript 3> AS3 Project. For navnet på prosjektet satt i "WindEffect." For stedet, klikk og naviger til mappen du vil lagre den i. La avkrysningsboksen "Opprett katalog for prosjekt" velges og klikk OK.

Hvis du vil bruke Flash CS3 / CS4, opprett en ny Flash-fil og sett bredden og høyden til scenen til 550x250px, sett bakgrunnsfargen til svart. Gi det navnet "windEffect.fla" og lagre det hvor du vil.


Trinn 3: Flytt kildebildet

For FlashDevelop, åpne prosjektkatalogen og kopier eller dra windEffect.jpg fra kilde nedlastingen (koblet øverst på siden) til \ bin \ mappen.

For Flash, kopier eller dra windEffect.jpg fra kilde nedlastingen til samme mappe hvor du har windEffect.fla.


Trinn 4: Installer TweenLite

Vi skal bruke TweenLite av Greensock for tweening. Du kan laste ned den nyeste versjonen av komponenten her; Jeg har også tatt med den i kilde nedlastingen.

For FlashDevelop, fortsett og kopier eller dra greensock.swc fra kilde nedlastingen til \ lib \ mappen for dette prosjektet.

Fra FlashDevelop klikker du på Vis> Prosjektleder


Trinn 5: Eksternt bibliotek

Fortsatt i FlashDevelop, klikk på '+' -tegnet til venstre for lib-mappen for å utvide det. Høyreklikk greensock.swc og velg Legg til i bibliotek.

For Flash, kopier eller dra \ com \ mappen fra kilde nedlastingen til samme mappe som windEffect.fla filen.


Trinn 6: Dokumentklassen

For FlashDevelop, åpne prosjektlederen igjen (se trinn 4), utvid mappen \ src \ og dobbeltklikk Main.as. Under importen og rett over klassedepartementet, legg til følgende metadatakode for å konfigurere sceneegenskapene:

[SWF (bredde = 550, høyde = 250, frameRate = 30, backgroundColor = 0)]

Innenfor init () -metoden etter kommentaren 'inngangspunkt' legger du til følgende kode:

 stage.scaleMode = StageScaleMode.NO_SCALE; // ikke strekke scenevarselen: WindEffect = ny WindEffect ('windEffect.jpg'); // vi vil lage WindEffect klassen snart addChild (effekt);

Det er det for hoveddokumentklassen.

For Flash, opprett en ny Main.as-klasse i samme mappe som prosjektet ditt. Pass på at Main.as-klassen er i samme mappe som fla. & com-mappen. Legg til følgende linjer:

pakke import flash.display.Sprite; importer flash.display.StageScaleMode; importere flash.events.Event; offentlig klasse Hoved utvider Sprite offentlig funksjon Main (): void if (stage) init (); ellers addEventListener (Event.ADDED_TO_STAGE, init);  privat funksjon init (e: Event = null): void removeEventListener (Event.ADDED_TO_STAGE, init); stage.scaleMode = StageScaleMode.NO_SCALE; // ikke strekke scenevarselen: WindEffect = ny WindEffect ('windEffect.jpg'); // vi vil lage WindEffect klassen snart addChild (effekt); 

Åpne Flash og tilordne "Main" som Dokument-klassen.

(Ikke sikker på hva dette handler om? Les denne korte introduksjonen til bruk av en dokumentklasse.)

Hvis du prøver å kjøre dette nå, vil du få en feil siden vi ikke har opprettet WindEffect-klassen ennå. Bare vær sikker på at du lagrer filen og legger den til nå.


Trinn 7: Opprett WindEffect-klassen

For FlashDevelop klikker du på Vis> Prosjektleder, høyreklikker \ src \ mappen og velger Legg til> Ny klasse.


Trinn 8: Konfigurere klassen

Navngi klassen WindEffect, klikk på blaeknappen for baseklassen og skriv inn flash.display.Sprite. Trykk OK for å fullføre.


Trinn 9: Importere andre klasser

Legg til all nødvendig import inne i pakken parentes rett under 'importer flash.display.Sprite;' og før klassen definisjonen. Klikk på Lagre.

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

For Flash, opprett en ny ActionScript-fil, kaller den "WindEffect.as" og lagre den i samme katalog du har brukt. Det burde være rett ved siden av fla. fil, com mappe og Main.as.

Legg til følgende kode:

pakke import com.greensock.easing.Strong; importer com.greensock.TweenLite; importer flash.display.Bitmap; importer flash.display.BitmapData; importer flash.display.Loader; importer flash.display.Sprite; importere flash.events.Event; importer flash.events.MouseEvent; importer flash.geom.Point; importer flash.geom.Rectangle; importere flash.net.URLRequest; offentlig klasse WindEffect utvider Sprite offentlig funksjon WindEffect () 

Trinn 10: Legg til en instansvariabel

Legg til en privat variabel kalt "_pictureArray." Dette er den eneste variabelen vi vil ha i denne klassen. Hovedformålet er å holde referanser til alle de små sprites som inneholder de små stykkene av bildet når det er brutt opp.

Legg til følgende linje kode i parentesene
av klassen:

offentlig klasse WindEffect strekker seg Sprite // dette vil huske alle brikkene av bildet vi vil animere. privat var _pictureArray: Array; 

Trinn 11: Legg til byggeren

Legg til følgende linjer etter _pictureArray-erklæringen:

offentlig klasse WindEffect strekker seg Sprite // dette vil huske alle brikkene av bildet vi vil animere. privat var _pictureArray: Array; offentlig funksjon WindEffect ($ url: String) // vi kalder bare lastbilde i constructor loadPicture ($ url); 

Trinn 12: Få tilgang til bildet

Inne i loadPicture () -metoden kalt av konstruktormetoden, instanser vi en laster for å laste windEffect.jpg. Vi legger også til en KOMPLETE hendelse lytter til å lytte etter når lasten fullfører.

Legg til følgende kodelinjer etter WindEffect () -metoden. (Merk at parameteren "$ url" er banen til bildet vi laster inn fra Main.as.)

privat funksjon loadPicture ($ url: String): void // vi lager en loader med lyttere for å laste kilde bildet vi bruker. // og da laster vi bildet. var loader: Loader = new Loader; loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onLoadComplete); // når den er lastet, ring funksjonen onLoadComplete () loader.load (ny URLRequest ($ url)); 

Trinn 13: Lasting

Etter at bildet er importert riktig, kalles denne metoden. Legg til følgende kodelinjer etter loadPicture () -metoden og lagre filen.

privat funksjon onLoadComplete (e: Event): void // for testing addChild (e.target.content); 

Trinn 14: Test ett

Gå videre og trykk CTRL + Enter på tastaturet. Det skal fungere og bildet skal være på venstre øverste hjørne av scenen.

Nå som vi har sjekket det lastes inn riktig, fjern addChild-metoden og erstatt den med følgende kode:

createEffect (e.target.content);

Din WindEffect-klasse skal se slik ut:

pakke import com.greensock.easing.Strong; importer com.greensock.TweenLite; importer flash.display.Bitmap; importer flash.display.BitmapData; importer flash.display.Loader; importer flash.display.Sprite; importere flash.events.Event; importer flash.events.MouseEvent; importer flash.geom.Point; importer flash.geom.Rectangle; importere flash.net.URLRequest; [SWF (bredde = 550, høyde = 250, frameRate = 30, backgroundColor = 0)] offentlig klasse WindEffect utvider Sprite private var _pictureArray: Array; offentlig funksjon WindEffect ($ url: String) loadPicture ($ url); 
 privat funksjon loadPicture ($ url: String): void var loader: Loader = new Loader; loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onLoadComplete); loader.load (ny URLRequest ($ url));  privat funksjon onLoadComplete (e: Event): void createEffect (e.target.content); 

Trinn 15: Konfigurer variablene

Metoden createEffect () vil ta bildeparameteren som egentlig er en bitmap og bryte den ned til 1250 stykker.

Først beregner vi x- og y-posisjonene for å sentrere bildet på scenen. Vi lagrer dem i lokale variabler kalt centerWidth og centerHeight.

Siden størrelsen på bildet vi bruker er 300x100 bestemte jeg meg for å dele bildet 50 ganger horisontalt og 25 ganger vertikalt. Disse verdiene ga et ganske anstendig resultat med optimal ytelse. Vi lagrer dem i lokale variabler, som jeg heter "numberOfColumns" og "numberOfRows."

Vi lagrer resultatet av å dele bildets bredde med talletOfColumns i "sizeWidth" og resultatet av å dele bildets høyde med tallOfRows til "sizeHeight."

"NummerOfBoxer" -variabelen inneholder nummerOfColumns multiplisert med nummerOfRows.

Deretter ordner vi _pictureArray slik at vi kan begynne å sette små sprites inn i den. Legg til følgende kodelinjer etter metoden onLoadComplete ():

privat funksjon createEffect ($ bitmap: Bitmap): void // senter bildet horisontalt. var centerWidth: Number = (scene.stageWidth - $ bitmap.width) * .5; // senter bildet vertikalt. var centerHeight: Number = (stage.stageHeight - $ bitmap.height) * .5; var nummerOfColumns: uint = 50; var nummerOfRows: uint = 25; var sizeWidth: uint = $ bitmap.width / numberOfColumns; var sizeHeight: uint = $ bitmap.height / numberOfRows; var numberOfBoxes: uint = numberOfColumns * numberOfRows; _pictureArray = []; 

Trinn 16: Nestede løkker

Etter instantiating _pictureArray legger vi til to looper, den ene i den andre. Den første sløyfen håndterer å flytte på x-stillingen og vil løpe gjennom alle kolonnene, mens den andre sløyfen vil bevege seg på y-posisjonen og vil løpe gjennom alle rader.

Legg til følgende kodelinjer inne i createEffect () -metoden umiddelbart etter instansering av _pictureArray, og lag deretter filen:

for (var jeg: 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);  

Trinn 17: Test to

Test filmen ved å trykke CTRL + Enter.

Som du kan se, for hver Jeg Det er en full sløyfe av j. Dette kalles "nesting loops". Dette betyr at Jeg som representerer x-aksen, forblir på en verdi mens den andre sløyfen detererer for y-aksen.

Enkelt sagt begynner vi med x = 0, y = 0; så er den neste iterasjonen x = 0, y = 1; så x = 0, y = 2, og så videre.

Når y når slutten, går den første sløyfen med 1 og deretter igjen gjennom 2. sløyfen: x = 1, y = 0; x = 1, y = 1, x = 1, y = 2, osv. Dette fortsetter til 1. søyle fullføres.

Du ser hva dette gjør når vi bruker det til litt bitmap-manipulasjon i de neste linjene.


Trinn 18: Splitting av bildet

Fra innsiden av den andre sløyfen, fortsett og fjern sporingsfunksjonen som ble brukt til testing. Hver gang vi slår, må vi lage et lite bilde som har bredden på "sizeWidth" og høyden på "sizeHeight".

Dette lille bildet tar et snapshot av en liten del av bildet, som starter fra øverste venstre hjørne og beveger seg gjennom til nederst til høyre. "TempBitmapData" er hvor vi tegner den lille delen av bildet. "SourceRect" er rektangelet vi vil bruke til å spesifisere hvilken del av bildet som skal kopieres.

Legg til følgende linjer inne i 2. loop og lagre filen:

// 1 midlertidig bitmapdata var tempBitmapData: BitmapData = ny BitmapData (sizeWidth, sizeHeight); // 1 midlertidig rektangel (x, y, bredde, høyde) // vi sender jeg * sizeWidth for x-parameteren og jeg * sizeHeight for y-parameteren // og størrelsen Bredde og størrelseHøyde for bredde- og høydeparametrene. var sourceRect: Rectangle = ny rektangel (jeg * sizeWidth, j * sizeHeight, sizeWidth, sizeHeight); spor (sourceRect); // for testing

Trinn 19: Enda mer testing

Test filmen. Hva det gjør nå, er å lage et rektangel som justerer sine x- og y-posisjoner hver iterasjon.

Som du kan se, viser 1ste eksempel x = 0, y = 0, og det neste er x = 0, y = 4. Dette er hva vi bruker for grenser for snapshotet tatt fra kildebildet. Fjern testfunksjonen når du er klar til å fortsette.


Trinn 20: BitmapData.copyPixels ()

Vi bruker så BitmapData.copyPixels () -metoden for å kopiere et lite stykke av bildet basert på sourceRect. Parametrene for denne metoden er bitmap-bildet som skal kopieres, rektangelområdet som skal kopieres og bestemmelsesstedet der vi skal kopiere det.

Legg til følgende kodelinje under sourceRect-deklarasjonen.

tempBitmapData.copyPixels ($ bitmap.bitmapData, sourceRect, nytt punkt);

Vi lager deretter en midlertidig Bitmap for å huse BitmapData vi nettopp har kopiert og en midlertidig Sprite for å huse den Bitmap.

Deretter skyver vi en referanse til hver Sprite på _pictureArray for tilgang senere. Etter dette legger vi Sprite til scenen med samme koordinat som hvor vi kopierte det fra, og dermed gjenoppretter det opprinnelige bildet.

Vi kompenserer da bildet ved centerWidth og centerHeight for å sentrere det riktig på scenen.

Legg til følgende kodelinjer, og lagre filen igjen:

// vi lager deretter 1 midlertidig bitmap for å huse bitmapdataene vi nettopp har kopiert. var tempBitmap: Bitmap = ny Bitmap (tempBitmapData); // og 1 midlertidig sprite for å huse bitmappen for å aktivere interaktivitet. var tempSprite: Sprite = new Sprite; // vi legger bare til hver boks inne i egen sprite for å aktivere interaktivitet siden bitmaps av seg selv ikke er interaktive. tempSprite.addChild (tempBitmap); // hver sprite er lagt til i _pictureArray-arrayet for tilgang senere. _pictureArray.push (tempSprite); // så plasser hver av dem på scenen. // Vi legger til midtbredden og midthøyden slik at bildesentre på scenen. tempSprite.x = i * sizeWidth + centerWidth; tempSprite.y = j * sizeHeight + centerHeight; addChild (tempSprite);

Trinn 21: Test tre

Gå videre og test det igjen. Du bør se bildet riktig lagt ut på scenen. Det vil ikke engang se ut som det er blitt skilt i 1250 stykker.

Rett etter avslutningsbraketten til den andre sløyfen, før vi lukker metoden, legg til følgende linje av kode:

stage.addEventListener (MouseEvent.CLICK, blowWind);

Vi legger til en hendelselytter på scenen for å lytte etter en MouseEvent.CLICK. Dette vil utløse animasjonen ved å kjøre blowWind () -funksjonen, som vi vil opprette i neste trinn.

Din WindEffect-klasse skal se slik ut:

pakke import com.greensock.easing.Strong; importer com.greensock.TweenLite; importer flash.display.Bitmap; importer flash.display.BitmapData; importer flash.display.Loader; importer flash.display.Sprite; importere flash.events.Event; importer flash.events.MouseEvent; importer flash.geom.Point; importer flash.geom.Rectangle; importere flash.net.URLRequest; offentlig klasse WindEffect utvider Sprite private var _pictureArray: Array; offentlig funksjon WindEffect ($ url: String) loadPicture ($ url);  privat funksjon lastbilde ($ url: streng): tomrom var loader: Loader = new Loader; loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onLoadComplete); loader.load (ny URLRequest ($ url));  privat funksjon onLoadComplete (e: Event): void createEffect (e.target.content);  privat funksjon createEffect ($ bitmap: Bitmap): void var centerWidth: Number = (scene.stageWidth - $ bitmap.width) * .5; var centerHeight: Number = (stage.stageHeight - $ bitmap.height) * .5; var nummerOfColumns: uint = 50; var nummerOfRows: uint = 25; var sizeWidth: uint = $ bitmap.width / numberOfColumns; var sizeHeight: uint = $ bitmap.height / numberOfRows; var numberOfBoxes: uint = numberOfColumns * numberOfRows; _pictureArray = []; for (var jeg: 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);   

Trinn 22: Lag vindeffekten

Start med å fjerne MouseEvent.CLICK hendelseslytteren, siden vi trenger det bare å skje en gang. Legg til følgende kodelinjer etter metoden createEffect ():

privat funksjon blowWind (e: MouseEvent): void stage.removeEventListener (MouseEvent.CLICK, blowWind); 

Vi må gå gjennom alle sprites vi tildelte til _pictureArray og animere dem individuelt.

TweenLite brukes til å animere alle stykkene mot høyre som om vinden blåste på dem.

Parametrene er: målet for tween, varigheten av tweenen, et variabelt objekt som inneholder alle egenskapene, sammen med verdiene du vil bruke tween til.

For eksempel: TweenLite.to (mål, varighet, x: 100, y: 100, rotasjon: 30, enkelhet: Strong.easeIn, onComplete: spor, onCompleteParams: ['hallo']).

Ovennevnte eksempel er de to siste parameterne som brukes til når tweenen er ferdig. OnComplete-parameteren kaller sporfunksjonen og parameteren onCompleteParams sender en matrise som inneholder strengen "hallo" i sporingsfunksjonen.

Legg til følgende kodelinjer rett etter fjernhendelseslytteren:

for (var jeg: 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]]  ); 

I den faktiske implementeringen, når vi kaller TweenLite fra løkken, tildeler vi målet som _pictureArray [nåværende iterasjon].

For varigheten tildeler vi en verdi for lengden på tween til en tilfeldig tid mellom .25 sekunder og 2 sekunder.

Det variable objektet inneholder 5 egenskaper:

  • x: stage.stageWidth + 100 som vil animere spriteens x-egenskap.
  • y: _pictureArray [i] .y + getRandomRange (-100,100, falsk) som vil få den nåværende spritens y-posisjon og legge til et tilfeldig tall mellom -100 og 100 for å gi animasjonen en utvidende effekt.
  • rotasjon: getRandomRange (-90,90) roterer gjeldende sprite til hvor som helst mellom -90 og 90 grader.
  • lette: Strong.easeIn som gjør at tween starter sakte og plutselig øker hastigheten.
  • onComplete: removeSprite som kaller removeSprite-metoden når tween er ferdig og Sprite er utenfor skjermen.
  • onCompleteParams som sender arrayet [_pictureArray [current iteration]] som parameter for removeSprite.

Trinn 23: removeSprite () Metode

Denne metoden kalles fra TweenLite når animasjonen for en bestemt tween er ferdig. Vi fjerner bare Sprite fra displaylisten, så det er ingen rot. Legg til følgende kodelinjer etter blowWind () -metoden:

privat funksjon removeSprite ($ sprite: Sprite): void removeChild ($ sprite); 

Trinn 24: getRandomInRange () Metode

Jeg er sikker på at du er kjent med denne (Hvis ikke, har Carlos Yanez skrevet en Quick Tip om emnet.) Min versjon har et alternativ til å returnere enten hele tall (int, uint) eller floats (fraksjoner).

Legg til følgende kodelinjer. Hvis du bruker FlashDevelop, kan du lagre den som en egendefinert kodebit, slik at den enkelt legges til i hvilken som helst klasse / prosjekt. Jeg har den erklært som en offentlig statisk metode for full tilgjengelighet.

offentlig statisk funksjon getRandomInRange ($ min: tall, $ maks: tall, $ avrundet: boolsk = sant): tall hvis ($ avrundet) returnerer Math.round (Math.random () * ($ max - $ min) + $ min); ellers returnerer Math.random () * ($ max - $ min) + $ min; 

Det er det! Kjør filmen. Hvis det er noe galt, sjekk koden din mot WindEffect-klassen jeg har tatt med i nedlasting av kilde.


Konklusjon

Nøkkelen til å skape kule effekter er å lære og mestre både bildemanipulering og animasjons-tweening-klasser som TweenLite. Vær så snill å slippe et notat for eventuelle kommentarer, bekymringer eller forslag. Takk for at du leste!