Blaas een afbeelding weg met een aangepast windeffect

Twee keer per maand bekijken we enkele van onze favoriete lezers uit de geschiedenis van Activetuts +. Deze zelfstudie is voor het eerst gepubliceerd in maart 2010.

In deze tutorial zullen we een aangepaste klasse maken die een afbeelding in duizend stukjes verdeelt en een wind simuleert die ze wegblaast. Ik heb dit project uitsluitend met AS3 en FlashDevelop gemaakt - Flash is niet nodig!


Eindresultaat voorbeeld

Laten we eens kijken naar het uiteindelijke resultaat waar we naartoe zullen werken. Ga je gang en klik ergens binnen de SWF:


Quick Intro voor FlashDevelop

FlashDevelop is een gratis code-editor voor Flash en Flex. U kunt het gebruiken om uw klassenbestanden te bewerken wanneer u met Flash-software werkt, of u kunt een AS3-project maken dat helemaal geen Flash vereist - en dat is precies wat we in deze tutorial zullen doen..

Dus download FlashDevelop en installeer het. Helaas werkt FlashDevelop alleen op Windows. Mac-alternatieven zijn FDT en Flex Builder, hoewel geen van beide gratis is. Je kunt Flash zelf gebruiken en ik zal uitleggen hoe je dit moet doen terwijl we verder gaan.


Stap 1: Maak een nieuw project

Open FlashDevelop en klik op Project> Nieuw project?


Stap 2: instellen

Kies Actionscript 3> AS3 Project. Voor de naam van het project in "WindEffect". Klik voor de locatie op en navigeer naar de map waarin u het wilt opslaan. Laat het selectievakje 'Directory voor project maken' geselecteerd en klik op OK.

Als u Flash CS3 / CS4 wilt gebruiken, maakt u een nieuw Flash-bestand en stelt u de breedte en hoogte van de stage in op 550x250 px, stel de achtergrondkleur in op zwart. Noem het "windEffect.fla" en bewaar het waar je maar wilt.


Stap 3: Verplaats de bronafbeelding

Voor FlashDevelop opent u de projectdirectory en kopieert of sleept u windEffect.jpg vanaf de brondownload (waarnaar bovenaan de pagina wordt verwezen) naar de map \ bin \.

Voor Flash kopieert of sleept u windEffect.jpg vanaf de brondownload naar dezelfde map waar u windEffect.fla hebt.


Stap 4: installeer TweenLite

We gaan TweenLite van Greensock gebruiken voor de tweening. U kunt hier de nieuwste versie van de component downloaden; Ik heb het ook opgenomen in de brondownload.

Voor FlashDevelop, ga je gang en kopieer of sleep greensock.swc van de brondownload naar de map \ lib \ voor dit project.

Klik in FlashDevelop op Beeld> Projectbeheer


Stap 5: Externe bibliotheek

Klik nog steeds in FlashDevelop op het '+' teken links van de lib-map om het uit te vouwen. Klik met de rechtermuisknop op greensock.swc en selecteer Toevoegen aan bibliotheek.

Voor Flash kopieert of sleept u de map \ com \ van de brondownload naar dezelfde map als uw windEffect.fla-bestand.


Stap 6: De documentklasse

Open voor FlashDevelop de projectmanager opnieuw (raadpleeg stap 4), vouw de map \ src \ uit en dubbelklik op Main.as. Onder de invoer en direct boven de klassendefinitie, voegt u de volgende metagegevenstag toe om de fase-eigenschappen in te stellen:

[SWF (width = 550, height = 250, frameRate = 30, backgroundColor = 0)]

Voeg de volgende code toe binnen de methode init () na het invoervak ​​'opmerking':

 stage.scaleMode = StageScaleMode.NO_SCALE; // rekt het effect stage var niet uit: WindEffect = new WindEffect ('windEffect.jpg'); // we zullen de WindEffect-klasse snel addChild (effect) maken;

Dat is het voor de hoofddocumentklasse.

Maak voor Flash een nieuwe Main.as-les in dezelfde map als uw project. Zorg ervoor dat de klasse Main.as zich in dezelfde map bevindt als de fla. & com-map. Voeg de volgende regels toe:

