Planet Survivors

In diesem Monat macht das Raumschiff des Spielers eine Bruchlandung auf einem unbekannten Planeten – der Spieler springt hinaus, erhält etwas primitiven Bewegungscode (damit die Umgebung erkundet werden kann) und eine Waffe mit unbegrenzter Munition (bislang). Das Level stammt von Nemisis, meinem Planet Survivors Partner :) und Sie können alle Maps und Wads im Archiv finden. Schauen wir uns die neuen Actions und Funktionen in der level2.wdl an:

function ship_explosion(coordinates)
{
    var number_of_gibbits;
    effect (explosion_core, 10 + random(10), coordinates, nullvector);
    sleep (0.3);
    ent_create (explosion_pcx, coordinates, explosion_sprite2);
    sleep (0.1);
    number_of_gibbits = random(15) + 5;
    while (number_of_gibbits > 0) // while without wait!
    {
       ent_create (gibbit_mdl, coordinates, move_gibbits);
       number_of_gibbits -= 1;
    }
}

Der Spieler gerät in ein Asteroidenfeld und dieses Mal können die metallisch aussehenden Asteroiden nicht zerstört werden; das Schiff des Spielers wird stark beschädigt und Sie werden einen schönen Explosionseffekt sehen. Ich werde Ihnen an dieser Stelle noch nicht verraten, wie der funktioniert; ich nutze den gleichen Effekt, der im Artikel “Explosionseffekte für Fortgeschrittene” weiter unten beschrieben wird und Sie werden in dem Artikel auch lernen, wie Sie sogar noch bessere Effekte erzeugen können.

action metal_asteroid // unbreakable asteroids
{
    while (first_boss != null) {wait (1);}
    sleep (3);
    my.x -= 33000;
    my.scale_x = 2 + random(5); // set a random scale on x, y, z
    my.scale_y = 2 + random(5);
    my.scale_z = 2 + random(5);
    asteroid_speed.x = -15 * time; // the metal asteroids have a big speed
    asteroid_speed.y = 0;
    asteroid_speed.z = 0;
    my.skill1 = 4 - random(8); // set random rotation (pan, tilt, roll) speeds
    my.skill2 = 4 - random(8);
    my .skill3 = 4 - random(8);
    while (my.x > -300)
    {
        move_mode = ignore_you + ignore_passable;
        ent_move (nullvector, asteroid_speed);
        my.pan += my.skill1 * time;
        my.tilt += my.skill2 * time;
        my.roll += my.skill3 * time;
        wait (1);

Diese Asteroiden warten bis der erste Boss (das große Schiff am Levelende) zerstört ist; wenn Sie diese Zeile auskommentieren, kommen Sie direkt ans Levelende. Wenn der Endgegner Geschichte ist, werden die Asteroiden um 33.000 Quants in die Nähe des Spielers bewegt, weil sie sich vorher nicht bewegt haben und schnell eine große Strecke zurücklegen müssen. Wir geben ihnen eine zufällige Größe in x, y und z-Richtung und stellen ihre x-Geschwindigkeit ein. Ebenso wird eine zufällige Rotationsgeschwindigkeit (-4 bis 4) für Pan, Tilt und Roll festgelegt und dann bewegen wir die Asteroiden in einer Schleife.

        if ((vec_dist (player.x, my.x) < 100) && (ship_down == 0))
        {
            ship_down = 1;
            players_shield = 0;
            ship_explosion (vector(player.x, player.y, player.z + 20));
            snd_play (explostart_wav, 100, 0);
            while (player.z > -10000)
            {
                 player.z -= 100 * time;
                 player.roll += 25 * time;
                 wait (1);
            }
            level_load (level3_wmb);
        }
        if (ship_down == 1)
        {
             my.passable = on;
        }
     }
    ent_remove (my); // remove the asteroids as soon as they can't be seen
}

