Scrollendes Panel

Manchmal möchten Sie vielleicht einen Text auf einem Panel scrollen, aber Sie können nicht einfach die pos_x und pos_y Werte ändern, wenn Sie das große Panel nicht auf dem Screen bewegen wollen. Sie bräuchten etwas kleineres, etwas wie ein Fenster auf dem Panel. Ok, also nutzen wir eines.

Als erstes definieren wir ein Panel:

panel spanel_pan
{
   bmap = spanel_pcx;
   pos_x = 0;
   pos_y = 0;
   layer = 30;
   button 217, 25, arrow1_pcx, arrow1_pcx, arrow1_pcx, scroll_up, null, null;
   button 217, 45, arrow2_pcx, arrow2_pcx, arrow2_pcx, scroll_down, null, null;
   window = 10, 20, 200, 50, text_pcx, text_pos.x, text_pos.y;
   flags = overlay, d3d, refresh;
}

Dies ist eine ganz normale Panel Definition; wir haben zwei pfeilförmige Knöpfe, die benutzt werden, um den Text hoch und runter zu scrollen und eine "Window" Definition. Diese sehen wir uns näher an:

window = 10, 20, 200, 50, text_pcx, text_pos.x, text_pos.y;

Dieser Befehl erzeugt ein window (ein Loch) im Panel. Dieses wird bei (10, 20) plaziert und wird 200 Pixel in x-Richtung und 50 Pixel in y-Richtung messen. Der Text, der in diesem Window erscheinen wird, ist im Bild text_pcx gespeichert; seine Koordinaten werden durch text_pos.x und text_pos.y gegeben.

function scrolling_text()
{
   mouse_toggle(); // show the cursor
   text_pos.x = 10;
   text_pos.y = 20;
   while (1)
   {
      if (key_h == 1) // press H to show the panel
      {
         while (key_h == 1) {wait (1);}
         spanel_pan.visible = (spanel_pan.visible == off);
      }
      wait (1);
   }
}

Die Funktion scrolling_text wird in der main aufgerufen; sie zeigt den Mauszeiger an (mit der Template Funktion mouse_toggle) und setzt dann die Startposition für den Text, der im Fenster erscheint. Die While Schleife zeigt das Panel oder verbirgt es, wenn wir H drücken mit einer einzigen Zeile Code. Versuchen Sie, diese zu verstehen:

spanel_pan.visible = (spanel_pan.visible == off);

und Sie werden einen Schritt näher am gelben Gürtel sein :)
 
Die letzten Funktionen sind:

function scroll_up()
{
   while (mouse_left == 1)
   {
      if (text_pos.y < 350) // text height - window height
      {
         text_pos.y += 3 * time;
      }
      wait (1);
   }
}

function scroll_down()
{
   while (mouse_left == 1)
   {
      if (text_pos.y > 0)
      {
         text_pos.y -= 3 * time;
      }
      wait (1);
   }
}

Diese laufen ab, wenn wir einen der Pfeile drücken, die den Text scrollen lassen. Wenn dies geschieht, scrollt der Text in die jeweilige Richtung, solange die linke Maustaste gedrückt ist. Wenn der Text seine obere oder untere Grenze erreicht hat, kann er nicht weiter scrollen. Viel Spaß, aber vergessen Sie nicht, dass jedes Panel Video Speicher verbraucht; verwenden sie adequadte Breite und Höhe für jedes Panel.
 
 

3rd shooter

Nein nein, dies ist nicht der dritte Shooter im AUM, es ist der Code für einen 3rd Person Shooter. Die gute Nachricht ist, dass Sie den Code für jedes Arcade Spiel nutzen können. Dieses Projekt hat seine eigene Main Funktion:

function main()
{
   level_load (shoot3rd_wmb);
   wait (2);
   clip_size = 0;
   fps_max = 50;
   on_d = null;
}

An dieser ist nichts Besonderes; ich habe die Frame Rate auf 50 fps festgesetzt und die "D" Taste wird das Debug Panel nicht aufrufen, wir brauchen die Taste nämlich für die Bewegung des Spielers (WASD).

Die Action des Spielers ist die längste, also schauen wir sie uns zuerst an:

action player_init
{
   player = me;
   player.skill20 = 100;
   my.enable_impact = on;
   my.event = player_damage;
   camera.z = my.z + 700;
   camera.tilt = -90;
   ent_create(soldiergun_mdl, nullvector, attach_soldiergun); // give him a gun

Wir benutzen skill20, um die Gesundheit (health) des Spielers zu speichern. Der Spieler reagiert auf "impact", wenn er also von etwas getroffen wird, dann wird das player_damage Event aufgerufen. Die Kamera wird 700 Quants über dem Spieler plaziert und sieht nach unten. Der Spieler erhält eine Waffe, aber wir werden über die Funktion attach_soldiergun etwas später reden.

   while (my.skill20 > 0)
   {
      my.pan += 4 * (key_a - key_d) * time - 20 * mouse_force.x * time;
      player_speed.x = 10 * (key_w - key_s) * (1 - mouse_left) * time;
      player_speed.y = 0;

Solange der Spieler lebt (skill20 > 0), kann er sich mit Hilfe der Tasten "A" und "D" drehen, indem einfach sein pan geändert wird. Der Spieler bewegt sich vorwärts / rückwärts mit "W" bzw. "S", aber nur, wenn die linke Maustaste nicht gedrückt ist. Dieses ist notwendig, denn die Waffe muß zum Gegner zeigen, wenn der Spieler feuert. Wenn er geht, zeigt seine Waffe aber nach links.

      if (mouse_left == 1)
      {
         ent_cycle ("attack", 100);
         ent_create (bullet_mdl, my.skill12, init_shot);
         snd_play (shoot1_snd, 70, 0);
         while (mouse_left == 1) {wait (1);}
      }
      else
     {
         if (player_speed.x != 0)
         {
            ent_cycle ("walk", my.skill10);
            my.skill10 += 10 * time;
            if (my.skill10 > 100) {my.skill10 = 0;}
         }
     }

Wenn die linke Maustaste gedrückt wird, ändert der Spieler seinen Frame auf den letzten "attack" Frame und feuert eine Kugel. Wir möchten keine Autofeuerfunktion einbauen, also warten wir, bis der Spieler die Taste wieder losläßt. Wenn die linke Maustaste nicht gedrückt ist, spielt der Spieler seine "walk" Animation in einer Schleife ab.

     vec_set (temp, my.x);
     temp.z -= 3000;
     trace_mode = ignore_me + ignore_sprites + ignore_models + use_box;
     player_speed.z = -trace (my.x, temp);
     ent_move(player_speed, nullvector);

     camera.pan = my.pan;
     camera.x = my.x + 250 * cos (my.pan);
     camera.y = my.y + 250 * sin (my.pan);

     wait (1);
  }
}

Der Spieler bewegt sich unter Beachtung der Gravitation - Sie kennen den Code aus Stratego2. Schließlich wird die Kamera auf einen Punkt 250 Quants vor dem Spieler zentriert.


 

function attach_soldiergun()
{
   proc_late();
   my.passable = on;
   my.metal = on;
   while(you != null)
   {
       vec_set(my.x,you.x);
       vec_set(my.pan,you.pan);
       my.frame = you.frame;
       my.next_frame = you.next_frame;
       vec_for_vertex(you.skill12, my, 6); // soldier's bullet position is stored in soldier's skill12
       wait(1);
   }
  ent_remove(my);
}

Die obige Funktion gibt dem Spieler eine Waffe, die solange existiert, wie der Spieler nicht aus dem Level entfernt wird. Diese Waffe wurde zusammen mit dem Spieler animiert und dann als separates Model gespeichert, also müssen wir lediglich den x, pan und frame Wert auf die entsprechenden Werte des Spielermodels zu setzen. Wir speichern die Koordinaten für die Kugel in skill12 des Spielers (you.skill12 ist player.skill12, denn der Spieler hat die Waffe mit create erzeugt).

Wenn der Spieler oder der Gegner feuert, wird die Funktion init_shot aufgerufen:

function init_shot()
{
   my.pan = you.pan;
   my.tilt = you.tilt;
   my.skill10 = 1;
   my.enable_entity = on;
   my.enable_block = on;
   my.event = remove_bullet;
   my.ambient = 100;
   my.skill1 = 0;
   bullet1_speed.x = 10;
   bullet1_speed.y = 0;
   bullet1_speed.z = 0;
   bullet1_speed *= time;
   while ((my != null) && (my.skill1 < 500)) // 500 = max distance
   {
      my.skill1 += 1 * time;
      move_mode = ignore_you + ignore_passents;
      ent_move (bullet1_speed, nullvector);
      wait (1);
   }
   ent_remove (me);
}

function remove_bullet()
{
   wait (1);
   ent_remove (me);
}

Die Kugel hat denselben pan und tilt, wie die erzeugende Entity; sie kann mit Entities und Level Blocks kollidieren. Die Kugel wird (solange sie mit nichts zusammenstößt) nur eine begrenzte Zeit existieren, bis ihr skill1 den Wert 500 erreicht. Sie ignoriert die erzeugende Entity und jede passierbare und kann somit nicht mit der Waffe kollidieren, aus der sie abgeschossen wird und auch nicht mit Wasser etc. Wenn sie etwas trifft, wird sie nach 1 Frame entfernt.

Wenn der Spieler von einer Kugel des Gegners getroffen wird, wird seine player_damage Funktion aufgerufen:

function player_damage()
{
   if (you.skill10 != 1)
   {
      return;
   }
   else
   {
      my.skill20 -= 10;
      if (my.skill20 <= 0)
      {
         my.enable_impact = off;
         my.event = null;
         my.skill10 = 0;
         my.skill30 = 1; // I'm dead
         while (my.skill10 < 67)
         {
            ent_cycle("death", my.skill10);
            my.skill10 += 6 * time;

             if (camera.z > player.z + 300)
             {
                camera.z -= 10 * time;
             }
             wait (1);
         }
      }
   }
}

Der Spieler könnte auch gegen eine Wand gelaufen oder von einem Gegner berührt worden sein. Deshalb müssen wir am Anfang der Funktion skill10 prüfen, um festzustellen, ob der Spieler auch von einer Kugel getroffen worden ist (wir haben skill10 am Anfang von init_shot auf 1 gesetzt, erinnern Sie sich?) Jede Kugel wird 10 Punkte Health abziehen und wenn diese unter 0 sinkt, spielt der Spieler seine "death" Animation ab. Die Kamera wird ein wenig hereinzoomen, um die Leiche des Spielers zu zeigen.

Zeit, sich den Gegnern zuzuwenden! Als ersten die Action, die die Gegner erstellt:

action generate_enemy
{
   my.scale_x *= 0.7;
   my.scale_y = my.scale_x;
   my.passable = on;
   my.oriented = on;
   my.bright = on;
   my.flare = on;
   while (player == null) {wait (1);}
   while (vec_dist (my.x, player.x) < 500) {wait (1);}
   waitt (48 + random (64));
   vec_set (temp, my.pos);
   temp.z += 50;
   ent_create (enemy_mdl, my.pos, move_enemy);
}

In diesem Spiel können Gegner während des Spiels erstellt werden; ich habe einige orientierte Sprites als Feindgeneratoren benutzt. Wenn der Spieler sich ihnen nähert, beginnen sie Gegner zu erschaffen. Auf diese Weise können Sie Feindgeneratoren entlang des Pfades verteilen, den der Spieler nehmen wird.

Diese warten, bis der Spieler existiert; kommt er näher als 500 Quants, wird ein Feind nach 3..7 Sekunden 50 Quants über dem Sprite erzeugt. Er benutzt diese Funktion:

function move_enemy
{
   my.enable_impact = on;
   my.event = enemy_damage;
   ent_create(enemygun_mdl, nullvector, attach_enemygun); // give him a gun

Auch er reagiert auf impacts und erhält eine Waffe mit ähnlicher Funktion.

   while (vec_dist(my.x, player.x) > (300 + random(100)))
   {
      enemy_speed.x = 10 * time;
      enemy_speed.y = 0;
      enemy_speed.z = 0;

      vec_set (temp.x, player.x);
      vec_sub (temp.x, my.x);
      vec_to_angle (my.pan, temp);

      move_mode = ignore_you + ignore_passents;
      ent_move (enemy_speed, nullvector);
      ent_cycle ("walk", my.skill10);
      my.skill10 += 10 * time;
      if (my.skill10 > 100) {my.skill10 = 0;}
      my.tilt = 0;
      wait (1);
   }

Solange der Spieler weiter als 300..400 Quants entfernt ist, bewegt sich der Gegner in seine Richtung und spielt seine "walk" Animation in einer Schleife.
 
   ent_cycle("attack", 100);
   waitt (2);
   while (my.skill30 == 0 && player.skill20 > 0)
   {
      vec_set (temp.x, player.x);
      vec_sub (temp.x, my.skill12);
      vec_to_angle (my.pan, temp);
      ent_create (bullet_mdl, my.skill12, init_shot);
      my.tilt = 0;
      snd_play (shoot1_snd, 70, 0);
      waitt (32);
   }
}

Ist der Gegner nah genug, spielt er seine "attack" Frames ab und beginnt, auf den Spieler zu feuern, wenn beide noch leben. Er dreht sich zum Spieler und schießt alle 2 Sekunden.

Wenn der Gegner von einer Kugel getroffen wird, dann wird die enemy_function aufgerufen. Die gute Nachricht ist, daß die Gegner sich auch gegenseitig verletzen können. :)

function enemy_damage()
{
   if (you.skill10 != 1) {return;}
   wait (1);
   my.enable_impact = off;
   my.event = null;
   my.skill10 = 0; // start with the first death frame
   my.skill30 = 1; // I'm dead
   while (my.skill10 < 67)
   {
      ent_cycle("death", my.skill10); // play death animation
      my.skill10 += 6 * time;
      wait (1);
   }
   my.passable = on; // can pass through the corpse
}

Als erstes prüfen wir, ob es auch eine Kugel war, die den Gegner getroffen hat. Ist dies der Fall, spielen wir die "death" Animation und machen seine Leiche passable, damit der Spieler nicht davon aufgehalten wird.

Das war es für heute. Bis nächste Woche bei einem neuen Projekt!