Teleportation

Den Spieler von einem Ort zu einem anderen zu teleportieren ist wirklich leicht – Sie müssen nur seine Koordinaten und manchmal seinen Winkel ändern. Der Ausschnitt unten erlaubt Ihnen, das Ziel und den Winkel in WED zu setzen, damit Sie diese Koordinaten nicht in Ihrem Skript ändern müssen, wenn Sie einen neuen Zielpunkt angeben.

Die Action für die Teleport Entity ist:

action teleport
{
     while (player == null) {wait(1);}
 
     vec_set (my.skill15, strength);
     vec_set (my.skill18, astrength);

     person_3rd = 0.5;
     camera_dist.x = 200;
     camera_dist.z = -300;
     head_angle.tilt = -45;

Wir warten bis der Spieler existiert und speichern seine strength und astrength template Werte (das sind die Geschwindigkeit und die Drehgeschwindigkeit). Ich benutze die Skills 15 bis 17 für die Strength und 18 bis 20 für die astrength. Falls Sie das Magazin schon länger lesen, dann wissen Sie bereits, dass wir jeden Vektor in 3 aufeinanderfolgenden Skills speichern können.

Wir setzen die Kamera auf Außensicht (3rd Person) und außerdem eine vernünftige Distanz in x und z Richtung, sowie einen guten Kamerawinkel, indem wir die Template Werte ändern.

     while (1)
     {
          while (vec_dist (my.x, player.x) > 40) {wait (1);}
          vec_set (strength, nullvector); // the player can't move
          vec_set (astrength, nullvector); // or rotate from now on
          temp.z = my.z;
          my.skill10 = particle_emmiters;
          my.skill11 = min_radius;
          while (my.skill10 > 0)
          {
               temp.x = player.x + min_radius * cos(my.skill12);
               temp.y = player.y + min_radius * sin(my.skill12);
               temp.z += up_step;
               my.skill12 += angle_step;
               min_radius += radius_step;
               effect (create_fx, 1, temp.x, normal);
               my.skill10 -= 1;
          }

Wenn der Spieler näher als 40 Quants an die Teleporter Entity herankommt, setzen wir strength und astrength zurück, so daß er sich nun nicht mehr bewegen oder drehen kann. Dann erzeugen wir Partikel auf einer Kreisbahn um den Spieler: der Radius und die Höhe des Kreises wird größer und größer, wie im Bild unten:
 


 
          player.shadow = off;
          player.transparent = on;
          player.alpha = 100;
          while (player.alpha > 0)
          {
               player.alpha -= 7 * time;
               wait (1);
          }
          player.invisible = on;
          waitt (16);
          min_radius = my.skill11;
          player.x = my.skill1; // set skill1..4 in Wed
          player.y = my.skill2;
          player.z = my.skill3;
          player.pan = my.skill4;
          player.transparent = off;
          player.invisible = off;
          vec_set (strength, my.skill15); // restore player's speed on x, y, z
          vec_set (astrength, my.skill18); // and player's angle speeds

          wait (1);
     }
}

Wenn der Spieler das Shadow Flag gesetzt hat, verschwindet der Schatten und der Spieler wird ausgeblendet, indem sein Alpha Wert geändert wird. Nach einer Sekunde wird der Spieler an seinen Zielort transportiert. (Skills1 bis 4 für x, y, z und pan).

Erinnern Sie sich an die Skill15 bis 17 bzw. 18 bis 20? Wir haben die ursprünglichen Werte für Strength und astrength gesichert - nun holen wir diese Werte zurück, denn wir möchten ja in der Lage sein, den Spieler zu bewegen.

Was nun noch fehlt ist der Partikeleffekt:

function create_fx()
{
     temp.x = random(2) - 1;
     temp.y = random(2) - 1;
     temp.z = random(2) + 1;
     vec_add (my.vel_x, temp);
     my.flare = on;
     my.bright = on;
     my.alpha = 50;
     my.bmap = effect_pcx;
     my.size = 30;
     my.move = on;
     my.lifespan = 100;
     my.function = fade_fx;
}