Wenn der Spieler das erste Mal auf 100 Quants an einen der Asteroiden herangekommen ist, werden die Schilde des Spielers auf 0 gesetzt. Das erlaubt uns, die Kontrolle zu übernehmen, weil sich der Spieler nun nicht mehr bewegen kann. 20 Quants über dem Schiff wird eine Explosion erzeugt, ein Geräusch ertönt und dann bewegen wir das Schiff nach unten, wobei wir den Roll Winkel ändern. Sobald das Schiff unter -10.000 Quants fällt, laden wir das nächste Level (level3.wmb). Alle Asteroiden werden auf passierbar gesetzt, damit sie nicht ineinander hängenbleiben, wenn der Abstand sehr gering ist. Die letzte Codezeile entfernt die Asteroiden, wenn man sie nicht mehr sehen kann (also wenn ihre x-Position kleiner als –300 Quants ist).

action halo_flare
{
    my.ambient = 100;
    my.transparent = on;
    my.bright = on;
    my.light = on;
    my.lightred = 255;
    my.lightgreen = 255;
    my.lightblue = 255;
    my.lightrange = 0;
    my.facing = on;
    my.passable = on;
    while(1)
    {
        my.alpha = min(100, vec_dist(my.x, camera.x) / 20);
        my.scale_x = min(3, my.alpha / 50);
        my.scale_y = my.scale_x;
        wait(1);
    }
}

action crystal_glow
{
    my.transparent = on;
    my.bright = on;
    my.ambient = 100;
    my.light = on;
    my.lightred = 255;
    my.lightgreen = 255;
    my.lightblue = 100;
    my.lightrange = 0;
}

Diese beiden Actions kontrollieren die Lichtsprites und Laternen, die auf dem ersten Bild oben betrachtet werden können. Die Sprites sind passierbar, werden durch weißes Licht erhellt (RGB = (255, 255, 255)) und sind zur Kamera ausgerichtet. Die Distanz zur Kamera wird in einer Schleife aktualisiert und darauf basiert der Transparenzfaktor. Die Skalierung kann bis auf das Dreifache anwachsen. Die Laternen haben einen gelben Glanz.

starter level3_camera()
{
    while (level_number != 3) {wait (1);}
    while (player == null) {wait (1);}
    camera.x = 20000;
    camera.y = 9600;
    camera.z = -500;
    camera.pan = 110;
    camera.tilt = 0;
    camera.roll = 0;
}

Diese Codezeilen setzen die Kamera auf die Anfangsposition für das 3. Level. Ich habe mich für eine Starter Funktion entschieden, die beim Spielstart läuft, daher nutze ich zwei Schleifen, um sicherzustellen, dass wir im 3. Level sind und dass das Schiff des Spielers geladen ist. Die letzten Zeilen setzen die Kamera auf eine geeignet Position mit entsprechender Ausrichtung.

action player_level3
{
    player = my;
    my.ambient = -50;
    level_number = 3;
    my.scale_x = 5;
    my.scale_y = my.scale_x;
    my.scale_z = my.scale_x;
    my.x = 10000;
    my.y = 28000;
    my.z = 8000;
    my.pan = 295; // and angles
    my.tilt = -50;
    my.skill1 = 15000;
    while (my.skill1 > 100)
    {
       vec_set (temp, my.x);
       temp.z -= 15000;
       trace_mode = ignore_me + ignore_you + ignore_passable;
       my.skill1 = trace (my.x, temp);
       my.roll += 20 * time;
       my.x += 70 * time;
       my.y -= 125 * time;
       my.z -= 120 * time;
       effect (particle_smoke, random(10) + 5, my.x, nullvector);
       wait (1);
    }

Diese Action wird dem abstürzenden Schiff in Level 3 zugewiesen. Wir stellen eine günstige Position und Ausrichtung ein, setzen skill1 auf einen riesigen Wert (15.000) und bewegen das Schiff nach unten, bis seine Distanz zum Terrain unter 100 Quants fällt. Das ist eine simple und zugleich effektive Methode, die es uns erlaubt, ein Schiff an einem bestimmten Ort zu landen, ohne auf Pfade oder andere Methoden zurückgreifen zu müssen, die wegen der hohen Geschwindigkeiten nicht gut funktionieren würden. Wir lassen das Schiff trudeln, indem wir den Roll erhöhen und erzeugen Rauch mit Hilfe der particle_smoke Funktion aus explosions.wdl; vergleichen Sie hierzu wieder den Artikel über Explosionen.

   snd_play (explomid_wav, 20, 0);
   my.skill1 = 0;
   while (my.skill1 < 100)
   {
       my.skill1 += 10 * time;
       camera.roll = 2 - random(4);
       wait (1);
   }
   sleep (3);
   ent_create (myhero_mdl, my.x, move_player);
   while (player_1st == null) {wait (1);}
   while (vec_dist (player_1st.x, my.x) < 2000)
   {
       effect (particle_smoke, random(3) + 2, vector(my.x, my.y + 80, my.z + 200), nullvector);
       wait (1);
   }
}

