Partikel

media type="file" key="Partikel_final.swf" width="700" height="200" align="center"

Version1: Einen Partikel erstellen
Hier wird ein neuer, leerer MovieClip erstellt und etwas (beliebiges) darauf gezeichnet. Wir nennen ihn ab jetzt einen "Partikel" - er wird gespeichert in einer Variablen namens dot. Ausserdem wird der MovieClip an die Koordinaten 200/150 gerutscht. code format="actionscript" var dot:MovieClip = new MovieClip; //neuen leeren MovieClip erstellen und in dot speichern dot.graphics.lineStyle(3,Math.random*0xffffff,1); //Stift (Breite, Farbe, Alpha) von dot festlegen dot.graphics.drawCircle(0,0,20); //Kreis zeichnen (an 0 | 0 von dot, mit 20 Pixel Radius) dot.x = 200; //dot an X-Koordinate 200 setzen (bezogen auf die Bühne) dot.y = 150; //dot an Y.Koordinate 150 setzen (bezogen auf die Bühne) addChild(dot); //dot auch wirklich anzeigen lassen code

Version2: Einen Partikel bei Mausklick hinzufügen
Ein Partikel soll nur dann hinzugefügt werden, wenn der Benutzer mit der Maus auf die Bühne klickt. Also packen wir den Code aus Version 1 in eine Funktion namens addParticle und sorgen dafür, dass diese Funktion vom Ereignis MouseEvent.CLICK aufgerufen wird. Damit es ein bisschen interessanter wird, setzen wir den neuen Partikel dort hin, wo die Maus gerade ist. code format="actionscript" function addParticle(e:Event):void {   var dot:MovieClip = new MovieClip; dot.graphics.lineStyle(3,Math.random*0xffffff,1); dot.graphics.drawCircle(0,0,20); dot.x = stage.mouseX; dot.y = stage.mouseY; dot.cacheAsBitmap = true; addChild(dot); } stage.addEventListener(MouseEvent.CLICK, addParticle); code