function fade_fx()
{
     my.alpha -= 2 * time;
     if (my.alpha < 0) {my.lifespan = 0;}
}

Wie Sie sehen haben die Partikel eine zufällige Geschwindigkeit in x, y und z, aber der z Wert ist immer positiv, also bewegen sich die Partikel nach oben und verringern ihren alpha Wert dabei.

 
 
Luftkampf

Diese Mal haben wir ein spaßiges Spieler gegen Hubschrauber Spiel mit vielen Features. Jedes neue Projekt hat seine Main Funktion:

function main()
{
     sky_clip = -90; // renders the whole sky
     on_d = null; // disables the debug panel
     level_load (aircombat_wmb);
     wait (2);
     game_init();
}

Die erste Zeile rendert den Himmel; es ist eine offene Fläche und wir möchten ihn ohne Clipping sehen können. Wir deaktivieren die "D" Taste, da wir sie für die Bewegung verwenden wollen, laden das Level und rufen dann die game_init() Funktion auf:

function game_init()
{
     while (player == null) {wait (1);}
     while (1)
     {
          if ((mouse_left == 1) && (player.health > 0)) // fire
          {
               snd_play (shoot_snd, 70, 0);
               ent_create (rocket_mdl, player.pos, move_bullet);
               recoil = 1;
               waitt (2);
               recoil = 0;
               while (mouse_left == 1) {wait (1);} // disable autofire
          }
          temp_counter += 1;
          if (temp_counter == 50)
          {
               temp_counter -= 49;
          }
          if (chopper_index[temp_counter] < distance && chopper_index[temp_counter] > 0)
          {
               distance = chopper_index[temp_counter];
               found_chopper = temp_counter;
          }
          else
          {
               distance = chopper_index[found_chopper];
          }
          if (remaining_choppers == 0)
          {
               aiming_pan.visible = off;
          }
          wait (1);
     }
}

Diese Funktion wartet, bis der Spieler erzeugt wurde. Wenn dies geschieht, wird eine Endlosschleife gestartet. Wenn die linke Maustaste gedrückt wird und der Spieler noch lebt, wird ein Geräusch abgespielt und eine Rakete wird an der Position des Spielers erstellt. Wir setzen den Rückstoß auf 1 für 0.1 Sekunden und warten bis die Maustaste losgelassen wurde; über den Rückstoß reden wir später.

Der Rest des Codes kümmert sich um das Auto Ziel System. Wenn der angewählte Hubschrauber näher ist als die anderen und es ein gültiger Hubschrauber ist, dann wird seine Distanz zum Spieler in der Variable distance gespeichert, andernfalls behalten wir die alte Distanz. Sind alle Hubschrauber abgeschossen, dann blenden wir das Ziel Panel aus.

Wir können bis zu 50 Hubschrauber haben; wir messen ihre Entfernung zum Spieler und der Hubschrauber, der dem Spieler am nächsten ist, plaziert ein Ziel Panel auf dem Schirm. Sie müssen nur auf dieses Panel schießen und der Hubschrauber wird getroffen.

Der Code, der den Spieler und die Kamera bewegt, ist in der Action unten:

action player_moves
{
     player = me;
     my.health = 100;
     my.invisible = on;
     my.enable_impact = on;
     my.enable_entity = on;
     my.event = player_event;
     while (my.health > 0)
     {
          vec_set (camera.pos, my.pos);
          camera.tilt += 20 * mouse_force.y * time;
          camera.pan -= 20 * mouse_force.x * time;
          my.pan = camera.pan;
          my.tilt = camera.tilt;
          player_speed.x = 15 * (key_w - key_s) * time - 0.5 * recoil;
          player_speed.y = 10 * (key_a - key_d) * time;
          vec_set (temp, my.x);
          temp.z -= 1000;
          trace_mode = ignore_me + use_box;
          player_speed.z = -trace (my.x, temp);
          move_mode = ignore_you + ignore_passable;
          ent_move(player_speed, nullvector);
          wait (1);
     }
}