Das Schiff ist am Boden, also lassen wir explomid.wav ertönen und setzen skill1 zurück, weil wir diesen Wert als Zähler in einer Schleife verwenden wollen, in der die Kamera durch Änderung des Roll Winkels durchgeschüttelt wird. Wir warten 3 weitere Sekunden, erstellen dann das Model für den Spieler und geben ihm die “move_player” Action. Wir müssen warten, bis der Spieler existiert und erzeugen dann dünneren Rauch bis der Spieler sich um mindestens 2000 Quants vom Schiff fortbewegt hat.

Schauen wir uns den Bewegungscode für den Spieler an:

function move_player()
{
    var players_speed;
    var track2_playing = 0;
    player_1st = my;
    player = null;
    my.invisible = on;
    players_shield = 25;
    players_ammo = 30;
    my.x = 14830;
    my.y = 19420;
    my.z = -80;
    my.pan = 300;
    my.tilt = -50;
    sleep (1);
    camera.x = my.x;
    camera.y = my.y;
    camera.z = my.z;
    camera.pan = my.pan;
    camera.tilt = my.tilt;
    snd_loop (wind3_wav, 15, 0);
    snd_play (smoked_wav, 100, 0);
    sleep (3);

Unser Spieler ist nun kein Schiff mehr sondern ein Mensch, richtig? Deshalb benutzen wir von jetzt an den neuen player_1st Pointer. Der Spieler ist unsichtbar (in der Ego-Perspektive müssen wir das Model nicht sehen) und hat 25 Punkte Gesundheit und 30 Kugeln; er hat sich während der Landung verletzt, aber ich wette, dass er nächsten Monat eine Möglichkeit findet, sich zu heilen. :) Wir wählen eine geeignete Position für den Spieler, in der Nähe des Schiffes, weil wir die Illusion erzeugen wollen, dass der Spieler aus dem Schiff kommt. Die angegebene Position und Ausrichtung erzeugt hoffentlich den Eindruck eines rauchenden Cockpits.

In einer Schleife lassen wir nun wind3.wav ertönen (mit Hilfe der snd_loop Anweisung) und spielen außerdem ein “Husten Geräusch” ab, das einige Sekunden dauert.

   while (my.x < 15000)
   {
       my.x += 20 * time;
       my.y -= 40 * time;
       my.z -= 25 * time;
       my.tilt += 2 * time;
       camera.x = my.x;
       camera.y = my.y;
       camera.z = my.z;
       camera.tilt = my.tilt;
       wait (1);
    }
   snd_play (jump_wav, 80, 0);
   while (my.tilt < 0)
   {
       my.tilt += 3 * time;
       camera.tilt = my.tilt;
       wait (1);
   }
   while (players_shield > 0)
   {
       players_speed.x = 15 * (key_w - key_s) * time;
       players_speed.y = 10 * (key_a - key_d) * time;
       vec_set (temp, my.x);
       temp.z -= 5000;
       trace_mode = ignore_me + ignore_passable + use_box;
       players_speed.z = -trace (my.x, temp);
       my.pan -= 5 * mouse_force.x;
       my.tilt += 5 * mouse_force.y;

Der Spieler springt auf den Boden (sein z-Wert wird geringer); der jump.wav Sound begleitet dies. Außerdem erhöhen wir den Tilt Winkel der Kamera, bis dieser geeignet ist. Solange der Spieler lebt, können wir ihn mit den WASD Tasten bewegen und wir sorgen dafür, dass er am Boden bleibt, indem wir 5000 Quants nach unten tracen und die Höhe entsprechend angleichen. Schließlich können wir uns mit Hilfe der Maus umsehen.

       if (mouse_left == 1)
       {
           players_bullet(); // then fire a bullet!
       }
       move_mode = ignore_passable + ignore_passents + glide;
       ent_move(players_speed, nullvector);
       camera.x = my.x;
       camera.y = my.y;
       camera.z = my.z + 30;
       camera.pan = my.pan;
       camera.tilt = my.tilt;
       if (((my.z < -750) || (mouse_left == 1)) && (track2_playing == 0))
       {
           track2_playing = 1;
           media_loop("track2.wav", null, 100);
       }
       wait (1);
    }
   my.skill46 = 0;
   while (my.skill46 < 80)
   {
       ent_cycle("death", my.skill46);
       my.skill46 += 2 * time;
       wait (1);
   }
}