pakket import flash.display.Sprite; import flash.display.StageScaleMode; import flash.events.Event; public class Hoofd breidt uit openbare functie Main (): void if (stage) init (); else addEventListener (Event.ADDED_TO_STAGE, init);  private function init (e: Event = null): void removeEventListener (Event.ADDED_TO_STAGE, init); stage.scaleMode = StageScaleMode.NO_SCALE; // rekt het effect stage var niet uit: WindEffect = new WindEffect ('windEffect.jpg'); // we zullen de WindEffect-klasse snel addChild (effect) maken; 

Open Flash en wijs "Main" toe als de documentklasse.

(Weet u niet zeker waar dit allemaal over gaat? Lees deze korte inleiding over het gebruik van een documentklasse.)

Als u dit nu probeert uit te voeren, krijgt u een foutmelding omdat we nog geen WindEffect-klasse hebben gemaakt. Zorg ervoor dat u het bestand opslaat en laat het voor nu.


Stap 7: Maak de WindEffect-klasse

Klik voor FlashDevelop op Beeld> Projectbeheer, klik met de rechtermuisknop op de map \ src \ en kies Toevoegen> Nieuwe klas.


Stap 8: De klas instellen

Geef de klasse WindEffect een naam, klik op de bladerknop voor de basisklasse en voer flash.display.Sprite in. Druk op OK om te voltooien.


Stap 9: Andere klassen importeren

Voeg alle noodzakelijke importen toe aan de pakkethaakjes direct onder 'import flash.display.Sprite;' en vóór de klassendefinitie. Klik op Opslaan.

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;

Maak voor Flash een nieuw ActionScript-bestand, noem dit "WindEffect.as" en sla het op in dezelfde directory die u hebt gebruikt. Het zou vlak naast de fla moeten zijn. bestand, map com, en Main.as.

Voeg de volgende code toe:

pakket 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; openbare klasse WindEffect breidt uit openbare functie WindEffect () 

Stap 10: voeg een instantie-variabele toe

Voeg een privévariabele toe met de naam "_pictureArray." Dit is de enige variabele die we in deze klasse hebben. Het belangrijkste doel is om verwijzingen te houden naar alle kleine sprites die de kleine stukjes van de foto bevatten, zodra deze zijn opgebroken.

Voeg de volgende coderegel toe tussen haakjes
van de klas:

openbare klasse WindEffect breidt Sprite uit // dit bevat alle stukken van de afbeelding die we zullen animeren. private var _pictureArray: Array; 

Stap 11: voeg de Constructor toe

Voeg de volgende regels toe na de verklaring _pictureArray:

openbare klasse WindEffect breidt Sprite uit // dit bevat alle stukken van de afbeelding die we zullen animeren. private var _pictureArray: Array; openbare functie WindEffect ($ url: String) // we noemen de load-afbeelding in de constructor loadPicture ($ url); 

Stap 12: Open de afbeelding

In de methode loadPicture () die wordt aangeroepen door de constructormethode, stellen we een lader voor om de windEffect.jpg te laden. We voegen ook een COMPLETE gebeurtenislistener toe om te luisteren wanneer de belasting is voltooid.

Voeg de volgende coderegels toe na de WindEffect () -methode. (Merk op dat de parameter "$ url" het pad is naar de afbeelding die we laden die door Main.as is doorgegeven)

private function loadPicture ($ url: String): void // we maken een loader met luisteraars om de bronfoto die we gebruiken te laden. // en dan laden we de afbeelding. var loader: Loader = new Loader; loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onLoadComplete); // wanneer het is geladen, roept u de functie onLoadComplete () aan loader.load (nieuwe URLRequest ($ url)); 

Stap 13: laden

Nadat de afbeelding correct is geïmporteerd, wordt deze methode genoemd. Voeg de volgende regels code toe na de methode loadPicture () en sla het bestand op.

private function onLoadComplete (e: Event): void // voor het testen van addChild (e.target.content); 

Stap 14: Test een

Ga je gang en druk op CTRL + Enter op je toetsenbord. Het zou moeten werken en het beeld zou in de linkerbovenhoek van het podium moeten staan.

