Planet Survivors

Diesen Monat habe ich einen neuen Gegner hinzugefügt (den Alien-Schützen), eine neue Waffe (das Sniper-Gewehr) und habe den Movement-Code verbessert sowie ein paar andere Kleinigkeiten.

action alien_gunner
{
    var gun_pos;
    while (player_1st == null) {wait (1);}
    my.skill20 = 1; // the alien that controls this turret isn't dead
    ent_create (blastshield_mdl, my.x, stick_with_parent);
    ent_create (alien_mdl, my.x, stick_with_gun);
    while (my.skill20 == 1)
    {
       vec_set(temp, player_1st.x); // rotate the gun towards the player
       vec_sub(temp, my.x);
       vec_to_angle(my.pan, temp);
       if (my.tilt < -35) {my.tilt = -35;}
       // the alien gunner has got a firing range of 15,000 quants
       // fire every 1.5 seconds if the player is in range and visible
       if ((vec_dist (player_1st.x, my.x) < 17000) && (total_frames % 90 == 1))
       {
          vec_set (temp, my.x);
          temp.z += 150; // the alien uses its head position to "see" (trace) the player
          trace_mode = ignore_me + ignore_passable + use_box;
          trace_distance = trace (temp.x, player_1st.x);
          if ((trace_distance > 100) && (trace_distance < 15000)) // fire only if the player is visible
          {
             vec_for_vertex (gun_pos, my, 1); // fire from the first vertex of the gun
             ent_create (projectile_mdl, gun_pos.x, move_projectile);
          }
       }
       wait (1);
    }
    while (my.tilt < 35)
    {
       my.tilt += 3 * time;
       wait (1);
    }
}

Dieser Code wird dem Kanonen-Model zugewisen; er erstellt einen Schild und die alien_mdl Models. So lange wie skill20 = 1 ist, wird die Kanone sich immer dem Player zu drehen, mit einem Tilt Limit von -35 Grad nach unten. Wenn der Spieler näher als 17,000 Quants kommt, wird jede 1,5 Sekunden (total_frames % 90 = 1 bei 60 FPS) ein Trace ausgeführt von einer Position, welche 150 Quants über der Kanone platziert ist, zum Spieler hin. Wenn der Spieler Sichtbar ist, bekommen wir die richtige Position des Abschuß-Vertexes zurück, und das Geschoss wird erstellt. Sollte skill20 != 1 sein, dann ist der Schütze tot und die Kanone wird sich nach Oben drehen.

function stick_with_parent()
{
    my.scale_x = 0.7;
    my.scale_y = my.scale_x;
    my.scale_z = my.scale_x;
    my.light = on;
    my.lightred = 100;
    my.lightgreen = 100;
    my.lightblue = 200;
    my.lightrange = 0;
    my.bright = on;
    my.metal = on;
    my.transparent = on;
    my.alpha = 30;
    while (1)
    {
       my.x = you.x;
       my.y = you.y;
       my.z = you.z;
       my.pan = you.pan;
       my.tilt = you.tilt;
       my.roll = you.roll;
       my.lightblue = 100 + random(150);
       wait (1);
    }
}

Diese Funktion wird dem Schild zugewiesen, welches wiederum mit dem der Kanone synchronisiert wird. Das Schild hat zusätzlich einen zufälligen bläulichen Glüheffekt.

function stick_with_gun()
{
    my.frame = 2; // needed by the alien model
    my.skill1 = 100;
    my.enable_impact = on;
    my.enable_entity = on;
    my.event = gunner_is_hit;
    while (my.skill1 > 0) // not dead yet?
    {
       my.x = you.x;
       my.y = you.y;
       my.z = you.z;
       my.pan = you.pan;
       my.tilt = you.tilt;
       my.roll = you.roll;
       wait (1);
    }
    // the alien was hit here (it is dead)
    snd_play (aliendies_wav, 50, 0);
    you.skill20 = 0; // stop the turret
    while (my.frame < 7)
    {
       my.frame += 0.3 * time;
       wait (1);
    }
}

function gunner_is_hit()
{
   wait (1);
   my.skill1 -= 100;
}

Die vorherigen Funktionen steuern den Alien: die erste synchronisiert ihn mit dem Kanonenmodel wenn er nicht tot ist, und wird Beendet, wenn der Alien getroffen wird. Die zweite Funktion ist das Event, welches den Alien sterben lässt, wenn der Spieler es schafft, ihn zu erschießen.