Wenn der Spieler die linke Maustaste drückt, wird die Funktion “players_bullet” gestartet. Die Kamera befindet sich 30 Quants über dem Origin des Spielermodels und übernimmt Pan und Tilt Winkel von diesem. Wenn die Höhe des Spielers unter –750 Quants fällt (der Spieler kommt der ersten Basis nahe) oder wenn er einen Schuß abfeuert, wird der “track2.wav” Soundtrack gestartet, der in einer Schleife läuft. Die Zeilen am Ende der Action werden nur aufgerufen, wenn der Spieler stirbt, was im Moment nicht geschehen kann; sie sorgen dafür, dass die “Death” Animation abgespielt wird.

function players_bullet()
{
    proc_kill(4);
    while (mouse_left == 1) {wait (1);}
    snd_play (bullet_wav, 50, 0);
    ent_create (pbullet_mdl, player_1st.x, move_players_bullet); // create player's bullet
}

Diese Funktion startet durch Druck auf die linke Maustaste. Wir stellen sicher, dass nur eine Instanz dieser Funktion läuft und warten bis der Spieler die linke Maustaste losläßt. Dann ertönt das bullet.wav Geräusch und wir erstellen ein Model für die Kugel mit der “move_players_bullet” Funktion.

function move_players_bullet()
{
   my.pan = you.pan; // the bullet and the player have the same pan angle
   my.tilt = you.tilt; // and tilt angle
   my.passable = on; // at first
   my.enable_entity = on; // the bullet is sensitive to other entities
   my.enable_impact = on;
   my.enable_block = on; // and to level blocks
   my.event = remove_bullet;
   my.ambient = 100;
   my.light = on;
   my.lightred = 150;
   my.lightgreen = 150;
   my.lightblue = 255;
   while (my != null)
   {
      if (vec_dist (player_1st.x, my.x) > 30) {my.passable = off;}
      my.skill1 = 100 * time; // bullet speed
      my.skill2 = 0;
      my.skill3 = 0;
      move_mode = ignore_you + ignore_passable;
      ent_move (my.skill1, nullvector);
      my.roll += 100 * time;
      wait (1);
   }
}

Die Kugel übernimmt Pan und Tilt von der erzeugenden Entity (dem Spieler). Am Anfang ist sie noch passierbar, obwohl sie später auf Kollisionen mit anderen Entities und Level Blocks reagiert. Die Event Funktion lautet “remove_bullet()”. Die Kugel bewegt sich mit Hilfe einer Schleife und wird unpassierbar, sobald sie weiter as 30 Quants vom Spieler weg ist. Die Kugel dreht sich außerdem, indem der “roll” Winkel geändert wird.

function remove_bullet()
{
   my.event = null;
   ent_playsound (my, phit_wav, 1000); // player's bullet hits something
   sleep (0.4);
   ent_remove (me);
}

Dies ist die Eventfunktion der Kugel: sie setzt event auf null, läßt an der Einschlagstelle ein Geräusch ertönen, wartet kurz und entfernt die Kugel.

function toggle_passable()
{
    player.passable = (player.passable == off);
    if (player.passable == on)
    {
        player.enable_scan = off;
        player.transparent = on;
        player.alpha = 30;
    }
    else
    {
        player.enable_scan = on;
        player.transparent = off;
        player.alpha = 100;
    }
}