Nu we hebben gecontroleerd dat het correct wordt geladen, verwijdert u de methode addChild en vervangt u deze door de volgende code:

createEffect (e.target.content);

Je WindEffect-klasse zou er ongeveer zo uit moeten zien:

pakket 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 (width = 550, height = 250, frameRate = 30, backgroundColor = 0)] public class WindEffect breidt Sprite uit private var _pictureArray: Array; openbare functie WindEffect ($ url: String) loadPicture ($ url); 
 persoonlijke functie loadPicture ($ url: String): void var loader: Loader = new Loader; loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onLoadComplete); loader.load (nieuwe URLRequest ($ url));  private function onLoadComplete (e: Event): void createEffect (e.target.content); 

Stap 15: Stel de variabelen in

De methode createEffect () neemt de afbeeldingsparameter, die in wezen een bitmap is, op tot 1250 stukjes.

Eerst berekenen we de x- en y-posities om het beeld op het podium te centreren. We slaan ze op in lokale variabelen met de naam centerWidth en centerHeight.

Omdat het formaat van de afbeelding die we gebruiken 300x100 is, heb ik besloten het beeld 50 keer horizontaal en 25 keer verticaal te verdelen. Deze waarden leverden een behoorlijk resultaat op met optimale prestaties. We slaan ze op in lokale variabelen, die ik "numberOfColumns" en "numberOfRows" heb genoemd.

We slaan het resultaat op door de breedte van de afbeelding te delen door numberOfColumns in "sizeWidth" en het resultaat van het delen van de hoogte van de afbeelding met numberOfRows in "sizeHeight".

De variabele "numberOfBoxes" bevat numberOfColumns vermenigvuldigd met numberOfRows.

Vervolgens nemen we _pictureArray op, zodat we er kleine sprites in kunnen zetten. Voeg de volgende coderegels toe na de methode onLoadComplete ():

private function createEffect ($ bitmap: Bitmap): void // centreer de afbeelding horizontaal. var centerWidth: Number = (stage.stageWidth - $ bitmap.width) * .5; // centreer de afbeelding verticaal. 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 = []; 

Stap 16: Geneste lussen

Na het instantiëren van _pictureArray zullen we twee lussen toevoegen, de ene in de andere. De eerste lus zal het verplaatsen op de x-positie afhandelen en zal door alle kolommen lussen, terwijl de tweede lus op de y-positie zal bewegen en door alle rijen zal lus- sen..

Voeg de volgende coderegels toe aan de methode createEffect () direct nadat u _pictureArray hebt gecontextialiseerd en sla het bestand vervolgens op:

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

Stap 17: Test twee

Test de film door op CTRL + Enter te drukken.

Zoals je kunt zien, voor elke ik er is een volledige lus van j. Dit wordt "nesting loops" genoemd. Dit betekent dat ik die de x-as vertegenwoordigt, blijft op één waarde terwijl de tweede lus itereert voor de y-as.

Simpel gezegd beginnen we met x = 0, y = 0; dan is de volgende iteratie x = 0, y = 1; dan x = 0, y = 2, enzovoort.

Wanneer y het einde bereikt, neemt de eerste lus toe met 1 en gaat dan opnieuw door de 2e lus: x = 1, y = 0; x = 1, y = 1, x = 1, y = 2, etc. Dit gaat door totdat de 1e lus voltooid is.

U zult zien wat dit doet als we het in de volgende paar regels toepassen op enkele bitmapmanipulatie.


Stap 18: Het beeld splitsen

Vanuit de tweede lus, ga je gang en verwijder de trace-functie die we hebben gebruikt voor het testen. Elke keer dat we een lus maken, moeten we een kleine afbeelding maken met de breedte van "sizeWidth" en de hoogte van "sizeHeight".

Deze kleine foto maakt een foto van een klein deel van de afbeelding, beginnend in de linkerbovenhoek en doorlopend naar rechtsonder. De "tempBitmapData" is waar we het kleine deel van de afbeelding zullen tekenen. De "sourceRect" is de rechthoek die we zullen gebruiken om aan te geven welk deel van de afbeelding zal worden gekopieerd.

Voeg de volgende regels toe in de 2e lus en sla het bestand op:

// 1 tijdelijke bitmapgegevens var tempBitmapData: BitmapData = nieuwe BitmapData (sizeWidth, sizeHeight); // 1 tijdelijke rechthoek (x, y, breedte, hoogte) // we geven i * sizeWidth door voor de x-parameter & i * sizeHeight voor de y-parameter // en de sizeWidth & sizeHeight voor de parameters width en height. var sourceRect: Rectangle = new Rectangle (i * sizeWidth, j * sizeHeight, sizeWidth, sizeHeight); trace (sourceRect); // voor testen

Stap 19: nog meer testen

Test de film. Wat het nu doet, is een rechthoek maken die zijn x- en y-posities aanpast voor elke iteratie.

Zoals u kunt zien, toont het eerste voorbeeld x = 0, y = 0 en de volgende is x = 0, y = 4. Dit is wat we gebruiken voor de grenzen van de snapshot uit de bronafbeelding. Verwijder de testfunctie wanneer u klaar bent om verder te gaan.


Stap 20: BitmapData.copyPixels ()

Vervolgens gebruiken we de methode BitmapData.copyPixels () om een ​​klein stukje van de afbeelding te kopiëren op basis van de sourceRect. De parameters voor deze methode zijn de te kopiëren bitmapafbeelding, het te kopiëren rechthoekgebied en het bestemmingspunt naar waar we het kopiëren.

Voeg de volgende regel code toe onder de sourceRect-declaratie.

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

We maken vervolgens een tijdelijke Bitmap om de BitmapData die we zojuist hebben gekopieerd en één tijdelijke Sprite te huisvesten om die Bitmap te huisvesten.

Vervolgens pushen we een referentie van elke Sprite naar _pictureArray voor later toegang. Hierna voegen we de Sprite toe aan het podium met dezelfde coördinaat als waar we het vanaf hebben gekopieerd, waardoor het originele beeld opnieuw is gecreëerd.

We compenseren vervolgens het beeld met centerWidth en centerHeight om het correct in het werkgebied te centreren.

Voeg de volgende coderegels toe en sla het bestand opnieuw op:

// we maken vervolgens 1 tijdelijke bitmap om de bitmapdata die we net hebben gekopieerd in te huisvesten. var tempBitmap: Bitmap = nieuwe bitmap (tempBitmapData); // en 1 tijdelijke sprite om de bitmap op te slaan om interactiviteit mogelijk te maken. var tempSprite: Sprite = nieuwe Sprite; // we voegen elke box gewoon toe aan zijn eigen sprite om interactiviteit mogelijk te maken, omdat bitmaps zelf niet interactief zijn. tempSprite.addChild (tempBitmap); // elke sprite wordt toegevoegd aan de array _pictureArray voor later toegang. _pictureArray.push (tempSprite); // plaats ze dan allemaal op het podium. // We voegen de middenbreedte en de middenhoogte toe, zodat het beeld op het podium wordt geplaatst. tempSprite.x = i * sizeWidth + centerWidth; tempSprite.y = j * sizeHeight + centerHeight; addChild (tempSprite);

Stap 21: Test drie

Ga je gang en test het opnieuw. Je zou de afbeelding correct op het podium moeten zien liggen. Het ziet er niet naar uit dat het in 1250 stukken is gescheiden.

Direct na de sluitingsbeugel van de tweede lus, voordat we de methode sluiten, voegt u de volgende coderegel toe:

stage.addEventListener (MouseEvent.CLICK, blowWind);

We voegen een gebeurtenislistener toe aan het podium om te luisteren naar een MouseEvent.CLICK. Dit activeert de animatie door de functie blowWind () uit te voeren, die we in de volgende stap zullen maken.

Je WindEffect-klasse zou er ongeveer zo uit moeten zien:

pakket 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 breidt Sprite uit private var _pictureArray: Array; openbare functie WindEffect ($ url: String) loadPicture ($ url);  private functie loadPicture ($ url: String): void var loader: Loader = new Loader; loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onLoadComplete); loader.load (nieuwe URLRequest ($ url));  private function onLoadComplete (e: Event): void createEffect (e.target.content);  private function 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 = []; for (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);   