function move_projectile()
{
    my.skill47 = 123; // to identify a bullet fired by the alien gunner
    my.pan = you.pan; // the bullet and the weapon have the same pan
    my.tilt = you.tilt; // and tilt angle
    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 = projectile_explodes;
    my.ambient = 100;
    my.light = on;
    my.lightred = 250;
    my.lightgreen = 150;
    my.lightblue = 55;
    while (my.passable == off)
    { 
       my.skill1 = 1000 * time; // bullet speed
       my.skill2 = 0;
       my.skill3 = 0;
       move_mode = ignore_you + ignore_passable;
       ent_playsound (my, rocketflying_wav, 3000);
       ent_move (my.skill1, nullvector);
       wait (1);
    }
}

Das Geschoß, welches vom Spieler geschossen wird, bewegt sich mit 1000 Quants * time und spielt einen 3D-Sound während seiner Bewegung.

function projectile_explodes()
{
    my.event = null;
    sleep (0.1);
    my.passable = on;
    my.invisible = on;
    if (vec_dist (player_1st.x, my.x) < 300)
    {
       players_shield -= 1000 / (vec_dist(player_1st.x, my.x) + 10);
    }
    ent_playsound (my, pexplo_wav, 2000); // the projectile hits something
    effect (explosion_core, 10 + random(10), my.x, nullvector);
    sleep (0.1);
    ent_create (explosion_pcx, my.x, explosion_sprite2);
    sleep (0.1);
    ent_create (explosion_pcx, my.x, explosion_sprite2);
    sleep (0.1);
    ent_create (explosion_pcx, my.x, explosion_sprite2);
    sleep (0.1);
    ent_create (explosion_pcx, my.x, explosion_sprite2);
    sleep (0.1);
    ent_create (explosion_pcx, my.x, explosion_sprite2);
    sleep (0.1);
    ent_create (explosion_pcx, my.x, explosion_sprite2);
}

Wenn das Geschoß etwas trifft, wird geprüft, ob der Spieler näher als 300 Quants ist und wenn das der Fall sein sollte, wird er verletzt. Wir spielen einen Explosions-Sound ab sowie verschiedene Explosions-Effekte aus meiner explosions.wdl Datei.

action sniper_weapon
{
    my.passable = on;
    while (player_1st == null) {wait (1);}
    while (vec_dist (my.x, player_1st.x) > 100) {wait (1);}
    snd_play (gotsniper_wav, 50, 0);
    my.invisible = on;
    got_sniper_rifle = 1;
}

Die Action hier wird dem Sniper-Gewehr zugewiesen; sie wartet bis der Spieler es berührt und setzt denn got_snip_rifle auf 1 und verschwindet. Nebenbei, das Gewehr wird im Zentrum der ersten Basis platziert.

function toggle_sniper()
{
    if (level_number != 3) {return;} // don't show the crosshair if the player hasn't reached the 3rd level
    if (got_sniper_rifle == 0) {return;}
    sniper_pan.visible = (sniper_pan.visible == off);
    camera.arc = 70 * (sniper_pan.visible == off) + 10 * (sniper_pan.visible == on);
}

on_mouse_right = toggle_sniper;

Das Gewehr kann mit und ohne Zoomen benutzt werden; drücken Sie einfach den rechten Mausbutton um das Zielfernrohr an und aus zu schalten. Das Gewehr wird nur funktionieren, wenn wir mindestens Level 3 erreicht haben (dieses Level) und auch dann nur wenn der Spieler das Gewehr aufgesammelt hat. Der Zoom-Faktor variiert von 1 (camera.arc = 70) bis zu 7 (camera.arc = 10).

Der Alien Schütze ist wirklich schwer zu erledigen. Dafür habe ich einen Cheat eingebaut, welcher mit F5 aktiviert wird:

function cheater()
{
    got_sniper_rifle = 1;
    players_ammo = 999;
    players_shield = 999;
}

on_f5 = cheater;

Wenn Sie den Level nicht mit 999 Schild-Punkten und 999 Schuss beenden können, dann können Sie diese Werte auch erhöhen. Bedenken Sie dabei, das wir 3 Aliens sowie 2 Ameisen in unserem Level haben; also sollten Sie noch ein paar Gegner einfügen, wobei es möglich sein sollte, das Fluchtschiff zu erreichen:

action ship_takes_off
{
    while (player_1st == null) {wait (1);}
    while (vec_dist (player_1st.x, my.x) > 350) {wait (1);}
    end_level3 = 1; // free the camera
    var ship_dist;
    ship_dist.y = 0;
    snd_play (shipout_wav, 50, 0);
    while (my.y < 25000)
    {
       ship_dist.x = 800 * time;
       ship_dist.z = 130 * time;
       ent_move(ship_dist, nullvector);
       vec_set(temp, my.x); // rotate the camera towards player's ship
       vec_sub(temp, camera.x);
       vec_to_angle(camera.pan, temp);
       wait (1);
    }
    exit;
}