on_t = toggle_passable;

Diese Funktion macht das Schiff des Spielers im 2. Level unverwundbar, damit Sie gut ins 3. Level kommen können. Drücken Sie die “T” Taste sobald das Level geladen ist und das Spielermodel wird passierbar, daher werden alle gegnerischen Schiffe, Geschosse und Asteroiden hindurchgleiten. Vergessen wir nicht, dass einige Feinde auch “scan_entity” nutzen, um den Spieler zu verletzen, also müssen wir enable_scan ebenfalls deaktivieren. Wie Sie sehen wir der Spieler auch transparent, wenn er unverwundbar ist; drücken Sie erneut “T”, um den Spieler wieder verwundbar und undurchsichtig zu machen.

 

Explosionseffekte für Fortgeschrittene

Zunächst möchte ich gern feststellen, dass Ihre Effekte natürlich um so besser aussehen, je härter Sie daran arbeiten. Und das, obwohl der Effekt aus einfachen, sich überlappenden Partikeln und Sprites besteht:

1) Der Kern der Explosion:

function explosion_core()
{
    if (random(1) > 0.5)
    {
      my.bmap = core1_tga;
    }
    else
    {
      my.bmap = core2_tga;
    }
    my.transparent = on;
    my.flare = on;
    my.bright = on;
    my.size = random(30) + 20;
    my.alpha = 100;
    my.function = core_fade;
}

function core_fade()
{
   if (my.alpha > 50)
   {
      my.size += 2 * time;
   }
   else
   {
      my.size -= 2 * time;
   }
   my.alpha -= 3 * time;
   if(my.alpha < 0)
   {
      my.lifespan = 0;
   }
}

Die erste Funktion wählt eine von zwei Bitmaps (core1.tga oder core2.tga), macht diese transparent, bright und so weiter und stellt eine zufällige Größe ein. Die zweite Funktion vergrößert die Bitmap bis der Alpha kleiner ist als 50, dann wird sie wieder verkleinert. Die Partikel werden bei einem Alpha kleiner als 0 entfernt.

 

2) Der Sprite Ring (Schockwelle):

function explosion_ring()
{
    my.passable = on;
    my.scale_x = 0.1;
    my.scale_y = 0.1;
    my.tilt = 90;
    my.oriented = on;
    my.bright = on;
    my.flare = on;
    my.transparent = on;
    my.alpha = 100;
    my.ambient = 100;
    my.lightred = 255;
    my.lightgreen = 200;
    my.lightrange = 100;
    while (my.scale_x < 4)
    {
       my.alpha -= 10 * time;
       my.lightrange += 50 * time;
       my.scale_x += 0.5 * time;
       my.scale_y = my.scale_x;
       wait(1);
    }
    ent_remove(my);
}

Das Sprite startet mit einer geringe Größe und Lightrange (zunächst 100 Quants). Die Schleife verringert den Transparenzfaktor und erhöht Größe und Lightrange. Der Ring wird entfernt, sobald die Größe 4 überschreitet.

 

3) Das rotierende Sprite:

function explosion_sprite1()
{
    my.passable = on;
    my.facing = on;
    my.bright = on;
    my.flare = on;
    my.alpha = 100;
    my.ambient = 100;
    while (my.scale_x < 4)
    {
       my.scale_x += 1 * time;
       my.scale_y = my.scale_x;
       my.alpha -= 10 * time;
       my.roll += 25 * time;
       wait(1);
    }
    ent_remove(my);
}

Dieses Sprite ist zur Kamera ausgerichtet. Wir erhöhen seine Größe und verringern den Alpha Wert, wobei wir das Sprite die ganze Zeit rotieren. Auch dieses Sprite wird bei einer Größe von 4 entfernt.

 

4) Das animierte Sprite:

function explosion_sprite2()
{
    my.passable = on;
    my.facing = on;
    my.bright = on;
    my.flare = on;
    my.ambient = 100;
    my.red = 255;
    my.lightrange = 100;
    while (my.frame < 20)
    {
       my.frame += 1 * time;
       my.scale_x += 0.1 * time;
       my.scale_y = my.scale_x;
       my.lightrange = 300 - random(100);
       wait(1);
    }
    ent_remove(my);
}