Stap 22: Het windeffect creëren

Begin met het verwijderen van de MouseEvent.CLICK-gebeurtenislistener, omdat we dit maar één keer hoeven te doen. Voeg de volgende coderegels toe na de methode createEffect ():

private function blowWind (e: MouseEvent): void stage.removeEventListener (MouseEvent.CLICK, blowWind); 

We moeten alle sprites doorlopen die we in _pictureArray hebben toegewezen en ze individueel animeren.

TweenLite wordt toegepast om alle stukken naar rechts te animeren alsof er wind op ze waait.

De parameters zijn: het doel voor de tween, de duur van de tween, een variabel object dat alle eigenschappen bevat, samen met de waarden waarop u de tween wilt toepassen.

Bijvoorbeeld: TweenLite.to (doel, duur, x: 100, y: 100, rotatie: 30, gemak: Strong.easeIn, onComplete: trace, onCompleteParams: ['hallo']).

De laatste twee parameters van het bovenstaande voorbeeld worden gebruikt voor wanneer de tween is voltooid. De parameter onComplete roept de trace-functie aan en de parameter onCompleteParams verzendt een array met de tekenreeks 'hallo' naar de trace-functie.

Voeg de volgende coderegels direct toe na de listener voor het verwijderen van evenementen:

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

In de daadwerkelijke implementatie, wanneer we TweenLite vanuit de lus aanroepen, wijzen we het doelwit toe als _pictureArray [huidige iteratie].

Voor de duur geven we een waarde voor de lengte van de tween aan een willekeurige tijd tussen 0,25 seconden en 2 seconden.

Het variabele object bevat 5 eigenschappen:

  • x: stage.stageWidth + 100 die de x-eigenschap van de sprite animeert.
  • y: _pictureArray [i] .y + getRandomRange (-100,100, false) die de y-positie van de huidige sprite zal krijgen en een willekeurig getal tussen -100 en 100 zal toevoegen om de animatie een expanderend effect te geven.
  • rotatie: getRandomRange (-90,90) roteert de huidige sprite naar een waarde tussen -90 en 90 graden.
  • gemak: Strong.easeIn waardoor de tween langzaam begint en plotseling sneller wordt.
  • onComplete: removeSprite waarin de methode removeSprite wordt aangeroepen wanneer de tween is voltooid en de Sprite buiten het scherm is.
  • onCompleteParams die de array [_pictureArray [huidige iteratie] verzendt als de parameter voor removeSprite.

Stap 23: removeSprite () -methode

Deze methode wordt aangeroepen vanuit TweenLite wanneer de animatie voor een bepaalde tween is voltooid. We verwijderen de Sprite gewoon van de displaylijst, dus er is geen rommel. Voeg de volgende coderegels toe na de methode blowWind ():

private function removeSprite ($ sprite: Sprite): void removeChild ($ sprite); 

Stap 24: methode getRandomInRange ()

Ik ben er zeker van dat je hiermee bekend bent (zo niet, Carlos Yanez heeft een Quick Tip over dit onderwerp geschreven.) Mijn versie heeft de optie om hele getallen (int, uint) of drijvers (breuken) te retourneren.

Voeg de volgende regels code toe. Als u FlashDevelop gebruikt, kunt u het opslaan als een aangepast fragment, zodat het eenvoudig kan worden toegevoegd aan een klas / project. Ik heb het verklaard als een openbare statische methode voor volledige toegankelijkheid.

openbare statische functie getRandomInRange ($ min: Number, $ max: Number, $ rounded: Boolean = true): Number if ($ rounded) return Math.round (Math.random () * ($ max - $ min) + $ min); else return Math.random () * ($ max - $ min) + $ min; 

Dat is het! Start de film. Als er iets mis is, controleer dan uw code ten opzichte van de WindEffect-klasse die ik in de brondownload heb opgenomen.


Conclusie

De sleutel tot het maken van coole effecten is het leren en beheersen van zowel beeldmanipulatie als tweening-klassen voor animaties, zoals TweenLite. Aarzel niet om een ​​opmerking achter te laten voor opmerkingen, opmerkingen of suggesties. Bedankt voor het lezen!