Das Schiff wartet solange, bis der Player sich ihm nähert und fliegt dann weg bis „y“ größer als 25.000 Quants ist. Dann endet das Spiel durch aufrufen der „exit“ Funktion.

Ich habe auch ein bisschen den Movement Code überarbeitet, man kann nun auch langsam fallen und (viel wichtiger) man kann fliegen, wenn man sich nach oben dreht. Auf diese Weise kann man über Hindernisse springen und dieses große Level in ein paar Minuten beeden.


Die Fackel

Diesen Monat werden Sie lernen, wie man eine Fackel erstellt, welche aufgenommen und vom Spieler herumgetragen werden kann, um seine Umgebung zu erleuchten.

action torch
{
    my.passable = on;
    while (player == null) {wait (1);}
    while(1)
    {
       effect(flame_init, 5, my.x, nullvector);
       my.lightred = 180 + random(30);
       my.lightgreen = 150 + random(20);
       my.lightblue = 60;
       my.lightrange = 200 + random(5);
       my.ambient = 50;
       if (vec_dist (player.x, my.x) < 70) // the player has come really close to the torch?
       {
          my.x = player.x + 50 * cos(player.pan) + 20 * sin(player.pan); // 50 quants in front of the player
          my.y = player.y + 50 * sin(player.pan) - 20 * cos(player.pan); // and 20 quants sideways (to the right)
          my.z = player.z + 25; // the height of the torch is set 25 quants above player's origin
          my.pan = player.pan;
          my.tilt = player.tilt;
          my.roll = player.roll;
       }
       wait (1);
    }
}

Die Fackel ist Passable und wartet, bis der Spieler erstellt worden ist; sobald dies passiert wird die Fackel beginnen Partikel zu erstellen an ihrem Null-Punkt, unter Benutzung des „effect“ Befehls. Jedes Partikel wird sich so verhalten, wie in „flame_init“ festgelegt worden ist. Die Fackel strahlt ein gelbliches Licht aus, dessen Reichweite von 200 bis 205 Quants reicht, was ein leichtes Flickern erzeugt. Wenn der Spieler sehr nahe an die Fackel kommt (näher als 70 Quants), wird er sie aufsammeln und die Fackel wird 50 Quants vor und 20 Quants neben ihm (rechts) platziert. Das Model wird 25 Quants über dem Nullpunkt des Spielers an der Z-Achse platziert und wird den pan/tilt/roll Winkel-Werten des Spielers folgen.

function flame_init()
{
    temp.x = (random(2) - 1) / 2;
    temp.y = (random(2) - 1) / 2;
    temp.z = random(1) + 1;
    vec_set(my.vel_x, temp);
    my.move = on;
    my.bmap = flame_tga;
    my.flare = on;
    my.bright = on;
    my.alpha = 70;
    my.lifespan = 100;
    my.size = 17;
    my.function = fade_flames;
}

function fade_flames()
{
   my.alpha -= 25 * time; // play with 25
   if(my.alpha < 0) {my.lifespan = 0;}
}

Die obige Funktion kümmert sich um die Partikel; es wird ein Random Wert für die Geschwindigkeit auf der x und y Achse (von -0.5 bis 0.5) festgelegt und ebenfalls auf der z Achse ( im Bereich von 1-2). Das Feuer beginnt mit der Starttransparenz von 70; experimentieren Sie ein bisschen mit diesem Wert herum!
Die Funktion der Partikel lässt den Alpha-Wert schnell sinken; wir können es uns nicht leisten, kleiner Werte zu nutzen, weil die Fackel sich immer mit dem Player bewegen wird, und das würde einen großen Unrealistischen Schweif hinter dem Spieler erzeugen. Die letzte Zeile Code entfernt die Partikel, welche nicht mehr zu sehen sind. Sie können auch eine andere „effect“ Zeile in die „Torch“ Action einfügen, wenn sie einen anderen Effekt möchten, z.B. Rauch.

Hier ist ein Tipp: Ich habe ein Fackelmodell mit einem einfachen Nullpunkt genommen, so musste ich keine aufwändige Berechnung durchführen, sondern einfach nur my.x um zu garantieren, das die Flamme auch in der Fackel startet. Ok, ein bisschen Mathematik ist schon drin (werfen Sie doch mal einen Blick auf die Formeln, welche den Player und die Fackel verbinden), aber ich dachte, es könnte Wertvoll für ihre weiteren Projekte sein.