Der Spieler hat health = 100 und ist unsichtbar, da wir uns im 1st Person Modus befinden. Außerdem reagiert er auf impact mit anderen Entities. Solange er lebt, kann er mit WASD und der Maus bewegt werden. Sie können ein wenig mit den Werten für camera.pan und tilt, player_speed.x und y spielen, um die Mausempfindlichkeit und die Geschwindigkeit zu ändern. Die Vorwärtsbewegung wird in player_speed.x gespeichert... erinnern Sie sich daran, daß wir den Rückstoß auf 1 gesetzt hatten, für 0.1 Sekunden? Auf diese Weise wird der Spieler nach hinten gestoßen, wann immer er eine Rakete abfeuert. Ändern Sie die Werte, um ein anderes Rückstoßverhalten zu bekommen. Der Bewegungscode enthält auch Gravitation, Sie können also jedes Level benutzen (mein Beispiel ist ein flaches Level).

Wenn der Spieler von einer Entity getroffen wird (die Hubschrauber schießen Sprites), dann wird seine player_event Funktion aufgerufen:

function player_event()
{
     wait (1);
     exclusive_global;
     if (my.health > 0)
     {
          my.health -= 0.5;
          snd_play (playerhit_snd, 40, 0);
      }
     else
     {
      my.health = 0;
     }
}

Falls der Spieler noch lebt, wird seine health verringert und ein Geräusch wird abgespielt. Ist der Spieler schon tot, wird seine health auf 0 gesetzt, denn negative Zahlen sehen in der Anzeige nicht gut aus. Schauen wir uns nun die Funktion an, welche für die Bewegung der Raketen verantwortlich ist:

function move_bullet()
{
     my.passable = on;
     my.enable_entity = on;
     my.enable_block = on;
     my.event = remove_me;
     my.pan = camera.pan;
     my.tilt = camera.tilt;
     my.skill1 = 0;
     rocket_speed.x = 500 * time;
     rocket_speed.y = 0;
     rocket_speed.z = 0;
     while (my.skill1 < 100)
     {
          if (vec_dist (my.x, player.x) > 50)
          {
               my.passable = off;
          }
          my.roll += 25 * time;
          my.skill1 += 1 * time;
          effect (create_smoke, 1, my.x, normal);
          move_mode = ignore_you + ignore_passable;
          ent_move (rocket_speed, nullvector);
          wait (1);
     }
     ent_remove (me);
}

function remove_me()
{
     waitt (2);
     ent_remove (me);
}

Wenn sie erstellt wird ist die Rakete passierbar, aber dieses Flag wird abgestellt, sobald sie mehr als 50 Quants vom Spieler entfernt ist. Die Rakete rotiert mit Hilfe des Roll Winkels und zieht eine Rachfahne hinter sich her. Wenn sie zu weit fliegt, ohne etwas zu treffen, wird sie entfernt. Dasselbe geschieht, wenn sie eine Entity oder einen Block trifft.

Hier ist die Funktion für die Rauchfahne:
 
function create_smoke
{
     temp.x = random(4) - 2;
     temp.y = random(4) - 2;
     temp.z = random(3) + 3;
     vec_add (my.vel_x, temp);
     my.flare = on;
     my.bright = on;
     my.alpha = 50;
     my.bmap = smoke_pcx;
     my.size = 30;
     my.move = on;
     my.lifespan = 100;
     my.function = fade_smoke;
}

function fade_smoke()
{
     my.alpha -= 2 * time;
     my.size -= 2 * time;
     if ((my.alpha < 0) || (my.size < 2)) {my.lifespan = 0;}
}