Dieses Sprite durchläuft seine Animationsframes, vergrößert sich und hat eine zufällige Lightrange. Nach dem letzten Frame der Animation wird es entfernt.This sprite will go through all its animation frames, increasing its scale and having a random lightrange. The sprite is removed as soon as it has played the last animation frame.

 

5) Die Fetzen und ihre Partikelspuren:

function move_gibbits()
{
    var gib_coords;
    var gib_speed;
    my.passable = on;
    my.scale_x = 0.5 + random(1);
    my.scale_y = my.scale_x;
    my.scale_z = my.scale_x;
    vec_set (gib_coords, my.x);
    gib_speed.x = (10 - random(20)) * time;
    gib_speed.y = (10 - random(20)) * time;
    gib_speed.z = (20 + random(10)) * time;
    my.skill10 = 10;
    while (my.skill10 > 0)
    {
       if (vec_dist (my.x, gib_coords.x) > 70)
       {
          my.passable = off;
       }
       ent_move (nullvector, gib_speed);
       effect (debris_trail, 1, my.x, nullvector);
       if (bounce.z != 0)
       {
          gib_speed.z = -(gib_speed.z * min(0.8, random(1)));
          if (gib_speed.z < 0.1)
          {
              gib_speed.x = 0;
              gib_speed.y = 0;
              gib_speed.z = 0;
          }
       }
       gib_speed.z -= 2 * time;
       my.skill10 -= 0.3 * time;
       wait (1);
    }
    my.transparent = on;
    my.alpha = 100;
    while (my.alpha > 0)
    {
       my.alpha -= 3 * time;
       wait (1);
    }
    ent_remove (my);
}

Die Explosionsfetzen sind kleine 3D Models mit einer zufälligen Größe (0,5 bis 1,5) und zufälligen Geschwindigkeiten auf x, y und z Achse. Beachten Sie, dass die z-Geschwindigkeit positiv ist, die Fetzen fliegen am Anfang also nach oben. Wir setzen skill10 auf 10 und gehen in eine Schleife, die stoppt, wenn skill10 kleiner wird als 0. Was geschieht in dieser Schleife? Zunächst wird der Fetzen unpassierbar, wenn er den Startpunkt verlassen hat; dieser Trick verhindert, dass die Fetzen aneinander hängenbleiben. Manipulieren Sie den Wert "70” – für Ihr eigenes Projekt könnte ein anderer Wert sinnvoll sein. Der Fetzen bewegt sich mit der Geschwindigkeit, die durch gib_speed gegeben ist und erzeugt in jedem Frame ein Partikel an seiner Position mit der debris_trail Funktion. Wenn der Fetzen etwas trifft (den Boden, eine Wand, etc.), ändert er seine Geschwindigkeit (sie wird geringer, bis zu 80% des ursprünglichen Wertes) und Richtung. Falls gib_speed zu klein wird, dann wird sie auf 0 gesetzt. Die letzten Zeilen in der Schleife verringern gib_speed.z und simulieren so Gravitation und verringern skill10, weil wir ja aus der Schleife auch herauskommen wollen. Was geschieht dann? Das Model wird transparent und verschwindet. Wenn der Alphawert kleiner wird als 0, wird das Model entfernt.

function debris_trail()
{
   my.bmap = debristrail_tga;
   my.flare = on;
   my.bright = on;
   my.size = 2;
   my.alpha = 30;
   my.function = fade_debtrail;
}

function fade_debtrail()
{
   my.size += 0.8 * time;
   my.alpha -= 1.5 * time;
   if (my.alpha < 0)
   {
      my.lifespan = 0;
   }
}

Diese Partikel vergrößern sich und werden dabei transparent – sobald sie nicht mehr zu sehen sind, werden sie entfernt.

 

6) Der Rauch:

function particle_smoke()
{
    my.bmap = smoke_tga;
    my.vel_x = 2 - random(4);
    my.vel_y = 2 - random(4);
    my.vel_z = 2 + random(1);
    my.lifespan = 200;
    my.flare = on;
    my.transparent = on;
    my.alpha = 50;
    my.move = on;
    my.size = 50;
    my.function = fade_smoke;
}

