Die Stardust Particle Engine bietet zwei Hauptansätze für die freie Manipulation der Partikelbewegung, nämlich Gravitationsfelder und Deflektoren. Gravitationsfelder sind Vektorfelder, die die Beschleunigung eines Partikels beeinflussen, und Ablenkelemente beeinflussen sowohl die Position als auch die Geschwindigkeit eines Partikels.
Der erste Teil dieses Tutorials behandelt die Grundlagen der Teilchenbewegung und der Schwerefelder. Außerdem wird gezeigt, wie Sie eigene Gravitationsfelder erstellen. Der zweite Teil konzentriert sich auf Deflektoren und wie man benutzerdefinierte Deflektoren erstellt.
Um das Tutorial weiter lesen zu können, müssen Sie sich zunächst mit den Grundkenntnissen von Stardust vertraut machen. Wenn Sie nicht mit Stardust vertraut sind, können Sie sich mein vorheriges Tutorial zum Thema "Shoot out Stars mit Stardust Particle Engine" ansehen, bevor Sie fortfahren.
Werfen wir einen Blick auf das Endergebnis, auf das wir hinarbeiten werden. Dies ist ein Beispiel eines benutzerdefinierten Wirbelgravitationsfeldes.
Es ist Zeit für einen kurzen Rückblick auf die Physik der High School. Erinnern Sie sich an grundlegende Kinematik? Es geht um Verdrängung, was nur eine schickere Art ist, "Position" zu sagen, und sein Verhältnis zur Zeit. Für den Umfang dieses Tutorials benötigen wir nur ein recht einfaches Verständnis des Themas.
Verschiebung bezeichnet die aktuelle Position eines Objekts. In diesem Tutorial handelt es sich bei den "Objekten" hauptsächlich um Partikel im 2D-Raum. Im 2D-Raum wird die Verschiebung eines Objekts durch einen 2D-Vektor dargestellt.
Die Geschwindigkeit eines Objekts gibt an, wie schnell sich die Position eines Objekts ändert und in welche Richtung es geändert wird. Die Geschwindigkeit eines Objekts im 2D-Raum wird auch durch einen 2D-Vektor dargestellt. Die x- und y-Komponenten des Vektors stellen die Richtung der Positionsänderung dar, und der absolute Wert des Vektors gibt die Geschwindigkeit des Objekts an, d. H. Wie schnell sich das Objekt bewegt.
Die Beschleunigung ist die Geschwindigkeit, wie die Geschwindigkeit die Verschiebung ist. Die Beschleunigung eines Objekts gibt an, wie schnell sich die Geschwindigkeit eines Objekts ändert und in welche Richtung. Genau wie die Geschwindigkeit eines Objekts im 2D-Raum wird die Beschleunigung eines Objekts durch einen 2D-Vektor dargestellt.
Erwähnenswert ist auch das Konzept der Vektorfelder. Sie können ein Vektorfeld grundsätzlich als Funktion anzeigen, die einen Vektor als Eingabe nimmt und einen anderen Vektor ausgibt. Gravitationsfelder sind eine Art Vektorfeld, das Positionsvektoren als Ein- und Ausgabebeschleunigungsvektoren verwendet. In der Physik-Simulation wird zum Beispiel normalerweise eine einheitliche Schwerkraft nach unten auf alle Objekte angewendet. In diesem Fall ist das Gravitationsfeld, das die Schwerkraft darstellt, ein Vektorfeld, das einen konstanten Vektor (nach unten zeigend) ausgibt, unabhängig von den Eingabepositionsvektoren.
Dies ist eine visualisierte Grafik eines Vektorfeldes. Der Ausgangsvektor eines gegebenen Eingangsvektors (1, 2) ist (0,5, 0,5), während der Ausgang eines Eingangs (4, 3) (-0,5, 0,5) ist..
Das Feld
Die Klasse in Stardust repräsentiert ein 2D - Vektorfeld und dessen 3D - Gegenstück, das Field3D
Klasse repräsentiert ein 3D-Vektorfeld. In diesem Lernprogramm konzentrieren wir uns nur auf 2D-Vektorfelder.
Das Field.getMotionData ()
Methode dauert a Particle2D
Objekt, das die 2D-Positions- und Geschwindigkeitsinformationen eines Partikels als Parameter enthält. Diese Methode gibt a zurück MotionData2D
object, ein 2D-Vektor "Wertobjekt", das aus X- und Y-Komponenten besteht. Kombiniert mit dem Schwere
Aktion, a Feld
Das Objekt kann als Gravitationsfeld verwendet werden, dessen Ausgabe zur Manipulation der Teilchengeschwindigkeit verwendet wird.
Das ist alles für unsere Physik-Zusammenfassung. Jetzt ist es Zeit für echtes Stardust-Zeug.
Wie bereits erwähnt, die Schwere
Aktionsklasse macht Gebrauch von Feld
Objekte als Gravitationsfelder, um die Teilchengeschwindigkeit zu beeinflussen. So erstellen Sie ein einheitliches Vektorfeld, ein Vektorfeld, das unabhängig von der Eingabe einen konstanten Vektor zurückgibt, und es in einen umschließen Schwere
Aktion.
// ein einheitliches Vektorfeld erstellen, das nach unten zeigt (positive Flash-Koordinate bedeutet "nach unten") var Feld: Feld = new UniformField (0, 1); // Erstellen einer Schwerkraftaktion Var Schwerkraft: Schwerkraft = neue Schwerkraft (); // füge das Feld zur Aktion der Schwerkraft hinzu gravity.addField (Feld);
Diese Schwere
action ist jetzt bereit, auf dieselbe Weise wie andere normale Stardust-Aktionen verwendet zu werden.
// füge die Schwerkraftwirkung zu einem Emitter hinzu emitter.addAction (Schwerkraft);
Wir erzeugen einen windigen Regeneffekt mit dem Schwere
Aktion.
Erstellen Sie ein neues Flash-Dokument, wählen Sie eine dunkle Farbe für den Hintergrund, zeichnen Sie einen Regentropfen auf der Bühne und konvertieren Sie den Regentropfen in ein Movieclip-Symbol, das für ActionScript mit dem Klassennamen "Regentropfen" exportiert wird. Löschen Sie anschließend die Regentropfen-Instanz auf der Bühne.
Jetzt erstellen wir eine AS-Datei für die Dokumentenklasse und eine AS-Datei für den Regenemitter. Ich werde den Code hier nicht erklären, da ich bereits in meinem vorherigen Tutorial auf die grundlegende Verwendung von Stardust eingegangen bin. Wenn Sie nicht mit Stardust vertraut sind oder eine Erfrischung benötigen, empfehle ich dringend, dass Sie mein vorheriges Lernprogramm lesen, bevor Sie fortfahren.
Dies ist die Dokumentenklasse.
Paket import flash.display. *; import flash.events. *; importieren Sie idv.cjcat.stardust.common.emitters. *; Importieren von idv.cjcat.stardust.common.renderers. *; Importieren Sie idv.cjcat.stardust.twoD.renderers. *; public class WindyRain erweitert Sprite private var emitter: Emitter; privater var-Renderer: Renderer; öffentliche Funktion WindyRain () emitter = new RainEmitter (); Renderer = neuer DisplayObjectRenderer (this); renderer.addEmitter (Sender); addEventListener (Event.ENTER_FRAME, mainLoop); private Funktion mainLoop (e: Event): void emitter.step ();
Und dies ist die Emitterklasse, die in der Dokumentenklasse verwendet wird.
Paket import idv.cjcat.stardust.common.clocks. *; idv.cjcat.stardust.common.initializers importieren. *; import idv.cjcat.stardust.common.math. *; importieren Sie idv.cjcat.stardust.twoD.actions. *; idv.cjcat.stardust.twoD.emitters importieren. *; idv.cjcat.stardust.twoD.initializers importieren. *; importieren Sie idv.cjcat.stardust.twoD.zones. *; public class RainEmitter erweitert Emitter2D public function RainEmitter () super (new SteadyClock (1)); // Initialisierer addInitializer (new DisplayObjectClass (Raindrop)); addInitializer (neue Position (neue RectZone (-300, -40, 940, 20))); addInitializer (neue Geschwindigkeit (neue RectZone (-0,5, 2, 1, 3))); addInitializer (neue Masse (neues UniformRandom (2, 1)))); addInitializer (neue Skala (neues UniformRandom (1, 0.2))); // Aktionen addAction (new Move ()); addAction (neu orientiert (1, 180)); addAction (neue DeathZone (neue RectZone (-300, -40, 960, 480), true));
So sieht unser derzeitiger Fortschritt aus.
Jetzt machen wir den Regeneffekt windig, indem wir ein einheitliches Gravitationsfeld hinzufügen, das die Regentropfen nach rechts "zieht". Fügen Sie den folgenden Code in den Konstruktor von ein RainEmitter
Klasse.
// ein einheitliches Feld erstellen, das immer (0.5, 0) zurückgibt var Feld: Field = new UniformField (0.5, 0); // Partikelmasse berücksichtigen field.massless = false; // Erzeuge eine Schwerkraftaktion und füge das Feld hinzu. var Schwerkraft: Schwerkraft = neu Schwerkraft (); gravity.addField (Feld); // füge die Schwerkraftaktion zum Emitter hinzu addAction (Schwerkraft);
Beachten Sie, dass wir das einstellen Field.massless
property auf false, was standardmäßig true ist. Wenn diese Eigenschaft auf true gesetzt ist, bewirkt diese Eigenschaft, dass Felder wie gewöhnliche Gravitationsfelder wirken und alle Objekte unabhängig von ihrer Masse gleichermaßen beeinflussen. Wenn jedoch die Eigenschaft auf false gesetzt ist, wird die Partikelmasse berücksichtigt: Partikel mit größerer Masse werden weniger durch das Feld beeinflusst, wohingegen Partikel mit geringerer Masse stärker betroffen sind. Deshalb haben wir die verwendet Masse
Initialisierung in unserem vorherigen Emittercode, um den Regeneffekt etwas zufällig zu gestalten.
Testen Sie den Film erneut, und so sieht unser Ergebnis aus. Regentropfen sind nun von einem Schwerefeld betroffen und werden alle nach rechts "gezogen".
Jetzt tauschen wir die UniformField
Objekt mit einem BitmapField
Objekt, das Vektorfelder basierend auf den Farbkanälen einer Bitmap zurückgibt, um einen Turbulenz-Effekt zu erzeugen. Wenn Sie eine Weile mit ActionScript gearbeitet haben, erwarten Sie möglicherweise die Verwendung von BitmapData.perlinNoise ()
Methode, wenn wir an Turbulenzen denken, und genau das werden wir tun.
So sieht ein Beispiel für ein Perlin-Rauschbit aus. Perlin-Rauschen ist ein hervorragender Algorithmus zur Erzeugung von Rauschen zur Simulation von Turbulenzen, Wasserwellen, Wolken usw. Weitere Informationen zum Perlin-Rauschen finden Sie hier.
Sie fragen sich vielleicht, ob wir das verwenden werden BitmapData.perlinNoise ()
Methode zur Erzeugung einer Perlin-Rausch-Bitmap. Wie wird diese Bitmap als Vektorfeld verwendet? Nun, das ist was der BitmapField
Klasse ist für. Es nimmt eine Bitmap und konvertiert sie in ein Vektorfeld.
Nehmen wir an, wir haben ein Bitmap-Feld, dessen X-Kanal ist eingestellt auf rot und Y-Kanal ist Grün. Das heißt, wenn das Feld einen Eingabevektor nimmt, beispielsweise (2, 3), blickt es bei (2, 3) zum Pixel der Bitmap hoch und die X-Komponente des Ausgangsvektors wird aus dem roten Kanal des Pixels und der Y-Komponente bestimmt bestimmt aus dem grünen Kanal. Wenn die Komponenten eines Eingabevektors keine Ganzzahlen sind, werden sie zuerst gerundet.
Der Wert eines Farbkanals reicht von 0 bis 255, wobei 127 der Durchschnitt ist. Ein Wert unter 127 wird vom Bitmap-Feld als negativ betrachtet, während ein Wert größer als 127 positiv ist. Null ist das am negativsten Nummer und 255 ist die am positivsten ein. Wenn wir beispielsweise ein Pixel mit der Farbe 0xFF0000 in Hexadezimaldarstellung haben, das heißt, ein roter Kanal mit dem Wert 255 und ein grüner Kanal mit 0, dann wäre die Ausgabe des Bitmap-Felds für dieses Pixel ein Vektor mit der X-Komponente von a am positivsten mögliche Anzahl und Y-Komponente von a am negativsten mögliche Anzahl, wo dies möglich ist höchst positive / negative mögliche Zahl, oder Maximale Anzahl, ist spezifisch für das Bitmap-Feld. Genauer gesagt, hier ist die Formel der Pixel-Vektor-Umwandlung.
Erstellen Sie ein neues Flash-Dokument. Zeichnen Sie einen Pfeil auf der Bühne, konvertieren Sie ihn in ein Symbol mit dem Namen "Pfeil" und exportieren Sie es für ActionScript.
Legen Sie eine AS-Datei für die Dokumentenklasse an. Dies ist fast das gleiche wie im vorherigen Beispiel.
Paket import flash.display. *; import flash.events. *; importieren Sie idv.cjcat.stardust.common.emitters. *; Importieren von idv.cjcat.stardust.common.renderers. *; Importieren Sie idv.cjcat.stardust.twoD.renderers. *; öffentliche Klasse Turbulenz erweitert Sprite private var emitter: Emitter; privater var-Renderer: Renderer; öffentliche Funktion Turbulence () emitter = new ArrowEmitter (); Renderer = neuer DisplayObjectRenderer (this); renderer.addEmitter (Sender); addEventListener (Event.ENTER_FRAME, mainLoop); private Funktion mainLoop (e: Event): void emitter.step ();
Erstellen Sie eine weitere AS-Datei für unsere Emitterklasse.
package import idv.cjcat.stardust.common.actions. *; idv.cjcat.stardust.common.clocks importieren. *; idv.cjcat.stardust.common.initializers importieren. *; import idv.cjcat.stardust.common.math. *; importieren Sie idv.cjcat.stardust.twoD.actions. *; idv.cjcat.stardust.twoD.emitters importieren. *; idv.cjcat.stardust.twoD.initializers importieren. *; importieren Sie idv.cjcat.stardust.twoD.zones. *; public class ArrowEmitter erweitert Emitter2D public function ArrowEmitter () super (new SteadyClock (1)); // Initialisierer addInitializer (new DisplayObjectClass (Pfeil)); addInitializer (neues Leben (neues UniformRandom (50, 10))); addInitializer (neue Position (neuer SinglePoint (320, 200)))); addInitializer (neue Geschwindigkeit (neue LazySectorZone (3, 2))); addInitializer (neue Masse (neues UniformRandom (2, 1)))); addInitializer (neue Skala (neues UniformRandom (1, 0.2))); // Aktionen addAction (neues Zeitalter ()); addAction (neues DeathLife ()); addAction (new Move ()); addAction (new Oriented ()); addAction (neue ScaleCurve (10, 10));
Der aktuelle Fortschritt sieht so aus.
Fügen Sie den folgenden Code hinzu, der im Emitterkonstruktor 641 x 480-Bit-Perlin-Rauschbitmapdaten erstellt. Für detaillierte Erklärungen zu jedem Parameter des BitmapData.perlinNoise ()
Methode können Sie auf diese Dokumentation verweisen. Zur Vereinfachung erstellt der folgende Code eine Perlin-Rausch-Bitmap mit "Oktaven", die ungefähr die Größe 50X50 haben, und das Rauschen besteht aus roten und grünen Farbkanälen.
// Erstellen eines Perlin-Rauschbitmap-Daten var-Rauschens: BitmapData = new BitmapData (640, 400); noise.perlinNoise (50, 50, 1, 0, wahr, wahr, 1 | 2);
Als nächstes erstellen Sie eine BitmapField
Objekt und weisen ihm die Bitmap-Daten durch aktualisieren()
Methode. Dann der Rest des Codes über die Schwere
Aktion ist genau das gleiche wie im vorherigen Beispiel.
// Erzeuge ein einheitliches Feld, das immer (0.5, 0) zurückgibt. var field: BitmapField = new BitmapField (); field.channelX = 1; // setze X Channel auf rot field.channelY = 2; // Y-Kanal auf grünes Feld setzen.max = 1; // Setze den absoluten Wert der maximalen Vektorkomponente field.update (noise); // das Feld mit der Rausch-Bitmap aktualisieren // Partikelmasse berücksichtigen field.massless = false; // Erzeuge eine Schwerkraftaktion und füge das Feld hinzu. var Schwerkraft: Schwerkraft = neu Schwerkraft (); gravity.addField (Feld); // füge die Schwerkraftaktion zum Emitter hinzu addAction (Schwerkraft);
Testen Sie den Film jetzt noch einmal und Sie werden sehen, dass unsere fliegenden Pfeile jetzt Turbulenzen erleben.
Wir haben die verwendet UniformField
und BitmapField
von Stardust zur Verfügung gestellt, und jetzt werden wir unsere eigenen benutzerdefinierten Felder erstellen, indem wir die Feld
Klasse und das Überschreiben getMotionData2D ()
Methode.
Das getMotionData2D
nimmt ein Particle2D
Parameter als Eingabe, der die Positionsvektorinformationen des Partikels enthält, und dies ist die Eingabe in das Feld. Die Methode gibt a zurück MotionData2D
Objekt, das die Ausgabe des Feldes darstellt. Das ist alles, was Sie wissen müssen, um ein benutzerdefiniertes Feld zu erstellen. Erstellen wir ein benutzerdefiniertes Vortex-Feld.
Unten sehen Sie die grafische Darstellung unseres Wirbelfeldes. Es ist ziemlich selbsterklärend, warum es ein Wirbelfeld genannt wird.
Hier ist die Formel für unser Wirbelfeld.
Und die Vortex-Feldklasse ist so einfach wie der folgende Code. Wir haben den Gebrauch gemacht Vec2D
Klasse, um die ganze schmutzige Arbeit zu erledigen, indem Sie einen Vektor um 90 Grad im Uhrzeigersinn drehen und den absoluten Wert des Vektors einstellen. Dann geben wir die x- und y-Komponenten des Vektors in a aus MotionData2D
object, das vom Objekttyp ist, der zurückgegeben werden soll.
package import idv.cjcat.stardust.twoD.fields. *; import idv.cjcat.stardust.twoD.geom. *; importieren Sie idv.cjcat.stardust.twoD.particles. *; public class VortexField erweitert Field public var centerX: Number; public var centerY: Anzahl; öffentliche var festigkeit: anzahl; öffentliche Funktion VortexField (centerX: Number = 0, centerY: Number = 0, Stärke: Number = 1) this.centerX = centerX; this.centerY = centerY; diese.Stärke = Stärke; Überschreibe die geschützte Funktion berechneMotionData2D (Partikel: Particle2D): MotionData2D var dx: Number = Partikel.x - centerX; var dy: Anzahl = Teilchen.y - centerY; var vec: Vec2D = neues Vec2D (dx, dy); vec.Länge = Stärke; vec.rotateThis (90); Rückgabe neuer MotionData2D (vec.x, vec.y);
Nachdem wir nun unser benutzerdefiniertes Feld haben, testen wir es im folgenden Beispiel.
Dieses Beispiel dient als Testfahrt für unser Wirbelvektorfeld. Es ist so einfach wie ein Feld mit einem neuen zu tauschen. Ändern Sie den folgenden Code aus dem vorherigen Beispiel
// Erzeuge ein einheitliches Feld, das immer (0.5, 0) zurückgibt. var field: BitmapField = new BitmapField (); field.channelX = 1; // setze X Channel auf rot field.channelY = 2; // Y-Kanal auf grünes Feld setzen.max = 1; // setze die maximale vecotr length field.update (Noise); // Aktualisieren Sie das Feld mit der Rausch-Bitmap
zu diesem
// Erzeuge ein Wirbelfeld um (320, 200) mit der Stärke 1 var field: VortexField = new VortexField (); Feld.ZentrumX = 320; field.centerY = 200; Feldstärke = 1;
Und wir sind fertig. Sie können den Film testen und den Wirbeleffekt sehen. Süss!
Sie haben gesehen, wie Sie das verwenden Schwere
Aktion und Feld
Klasse, um die Partikelgeschwindigkeit zu beeinflussen. Und Sie haben gelernt, wie Sie Ihre eigenen benutzerdefinierten Vektorfelder erstellen, die als Gravitationsfelder verwendet werden. Im nächsten Teil dieses Tutorials erfahren Sie, wie Sie mithilfe von Deflektoren Partikelposition und -geschwindigkeit gleichzeitig manipulieren können.
Vielen Dank fürs Lesen!