Der Rauch bewegt sich nach oben; die Partikel verschwinden, sobald ihr Alphawert unter 0 sinkt und ihre Größe unter 2 (letzteres sollte zuerst geschehen wenn Sie meine Werte verwenden, aber Sie können diese abändern).

Jeder Hubschrauber wird von einem Objekt generiert, welches die Action chopper_generator hat:

action chopper_generator
{
     my.invisible = on;
     my.passable = on;
     waitt (64 + random (64));
     ent_create (chopper_mdl, my.pos, move_chopper);
}

Ich habe jeweils einen kleinen Würfel benutzt; dieser wird unsichtbar und passierbar gemacht. Der Hubschrauber wird 4 bis 8 Sekunden nach Laden des Levels erzeugt und seine Funktion hat es in sich:

function move_chopper()
{
     chopper_number += 1;
     remaining_choppers += 1;
     my.skill1 = chopper_number;
     my.enable_impact = on;
     my.enable_block = on;
     my.enable_entity = on;
     my.event = chopper_event;
     my.skill40 = 1;

Jeder Hubschrauber hat eine eindeutige Nummer; wir benutzen eine Variable namens chopper_number und jedes Mal, wenn move_chopper() aufgerufen wird, dann wird chopper_number erhöht und das Ergebnis in skill1 gespeichert. Der Hubschrauber reagiert auf Kollisionen mit Entities und Level Blocks. Schließlich setzen wir skill40 für alle Hubschrauber auf 1 - auf diese Weise werden wir feststellen, ob eine bestimmte Entity ein Hubschrauber ist oder nicht.

     while (my != null)
     {
        vec_for_vertex(my.skill18, my, 55);
        if (my.skill42 == 0 && abs(my.x + my.y - player.x - player.y) > 2000)
        {
            vec_set (temp.x, player.x);
            vec_sub (temp.x, my.x);
            vec_to_angle (my.pan, temp);
        }
        my.tilt = 0;
        ent_cycle("fly", my.skill10);
        my.skill10 += my.skill11 * time;
        if (my.skill11 < 10)
        {
            my.skill11 += 0.2 * time; // increase the rotation speed
        }
        if (my.skill10 > 100)
        {
            my.skill10 = 0; // loop animation
        }

Solange der Hubschrauber "lebt", speichern wir den Vertex, der zum Feuern benutzt wird in skill18. Wenn die Distanz zwischen dem Spieler und dem Hubschrauber größer ist als 2000 Quants, wird der Hubschrauber sich drehen und in Richtung Spieler bewegen. Wir brauchen den Tilt nicht einzustellen... vec_to_angle tut dies, also setzen wir den Tilt auf 0. Der Hubschrauber wird seinen Rotor schneller und schneller drehen, denn skill1 wächst von 0 auf 10.

        if ((my.skill17 < 3 + random(3)) && (my.skill12 == 0))
        {
            my.skill15 = 0; // skills 15..17 are used a var here
            my.skill16 = 0;
            my.skill17 += 0.05 * time;
        }
        else
        {
            my.skill12 = 1;
            if (my.skill15 < 5 * time)
            {
                my.skill15 += 2 * time;
            }
            my.skill16 = 0;
            my.skill17 = 0;
            if (500 < abs(my.x + my.y - player.x - player.y) < 1000) // close to the player -> fire bullets
            {
                my.skill25 += 3 * time; // a simple counter
                my.skill26 = int (my.skill25);
                if ((my.skill26 % 100 == 0) && (vec_dist (player.x, my.x) > vec_dist (player.x, my.skill18)))  // change "100" to adjust the fire rate
                {
                    ent_create (bullet_pcx, my.skill18, chopper_bullet); // don't fire until the chopper is up
                }
            }
        }

Jeder Hubschreuber hat eine zufällige Höhe; Skill15 bis 17 werden hier als Vektor benutzt, um die Geschwindigkeit in den 3 Richtungen zu speichern. Der Hubschrauber bewegt sich nur solange nach oben, bis skill17 den Wert 3 + random(3) erreicht; ändern Sie diese Werte, um andere Höhen zu erreichen. Hat der Hubschrauber seine maximale Höhe erreicht, bewegt er sich nicht mehr nach oben, sondern bewegt sich schneller und schneller in die Richtung, die durch seinen pan gegeben ist. Ist die Distanz zum Spieler zwischen 500 und 1000 Quants, dann feuert der Hubschrauber.

Nun müssen wir uns einer weiteren Herausforderung stellen: wir möchten nicht, daß der Hubschrauber 50 - 100 Kugeln pro Sekunde schießt (das wäre nicht fair), aber wir möchten uns mit 50 - 100 Frames pro Sekunde in der gleichen Schleife bewegen. Wenn wir waitt(8) benutzen würden, dann würde der Hubschrauber 2 Kugeln pro Sekunde feuern - was Ok wäre - aber er würde sich auch nur zweimal pro Sekunde bewegen und seine Animation abspielen.

Die Lösung ist einfach: wir benutzen einen Skill, dessen Wert wir in jedem Frame erhöhen. Wenn ein kritischer Wert erreicht ist, feuern wir. Ich benutze skill26 um den ganzzahligen Teil von skill25 zu speichern; falls skill26 % 100 = 0 (mit anderen Worten, wenn skill26 = 0, 100, 200, 300, ...) feuern wir. Sie können die 100 ändern, um eine andere Feuerrate zu erhalten.

Moment mal! Die Bedingung hat noch einen anderen seltsamen Teil. Was ist mit dieser Zeile?

               if (.......vec_dist (player.x, my.x) > vec_dist (player.x, my.skill18)

Naja, Sie haben mich erwischt. Dieser Teil der Bedingung stellt sicher, dass der Hubschrauber nicht mit seinem Rücken schießen kann. Ich hätte die Winkel vom Hubschrauber zum Spieler vergleichen können, aber ich wollte Ihnen so viele Tricks wie möglich zeigen - sehen Sie sich das Bild an:

 
 

Wenn der Abstand zwischen Spieler und der Waffe des Hubschraubers (in skill18) kleiner ist als der Abstand zwischen Spieler und der Mitte des Hubschraubers, dann schießt der Hubschrauber nicht, denn der Spieler ist hinter ihm.

        chopper_index[my.skill1] = vec_dist(my.x, player.x);
        if (distance > chopper_index[my.skill1] - 4000)
        {
            vec_set (temp, my.x);
            if (vec_to_screen (temp, camera)) // if the target is visible
            {
                aiming_pan.pos_x = temp.x - bmap_width(aiming_pcx) / 2;
                aiming_pan.pos_y = temp.y - bmap_height(aiming_pcx) / 2;
                aiming_pan.visible = on;
            }
            else
            {
                aiming_pan.visible = off;
            }
        }
        move_mode = ignore_you + ignore_passable;
        ent_move(my.skill15, nullvector);
        wait (1);
    }
}

Das Array chopper_index speichert die Distanz zwischen jedem Hubschrauber und dem Spieler; wenn einer der Hubschrauber näher ist, wird das Ziel an seiner Position erscheinen. Ich habe die Distanz um 4000 Quants verringert, um sicher zu sein, dass das Ziel nicht so oft hin und her springt, wenn die Hubschrauber sich nähern. Spielen Sie mit diesem Wert - er hängt von der Größe Ihres Levels ab.

Wenn das Ziel sichtbar ist, setzen wir die richtige Position für das Zielpanel und machen es sichtbar, andernfalls deaktivieren wir es. Schließlich bewegt sich der Hubschrauber mit den skills 15 bis 17 und ignoriert passierbare Entities.

Wenn er eine Rakete eine Wand oder einen anderen Hubschrauber trifft, wird die chopper_event Funktion aufgerufen:

function chopper_event()
{
     if (((event_type == event_entity) || (event_type == event_impact)) && (you.skill40 == 1))
     {
          my.pan -= 180;
          my.skill42 = 1;
          waitt (64);
          my.skill42 = 0;
     }
     else
     {
          chopper_index[my.skill1] = 0;
          distance = 20000;
          remaining_choppers -= 1;
          ent_playsound (my, chopperx_snd, 1000);
          my.passable = on;
          my.ambient = 50;
          waitt (2);
          ent_create (explo13_pcx, my.pos, explode_me);
          waitt (4);
          my.transparent = on;
          ent_create (explo13_pcx, my.pos, explode_me);
          ent_remove (me);
     }
}

Falls der Hubschrauber mit einem anderen Hubschrauber kollidiert (wir hatten ja skill40 bei allen Hubschraubern auf 1 gesetzt), wird er für 4 Sekunden fortfliegen und dann zurückkommen. Dies geschieht, weil der Hubschrauber den Spieler nur verfolgt, wenn sein skill42 auf 0 steht - sehen Sie sich den Anfang der Schleife in move_chopper an.

Wenn der Hubschrauber mit einer Rakete kollidiert, wird er als Ziel gelöscht (wir setzen eine riesige Distanz). Dann kommt ein Explosionsgeräusch, erzeugen zwei sich überlappende Sprites und dann entfernen wir den Hubschrauber.

function explode_me()
{
     my.oriented = on;
     my.flare = on;
     my.bright = on;
     my.ambient = 100;
     while (my.frame < 14)
     {
          if (my.scale_x < 3)
          {
               my.scale_x += 0.5 * time;
               my.scale_y = my.scale_x;
          }
          my.frame += 1 * time;
          vec_set (temp.x, player.x);
          vec_sub (temp.x, my.x);
          vec_to_angle (my.pan, temp);
          wait (1);
     }
     ent_remove (me);
}

Wenn der Hubschrauber explodiert, erzeugt er 2 Sprites; diese werden wachsen, bis ihr scale 3 erreicht und ihre Animationsphasen werden abgespielt. Die Sprites werden sich zum Spieler ausrichten, damit die Explosion auch gut aussieht; ein Sprite sieht sonst nicht mehr so gut aus, wenn Sie einen Hubschrauber über Ihrem Kopf abschießen.

Sind Sie schon müde? Wir könnten aufhören, aber eine Funktion muß noch besprochen werden:

function chopper_bullet()
{
     my.passable = on;
     my.oriented = on;
     my.flare = on;
     my.bright = on;
     my.scale_x = 0.5;
     my.scale_y = my.scale_x;
     my.enable_entity = on;
     my.enable_block = on;
     my.event = remove_me;

     vec_set (temp.x, player.x);
     vec_sub (temp.x, my.x);
     vec_to_angle (my.pan, temp); // the bullet moves towards the player

     my.skill1 = 0;
     bullet_speed.x = 100 * time;
     bullet_speed.y = 0;
     bullet_speed.z = 0;
     while (my != null)
     {
          if (my.roll > 200) {my.passable = off;} // it works :)
          my.roll += 25 * time;
          my.skill1 += 1 * time;
          move_mode = ignore_you + ignore_passable;
          ent_move (bullet_speed, nullvector);
          wait (1);
     }
}

Diese Funktion bewegt die Kugeln der Hubschrauber. Diese sind passierbar und richten sich zum Spieler aus, wenn sie erzeugt werden; wenn Sie diese 3 Zeilen in eine Schleife schreiben würden, könnte der Spieler keiner Kugel ausweichen - er würde jedes Mal getroffen. Die Kugeln rotieren mit ihrem Roll Winkel und falls roll > 200 ist, wird ihr passierbar Status abgestellt.

Ich hoffe, dass Sie gern mit diesem Projekt spielen - Ich habe es genossen!