|
Partikel |
Top Previous Next |
|
In diesem Workshop werden Sie lernen mit Partikeln zu arbeiten, den kleinen Bitmaps, die jedem Spiel viel Farbe und Aufregung verleihen. Jeder Partikeleffekt hat eine klare und präzise Struktur:
action particle_start // this can be a function as well { ............................ effect(particle_function, number_of_desired_particles, starting_position, initial_velocity); }
function particle_function() // this function is run by each and every particle { // set the properties and the speed of the particles here ............................ my.function = some_function; }
function some_function() // this (short) function tells the particles how to behave after they are emitted { ............................ }
Wenn Sie mit Partikeln arbeiten, werden Sie feststellen, dass 99% Ihrer Partikeleffekte diese Struktur verwenden. Schauen wir uns ein Beispiel an:
action damaged_lightbulb { while (1) { effect(effect_explo, 1000, my.x, normal); sleep (random(6) + 0.3); } }
function effect_explo() { var particle_direction; particle_direction.x = random(2) - 1; particle_direction.y = random(2) - 1; particle_direction.z = -random(2); vec_normalize(particle_direction, random(5)); vec_add(my.vel_x, particle_direction); my.alpha = 30 + random(65); my.flare = on; my.bright = on; my.move = on; my.function = fade_particle; }
function fade_particle() { my.alpha -= 1.2 * time_step; if (my.alpha < 0) {my.lifespan = 0;} }
Dies ist das erste Beispiel dieses Workshops; öffnen Sie work39.wmp, starten Sie es mit script39.wdl als Skript und Sie sehen den Effekt in Aktion.
Lassen Sie uns nun den Code durchgehen und schauen, was dort geschieht.
action damaged_lightbulb { while (1) { effect(effect_explo, 1000, my.x, normal); sleep (random(6) + 0.3); } }
Dies ist die Action, die der beschädigten Glühbirne zugeordnet ist; die While Schleife ruft die "effect" Anweisung, die für die Partikel zuständig ist, alle 0,3 bis 0,6 Sekunden auf. Schauen wir uns die Syntax von "effect" genauer an:
effect (particle_function_name, number_of_desired_particles, starting_position, initial_velocity); - particle_function_name ist der Name der Funktion, die den Partikeln sagt, wie sie sich verhalten sollen, Sie können hier also jeden Funktionsnamen verwenden. - number_of_desired_particles bezeichnet die Anzahl der Partikel, die erzeugt werden sollen. Für ein einzelnes Partikel genügt hier eine "1". Wie Sie sehen werden in unserem Beispiel 1000 Partikel erzeugt, wenn die "effect" Anweisung ausgeführt wird. - starting_position ist der Startpunkt der Partikel. Wenn Sie die Partikel aus der Nase eines Monsters kommen lassen wollen, müssen Sie nur die Koordinaten mit vec_for_vertex ermitteln und dort eintragen, alles klar? In diesem Beispiel verwenden wir einfach my.x, wodurch der Startpunkt der Partikel im Origin der Glühbirne festgelegt wird. - initial_velocity legt die Startgeschwindigkeit der Partikel fest. Da wir diese in der Funktion ohnhein ändern, reicht hier auch normal oder nullvector aus.
Jetzt können Sie Ihre Kreativität richtig ausleben; die folgende Funktion sagt den Partikeln, wie sie sich zu verhalten haben.
function effect_explo() { var particle_direction; particle_direction.x = random(2) - 1; particle_direction.y = random(2) - 1; particle_direction.z = -random(2);
Diese Funktion vergibt zufällige Geschwindigkeiten in x und y Richtung und zwar zwischen -1 und 1 und eine Geschwindigkeit, die bis -2 hinuntergeht in z Richtung. Das heißt, unser erstes Partikel könnte die Geschwindigkeit (0,5 ; -0,3 ; -1,2) erhalten, das zweite z.B. (0,2 ; 0,7 ; -0,1) und so weiter; wir erhalten somit 1000 Partikel, die sich alle mit einer anderen Geschwindigkeit bewegen.
vec_normalize(particle_direction, random(5)); vec_add(my.vel_x, particle_direction);
Die erste Codezeile normalisiert die Geschwindigkeit, oder einfacher ausgedrückt, die Geschwindigkeit wird auf den Wert random(5) skaliert. Damit kann man die Geschwindigkeit der Partikel beeinflussen, ohne ihre Richtung zu ändern. Wenn der Effekt also größer oder kleiner wirken soll, ohne den Streuradius zu ändern, können Sie die 5 einfach durch einen anderen Wert ersetzen. Die vec_add Zeile addiert die Geschwindigkeit zu vel_x und stellt so die Geschwindigkeit ein. Da wir zwei Vektoren addieren, werden vel_y und vel_z ebenfalls korrekt eingestellt.
my.alpha = 30 + random(65); my.flare = on; my.bright = on; my.move = on; my.function = fade_particle; }
Die letzten Zeilen sind einfacher zu verstehen! Sie legen eine zufällige Transparenz zwischen 30 und 95 fest, machen die Partikel transparent, setzen das "bright" Flag und erlauben ihnen, sich in Richtung ihres Geschwindigkeitsvektors zu bewegen. Die letzte Zeile sagt den Partikeln, dass sie sich von jetzt ab an die Anweisungen halten sollen, die in der Funktion fade_particle festgelegt sind.
function fade_particle() { my.alpha -= 1.2 * time_step; if (my.alpha < 0) {my.lifespan = 0;} }
Das sollte (und ist) eine sehr schnelle Funktion sein; hier wird die Transparenz in jedem Frame verringert und zwar mit der Geschwindigkeit -1,2 * time_step. Sollte der Faktor unter 0 fallen, setzen wir die "lifespan" des Partikels auf 0, wodurch es verschwindet; und das ist in diesem Fall auch sinnvoll, da es mit einem Alphawert unter 0 ohnehin unsichtbar ist.
Das Handbuch enthält eine Menge Parameter für Partikel, die geändert werden können; schauen wir uns einige an! Zunächst können wir die Farbe der Partikel ändern, sie z.B. bläulicher erscheinen lassen. Um dies zu tun, fügen wir eine einzige Codezeile zur effect_explo Funktion hinzu:
function effect_explo() { var particle_direction; particle_direction.x = random(2) - 1; particle_direction.y = random(2) - 1; particle_direction.z = -random(2); vec_normalize (particle_direction, random(5)); vec_add(my.vel_x, particle_direction); my.alpha = 30 + random(65); my.flare = on; vec_set(my.blue, vector(200, 100, 130)); // add this new line of code my.bright = on; my.move = on; my.function = fade_particle; }
Diese Zeile setzt die "Blau" Komponente auf 200, "grün" auf 100 und "rot" auf 130, genau wie .x, wo man die x, y und z Koordinaten beeinflussen kann. Alternativ liefert dies:
my.blue = 200; my.green = 100; my.red = 130;
das gleiche Ergebnis. Oh, a propos Ergebnis, so sehen die Partikel jetzt aus:
Schon besser, aber immer noch sehr pixelig; sie erinnern mich an die Partikeleffekte vom zweiten Teil eines berühmten Shooters, der vor vielen Jahren erschien. Mit einem schönen Bitmap können wir das (hoffentlich) ändern.
Zunächst muss die Bitmap definiert werden. Ich habe eine ganz gut aussehende light.tga erstellt, die verwendet werden sol; fügen Sie diese Codezeile oben im Skript ein:
BMAP light_tga = "light.tga";
Editieren Sie dann effect_explo nochmals, auf folgende Weise:
function effect_explo() { var particle_direction; particle_direction.x = random(2) - 1; particle_direction.y = random(2) - 1; particle_direction.z = -random(2); vec_normalize (particle_direction, random(5)); vec_add(my.vel_x, particle_direction); my.alpha = 30 + random(65); my.flare = on; vec_set(my.blue, vector(200, 100, 130)); my.bmap = light_tga; // add this new line of code my.bright = on; my.move = on; my.function = fade_particle; }
Dies hat unsere Partikel geändert, es sind nun keine Quadrate mehr sondern Bitmaps und sehen damit viel besser aus, sind aber etwas groß. Glücklicherweise können wir die Größe im Code ändern; fügen Sie eine weitere Zeile zu effect_explo hinzu:
function effect_explo() { var particle_direction; particle_direction.x = random(2) - 1; particle_direction.y = random(2) - 1; particle_direction.z = -random(2); vec_normalize (particle_direction, random(5)); vec_add(my.vel_x, particle_direction); my.alpha = 30 + random(65); my.flare = on; vec_set(my.blue, vector(200, 100, 130)); my.bmap = light_tga; my.size = 2; // this new line controls the size of the particle my.bright = on; my.move = on; my.function = fade_particle; }
Die Partikel haben eine voreingestellte Größe von 4, also wird ihre Größe automatisch auf 4 gesetzt, wenn wir die my.size Anweisung entfernen. Ich denke, dass die Partikel schon besser aussehen, aber ich hätte gern noch einen einfachen Effekt mit dynamischem Licht in der Gegend. Editieren Sie die Action damaged_lightbulb wie folgt:
action damaged_lightbulb { my.blue = 160; my.green = 100; my.red = 130; while (1) { my.lightrange = 500; // make the light bulb entity generate light on a radius of 500 quants effect(effect_explo, 1000, my.x, normal); sleep (0.1); // the dynamic light effect lasts for 0.1 seconds my.lightrange = 0; // extinguish the light bulb sleep (random(6) + 0.3); } }
Und so sieht der Effekt in Aktion aus:
Wir könnten auch ein Geräusch ertönen lassen, wenn die Funken erzeugt werden, aber das überlasse ich Ihnen als Hausaufgabe. Schauen wir uns einen anderen Partikeleffekt an: Kopieren Sie die folgenden Zeilen in Ihr script39.wdl Skript, ganz nach unten:
var max_particles = 50000; // allow the generation of up to 50,000 particles
BMAP barrier_tga = "barrier.tga"; // new bitmap, used for the particle barrier
function fade_barrier() { if (my.y < -400) {my.lifespan = 0;} }
function effect_barrier() { var particle_direction; particle_direction.x = 0; particle_direction.y = -50 - random(100); particle_direction.z = 0; vec_normalize (particle_direction, random(250)); vec_add(my.vel_x, particle_direction); my.alpha = 30 + random(65); my.flare = on; my.bmap = barrier_tga; my.size = 2; //my.beam = on; //my.streak = on; my.bright = on; my.move = on; my.function = fade_barrier; }
function particle_barrier_startup() { while (!key_b) {wait (1);} // wait until the player presses the "B" key while (1) { effect(effect_barrier, 10 / (0.1 + time_step), vector(900, 450, 50 + random(100)), nullvector); wait (1); } }
Starten Sie das Level, ignorieren Sie den bestehenden Effekt und drücken Sie dann "B", um die Barriere auszulösen.
Sie sehen eine Menge Partikel, die sich von der linken zur rechten Seite des Bildschirms bewegen; der Effekt sieht in Bewegung natürlich viel besser aus. Dieses Mal starten wir den Effekt mit Hilfe einer Funktion und nicht in einer Action.
function particle_barrier_startup() { while (!key_b) {wait (1);} // wait until the player presses the "B" key while (1) { effect(effect_barrier, 10 / (0.1 + time_step), vector(900, 450, 50 + random(100)), nullvector); wait (1); } }
Die Funktion wartet bis die "B" Taste gedrückt wird, dann werden in jedem Frame Partikel erzeugt. Die effect Anweisung verwendet dabei einige Tricks: - number_of_particles wird auf 10 / (0,1 + time_step) gesetzt. Das bedeutet, dass auf langsamen Rechnern, wo time_step groß ist, weniger Partikel erzeugt werden als auf schnellen Rechnern. Zum Beispiel wird ein Rechner mit 16 fps etwa 9 Partikel pro FRame erzeugen, wohingegen ein Rechner mit 100 fps immerhin etwa 55 Partikel erzeugt. - starting_position wird auf x = 900, y = 450 und z zwischen 50 und 150 gesetzt. Diese Werte habe ich im WED abgelesen, dort habe ich die Generatoren der Barriere erstellt (zwei Levelblocks). - initial_velocity wird am Anfang auf den Nullvektor gesetzt (überall 0), weil sich die Partikel nur entlang der y-Achse bewegen sollen, was folgende Funktion leistet.
function effect_barrier() { var particle_direction; particle_direction.x = 0; particle_direction.y = -50 - random(100); particle_direction.z = 0; vec_normalize (particle_direction, random(250)); vec_add(my.vel_x, particle_direction); my.alpha = 30 + random(65); my.flare = on; my.bmap = barrier_tga; my.size = 2; //my.beam = on; //my.streak = on; my.bright = on; my.move = on; my.function = fade_barrier; }
In der Funktion steckt die meiste Arbeit, wie üblich. Wir setzen eine negative Geschwindigkeit in y-Richtung, weil die Partikel sich in die entsprechende Richtung bewegen sollen, wie die Top-Sicht in WED zeigt. Unsere Partikel sehen nicht schlecht aus, aber besser wäre es, wenn sie eine Art Spur hinter sich herzögen, oder? Glücklicherweise kann dies erreicht werden, falls Ihre Acknex Version die Parameter "beam" und "streak" unterstützt; entfernen Sie den Kommentar von einer der Zeilen und betrachten Sie das Ergebnis.
Der Effekt wirkt wiederum in Bewegung deutlich besser. Ach ja, die Funktion, die sich nach der Initialisierung um die Partikel kümmert entfernt sie einfach, wenn ihre y-Koordinate unter -400 sinkt, weil die Partikel keine Kollisionserkennung haben (daher sind sie so schnell!)
function fade_barrier() { if (my.y < -400) {my.lifespan = 0;} }
Wie Sie sich denken können, tut die Partikelbarriere dem Spieler in keinster Weise weh, aber Sie können sie tödlich machen, wenn Sie einfach eine unsichtbare WMB-Entity an ihre Stelle plazieren, die dafür sorgt, dass die Gesundheit des Spielers auf 0 gesetzt wird, wenn er sich traut, sie zu berühren. In älteren Ausgaben finden Sie Beispiele hierfür.
Das letzte Beispiel zeigt uns weitere Tricks; der Effekt sieht folgendermaßen aus:
Kopieren Sie die folgenden Zeilen ins Skript:
var particle_gravity = 0; var particle_lifespan = 0;
BMAP earth_tga = "earth.tga";
function earth_fade() { my.lifespan = particle_lifespan; my.alpha -= 10 * time_step; if (my.alpha < 0) {my.lifespan = 0;} }
function particle_earth() { my.alpha = 10 + random(20); my.flare = on; my.bmap = earth_tga; my.size = 2; my.bright = on; my.gravity = particle_gravity; my.move = on; my.function = earth_fade; }
action particle_sphere { my.invisible = on; my.passable = on; var particle_pos; while (!key_e) {wait (1);} // wait until the player presses the "E" key my.skill99 = 0; while (1) { my.skill99 += time_step / 16; my.skill1 = 0; while (my.skill1 < ent_vertices (my)) // go through all the vertices { my.skill1 += 1; vec_for_vertex(particle_pos, my, my.skill1); effect(particle_earth, 1, particle_pos, nullvector); } if (my.skill99 > 3) // the sphere didn't move for 3 seconds? { my.roll += 3 * time_step; } if (my.skill99 > 7) // 7 seconds have passed? { my.pan += 2 * time_step; } if (my.skill99 > 10) // 10 seconds have passed? { my.tilt += 2 * time_step; } if (my.skill99 > 15) // 15 seconds have passed? { particle_lifespan = 10; particle_gravity = -0.5; } if (my.skill99 > 20) { my.scale_z = 1 + 0.5 * sin(total_ticks); } wait (1); } }
Starten Sie das Level und drücken Sie "E", um den Effekt zu starten; eine unsichtbare Erde (Kugel) wird als Model erscheinen und dreht sich um ihre Achsen, ändert dabei ihre Größe und so weiter. Die zgehörige Action geht die Vertizes durch und generiert überall einen Partikel.
Dieses Mal habe ich die Lebensdauer der Partikel und die Schwerkraft direkt gesetzt. Ja, jedes Partikel bewegt sich automatisch hoch oder runter, selbst wenn die Geschwindigkeit in z-Richtung gleich 0 ist, solange die gravity auf einen Wert ungleich 0 gesetzt ist. Wenn Sie diesen Workshop Schritt für Schritt durchgehen wollen, verwenden Sie script39_init.wdl als Ausgangspunkt; script39.wdl enthält allen Code, Sie können also direkt alles ausprobieren.
Der Workshop ist damit beendet, aber ich ermutige Sie dazu, Ihre eigenen Partikeleffekte zu erstellen; Sie finden auch viele weitere Beispiele (sehr einfache bis fortgeschrittene) in älteren Ausgaben vom AUM.
|