Version 3: Das Zeichnen in eine Funktion auslagern
Die Partikel sollen graphisch ein bisschen interessanter gestaltet werden, und damit der Code in addParticle übersichtlich bleibt, lagern wir das Zeichnen auf den Partikel in eine eigene Funktion aus - hier heisst sie drawOnto. Und damit auch auf den richtigen Partikel gezeichnet wird, schicken wir diesen gleich als Übergabewert mit in die Funktion. Wichtig ist natürlich, dass diese Funktion innerhalb von addParticle aufgerufen wird. code format="actionscript" function addParticle(e:Event):void {   var dot:MovieClip = new MovieClip; drawOnto(dot); //hier wird die Funktion zum Zeichen des Partikels aufgerufen, und der aktuelle Partikel gleich mitgeschickt dot.x = stage.mouseX; dot.y = stage.mouseY; addChild(dot); }

function drawOnto(dot:MovieClip):void{ var dotAlpha:Number = Math.random * 0.8 + 0.2; //also ein Wert zwischen 0.2 und 1 var dotColor:Number = Math.random*0xffffff; dot.graphics.lineStyle(3,dotColor,dotAlpha); dot.graphics.beginFill(dotColor, dotAlpha/2); //die Füllung ist halb so sichtbar wie der Rand var radius:Number = Math.random*15+5; //also zwischen 5 und 20 dot.graphics.drawCircle(0,0,radius); dot.graphics.endFill; }

stage.addEventListener(MouseEvent.CLICK, addParticle); code

Version 4: Die Partikel nach der Erstellung bewegen
Jetzt wollen wir dafür sorgen, dass sich Partikel nach ihrer Erstellung noch verändern können (z.B. bewegen). Dazu braucht es das Event ENTER_FRAME, dessen Listener wir an jeden Partikel anhängen. So ruft jeder Partikel bei jedem neuen Frame (also mehrmals pro Sekunde) die Funktion moveParticle auf. Innerhalb dieser Funktion sorgen wir einfach dafür, dass genau dieser Partikel ein kleines bisschen verschoben wird. code format="actionscript" function addParticle(e:Event):void {   var dot:MovieClip = new MovieClip; drawOnto(dot); dot.x = stage.mouseX; dot.y = stage.mouseY; dot.xMovement = Math.random * 10 - 5; //diese Variable wird direkt an DIESEN Partikel gehängt dot.yMovement = Math.random * 10 - 5; //so kann sich jeder Partikel seine eigenen Bewegungswerte merken dot.cacheAsBitmap = true; //das macht alles ein bisschen schneller, ist nur für grosse Partikelmengen wichtig addChild(dot);

dot.addEventListener(Event.ENTER_FRAME, moveParticle); }

function moveParticle(e:Event):void {   var thisDot:Object = e.currentTarget;  //so komme ich an den ursprünglichen Partikel (der, dessen EventListener diese Funktion aufgerufen hat) thisDot.x = thisDot.x + thisDot.xMovement; thisDot.y = thisDot.y + thisDot.yMovement; }

function drawOnto(dot:MovieClip):void {   var dotAlpha = Math.random * 0.8 + 0.2; var dotColor = Math.random*0xffffff; dot.graphics.lineStyle(3,dotColor,dotAlpha); dot.graphics.beginFill(dotColor, dotAlpha/2); var radius:Number = Math.random*15+5; dot.graphics.drawCircle(0,0,radius); dot.graphics.endFill; }

stage.addEventListener(MouseEvent.CLICK, addParticle); code

Version 5: Partikel automatisch erstellen
Die Partikel sollen auch ohne Klicken automatisch erstellt werden. Eigentlich ganz einfach, es muss nur das Event geändert werden. Anstatt code format="actionscript" stage.addEventListener(MouseEvent.CLICK, addParticle); code könnte man beispielsweise schreiben: code format="actionscript" stage.addEventListener(MouseEvent.MOUSE_MOVE, addParticle); code So gibt es immer dann neue Partikel, wenn die Maus bewegt wird (weitere Events finden sie unter Ereignisse auf diesem WIKI) Wenn die Partikel gänzlich ohne Benutzerinteraktion erscheinen sollen, könnte man wieder ENTER_FRAME benutzen: code format="actionscript" stage.addEventListener(Event.ENTER_FRAME, addParticle); code Das gibt jetzt allerdings sehr viele Partikel (Default ist 24 FPS - s. Eigenschaften der Bühne-, also 24 ENTER_FRAME Ereignisse und damit 24 neue Partikel pro Sekunde) Natürlich muss man nicht bei JEDEM neuen Frame addParticle aufrufen, z.B.: code format="actionscript" var frameCount:Number = 0; //Variable zum zählen von Frames function countFrames(e:Event){ //diese funktion zählt Frames und ruft nur bei jedem 24ten addParticle auf if(frameCount%24==0){ //bei jedem 24ten Frame, also ein Mal pro Sekunde addParticle(null); //das null wird mitgeschickt als Event-Dummy, sozusagen ein leeres Event }   frameCount++;  //frameCount immer um Eins erhöhen } stage.addEventListener(Event.ENTER_FRAME, countFrames); code Für zeitlich präzisere Aufrufe gibt es auch folgende Alternativ-Lösung, die ohne das Zählen von Frames auskommt und daher auch von der eingestellten Framerate unabhängig ist: code format="actionscript" //stage.addEventListener(MouseEvent.CLICK, addParticle); //ersetzen durch: var myTimer:Timer = new Timer(50); //eine Art Wecker, der alle 50 Millisekunden ein Event auslöst myTimer.addEventListener(TimerEvent.TIMER, addParticle); //eben dieses Event ruft dann addParticle auf myTimer.start; //nicht vergessen! der Timer muss noch gestartet werden code

Version 6: Nicht mehr benötigte Partikel wieder löschen
Jetzt haben wir doch schon eine recht hübsche Animation, nur kann nach einer gewissen Zeit ein Problem auftreten: Wir setzen ständig neue Partikel ein, und für jedes einzelne muss in jedem Frame neu berechnet werden, wo es sich gerade befindet. Da es auf die Dauer ziemlich viele Partikel werden können und da auch für die Partikel, die schon längst nicht mehr auf zu sehen sind, weiterhin die Positionen berechnet werden, muss der Computer immer mehr rechnen und wird irgendwann langsam. Die Lösung: nicht mehr benötigte Partikel sollen gelöscht werden. Im folgenden finden sie den finalen Code in zwei Varianten. Hinweis: Die Einzelheiten sind jetzte nicht mehr ganz einfach nachzuvollziehen, allerdings muss man auch bei Spielen manchmal (je nach Spiel) MovielClips löschen oder in Arrays speichern und falls das der Fall sein sollte, können sie auf diese Codes zurückgreifen.

Variante 6b: Partikel löschen sich selbst
In dieser Version merkt sich jeder Partikel, seit wie vielen Frames er bereits existiert. Aufgrund dieser Information kann er dann nach einer Weile sein Verhalten ändern oder gelöscht werden. Im Beispielcode beginnet jeder Partikel nach 50 Lebensframes, immer schneller nach unten zu fallen, und er wird gelöscht, wenn die Y-Koordinate grösser ist als die Bühne hoch, also wenn er nach unten aus dem Bild gefallen ist. code format="actionscript" //allgemeine Variablen //damit sie die ganze Zeit und für alle Funktionen zur Verfügung stehen, //muss man sie AUSSERHALB einer Funktion initialisieren var particleArray:Array = new Array; //neu, leere Liste machen var maxParticles:Number = 100;

//diese Funktion erstellt einen neuen Partikel-MovieClip und setzt ihn auf die Bühne function addParticle(e:Event):void { var dot:MovieClip = new MovieClip; //neuer, leerer MovieClip drawOnto(dot); //auf den etwas gezeichnet wird dot.x = stage.mouseX; //er wird an die momentane Position der Maus geschoben dot.y = stage.mouseY; dot.xMovement = Math.random * 10 - 5; //er merkt sich seine Bewegungsrichtung/-geschwindigkeit dot.yMovement = Math.random * 10 - 5; dot.age = 0; //er merkt sich sein Alter dot.cacheAsBitmap = true; //das macht die Anzeige ein bisschen schnellen addChild(dot); //er wird zur Bühne hinzugefügt, also jetzt auch angezeigt //jedes Partikel bekommt seinen eigenen EventListener, der in jedem neuen Frame //die Funktion moveParticle aufruft -> so kann er immer wieder verändert werden

// **** ACHTUNG ******* Mehr Argumente in addEventListener ! ********   dot.addEventListener(Event.ENTER_FRAME, moveParticle, false, 0, true ); // die Argumente 3 und 4 sind default (einfach so übernehmen) // das 5. sollte man auf true setzen --> macht das Entfernen leichter }

//diese Funktion bewegt den Partikel-MovieClip ein kleines Bisschen in x und y Richtung //aufgerufen wird sie in jedem Frame, als ca 30 mal in der Sekunde (je nach BPS-Einstellung, s. Eigenschaften der Bühne) //wie weit sich ein bestimmter Partikel jedes Mal bewegen soll, ist als Variable (xMovement & yMovement) //im Partikel selbst gespeichert, deswegen kann jeder Partikel seine eigene Richtung und Geschwindigkeit haben function moveParticle(e:Event):void { //herausfinden, um welchen Partikel es geht: man fragt das Event, welches die Funktion aufgerufen hat (an dem der Listener hängt) var thisDot:Object = e.currentTarget; thisDot.x = thisDot.x + thisDot.xMovement; thisDot.y = thisDot.y + thisDot.yMovement; thisDot.age++; //jeder Partikel zählt sein Alter (in Frames)

if (thisDot.age++ > 50){ //wenn der Partikel schon über 50 Frames lang lebt thisDot.yMovement = thisDot.yMovement+1; //bewegt er sich immer schneller nach unten }

if (thisDot.y > stage.stageHeight){ //wenn ein Partikel unten rausgefallen ist... thisDot.parent.removeChild(thisDot); //Partikel aus der DisplayListe entfernen thisDot.removeEventListener(Event.ENTER_FRAME, moveParticle); //Listerner entfernen //wenn man beim Erstellen des Listeners das 5. Argument auf true gesetzt hat (s. oben), dann ist dieser Schritt hier eigentlich überflüssig thisDot = null; //sicherstellen, dass der Partikel keine Referenzen mehr enthält } }

//diese Funktion zeichnet etwas auf den übergebenen MovieClip //im Moment wird ein Kreis mit zufälliger Farbe und Transparenz gezeichnet function drawOnto(dot:MovieClip):void { var dotAlpha:Number = Math.random * 0.8 + 0.2; var dotColor:Number = Math.random*0xffffff; dot.graphics.lineStyle(3,dotColor,dotAlpha); dot.graphics.beginFill(dotColor, dotAlpha/2); var radius:Number = Math.random*15+5; dot.graphics.drawCircle(0,0,radius); dot.graphics.endFill; }

//es soll alle 30 Millisekunden ein neuer Partikel erschaffen werden, also rufe ich die //Funktion addParticle mittels eines auf 30 eingestellten Timers (wiederholt) auf var myTimer:Timer = new Timer(30); myTimer.addEventListener(TimerEvent.TIMER, addParticle); myTimer.start; code

Variante 6b: Gesamtmenge der Partikel begrenzen
In dieser Version wird die maximale Anzahl von Patikeln auf 100 beschränkt. Dazu werden alle generierten Partikel in einer zentralen Liste (einem sogenannten Array) gespeichert. Ist die Liste zu voll, wird immer der erste (also älteste) Partikel gelöscht. code format="actionscript" //allgemeine Variablen //damit sie die ganze Zeit und für alle Funktionen zur Verfügung stehen, //muss man sie AUSSERHALB einer Funktion initialisieren var particleArray:Array = new Array; var maxParticles:Number = 100;

//diese Funktion erstellt einen neuen Partikel-MovieClip und setzt ihn auf die Bühne function addParticle(e:Event):void {   var dot:MovieClip = new MovieClip; //neuer, leerer MovieClip drawOnto(dot); //auf den etwas gezeichnet wird dot.x = stage.mouseX; //er wird an die momentane Position der Maus geschoben dot.y = stage.mouseY; dot.xMovement = Math.random * 10 - 5; //er merkt sich seine Bewegungsrichtung/-geschwindigkeit dot.yMovement = Math.random * 10 - 5; particleArray.push(dot); //er wird zur Liste mit allen Partikeln hinzugefügt (am Ende) dot.cacheAsBitmap = true; //das macht die Anzeige ein bisschen schnellen addChild(dot); //er wird zur Bühne hinzugefügt, also jetzt auch angezeigt if (particleArray.length >= maxParticles) //wenn die Partikelliste zu lang ist ... {       removeChild(particleArray.shift); //... wird der letzte Partikel in der Liste gelöscht }   //jedes Partikel bekommt seinen eigenen EventListener, der in jedem neuen Frame //die Funktion moveParticle aufruft -> so kann er immer wieder verändert werden dot.addEventListener(Event.ENTER_FRAME, moveParticle); }

//diese Funktion bewegt den Partikel-MovieClip ein kleines Bisschen in x und y Richtung //aufgerufen wird sie in jedem Frame, als ca 30 mal in der Sekunde (je nach BPS-Einstellung, s. Eigenschaften der Bühne) //wie weit sich ein bestimmter Partikel jedes Mal bewegen soll, ist als Variable (xMovement & yMovement) //im Partikel selbst gespeichert, deswegen kann jeder Partikel seine eigene Richtung und Geschwindigkeit haben function moveParticle(e:Event):void {   //herausfinden, um welchen Partikel es geht: man fragt das Event, welches die Funktion aufgerufen hat var thisDot:Object = e.currentTarget; //currentTarget ist das Object, zu dem der EventListener gehört thisDot.x = thisDot.x + thisDot.xMovement; thisDot.y = thisDot.y + thisDot.yMovement; }

//diese Funktion zeichnet etwas auf den übergebenen MovieClip //im Moment wird ein Kreis mit zufälliger Farbe und Transparenz gezeichnet function drawOnto(dot:MovieClip):void {   var dotAlpha:Number = Math.random * 0.8 + 0.2; var dotColor:Number = Math.random*0xffffff; dot.graphics.lineStyle(3,dotColor,dotAlpha); dot.graphics.beginFill(dotColor, dotAlpha/2); var radius:Number = Math.random*15+5; dot.graphics.drawCircle(0,0,radius); dot.graphics.endFill; }

//es soll alle 50 Millisekunden ein neuer Partikel erschaffen werden, also rufe ich die //Funktion addParticle mittels eines auf 50 eingestellten Timers (wiederholt) auf var myTimer:Timer = new Timer(50); myTimer.addEventListener(TimerEvent.TIMER, addParticle); myTimer.start; code (Die finale Version 6b)

Erweiterungen
Möglichen Erweiterungen sind kaum Grenzen gesetzt, hier nur einige Vorschläge:
 * Sorgen sie dafür, dass die Partikel immer grösser und blasser werden (Eigenschaften scale & alpha)
 * Die Partikel könnten rotieren (Eigenschaft rotation) - macht natürlich bei Kreisen keinen Sinn, also zeichnen sie etwas anderes
 * Die Partikel könnten sich beschleunigen, also zunehmend schneller nach aussen wegfliegen
 * Die Partikel könnten weiterhin (nicht nur beim Einsetzen) auf die Maus reagieren, z.B. auf sie zu oder von ihr weg fliegen
 * Die Partikel könnten am Aussenrand der Bühne abprallen, wenn dieser erreicht ist

Quelle
Der oben vorgestellte Partikeleffekt ist eine Abwandlung des AS3-Codes, der hier vorgestellt wird:
 * http://www.schoolofflash.com/2008/03/flash-cs3-particle-effect/

Inspiration
Eine Serie von ähnlichen graphischen Experimenten mit AS3 (inkl. source code) finden sie hier: Zumindest die ersten beiden Beispiele (00 & 01) sollten sie inzwischen eigentlich verstehen können - danach wird es noch ein bisschen komplizierter (und kreativer), aber vielleicht möchte sich ja jemand durchbeissen.
 * http://circlecube.com/category/generative-art/