function fade_smoke()
{
   my.size += 0.5 * time;
   my.alpha -= 0.4 * time;
   if (my.alpha < 0)
   {
      my.lifespan = 0;
   }
}

Ein typischer Raucheffekt, mit zufälligen Geschwindigkeiten auf x und y Achse und positiver Geschwindigkeit in z-Richtung. Das Partikel wird vergrößert, wenn es sich nach oben bewegt und wird dabei transparent.

Das sind alle Funktionen für den Effekt – schauen wir uns an, wie sie zusammengesetzt werden:

function start_explosion(coordinates)
{
    var sound_volume;
    var number_of_gibbits;
    sound_volume = 30000 / (vec_dist(coordinates.x, camera.x) + 100);
    snd_play (explostart_wav, sound_volume, 0);
    effect (explosion_core, 10 + random(10), coordinates, nullvector);
    sleep (0.5);
    ent_create (exploring_tga, coordinates, explosion_ring);
    snd_play (explomid_wav, sound_volume, 0);
    sleep (0.1);
    ent_create (exploflare_pcx, coordinates, explosion_sprite1);
    sleep (0.1);
    ent_create (explosion_pcx, coordinates, explosion_sprite2);
    sleep (0.1);
    number_of_gibbits = random(15) + 5;
    while (number_of_gibbits > 0) // while without wait!
    {
       ent_create (gibbit_mdl, coordinates, move_gibbits);
       number_of_gibbits -= 1;
    }
    snd_play (exploend_wav, sound_volume, 0);
    sleep (0.5);
    effect (particle_smoke, random(20) + 10, coordinates, nullvector);
}

Ich habe den sound_volume Wert für die Lautstärke aus dem Abstand der Explosion und der Kamera berechnet; auf diese Weise kann die Explosion irgendwo im Level stattfinden und die Geräusche werden entsprechend angeglichen. Wir beginnen mit der explosion_core Funktion, mit einer zufälligen Partikelzahl (10 bis 20) und bei der Position gegeben durch “coordinates” – das ist der Vektor, den wir an start_explosion übergeben müssen. Wir warten 0,5 Sekunden und erzeugen dann den Ring. Nach weiteren 0,1 Sekunden kommt das rotierende Sprite dazu und nach wiederum 0,1 Sekunden das animierte Sprite. Es folgen eine zufällige Anzahl Explosionsfetzen (15 – 20), die in einer schnellen Schleife erzeugt werden. Schließlich warten wir weitere 0,5 Sekunden und fügen den Rauch hinzu.

Experimentieren Sie ruhig mit der Reihenfolge und den Pausen oder fügen sie Effekte mehrfach hinzu. Bis bald!

Halt, einen Moment noch! Ich wollte ja noch erklären, wie man diese Effekte in ein Projekt einbaut!

Schauen wir uns zwei Beispiele an:

1) Lassen Sie die Explosion an einem bestimmten Ort geschehen:

function explo_test()
{
    start_explosion (vector(0, 0, 100));
}

on_e = explo_test;

Wenn die “E”-Taste gedrückt wird, erzeugen Sie damit eine Explosion an der Position (0,0,100) in Ihrem Level. Der Aufruf explo_test() läßt den Bereich explodieren.

2) Explodierende Fässer:

function destroy_me()
{
    start_explosion (vector(my.x, my.y, my.z + 20));
    sleep (0.5);
    my.invisible = on;
    my.passable = on;
}

action explodable_barrel
{
   my.enable_impact = on;
   my.enable_entity = on;
   my.enable_shoot = on;
   my.event = destroy_me;
}

Das Faß reagiert auf Kollisionen mit anderen Entities und auf “trace” Anweisungen; die Event Funktion löst die Explosion an der Position des Fasses (bzw. 20 Quants darüber) aus, wartet ein wenig und läßt das Faß verschwinden. Beide Beispiele finden Sie in der office.wmp, also experimentieren Sie damit. Vergessen Sie nicht, dass Sie auch in die Fässer laufen können, um sie hochzujagen, wenn Ihnen die Munition ausgeht! :)