Beginner's corner

Top  Previous  Next

Surveillance cameras

I saw these cameras in Duke Nukem back in 1997 - see the real thing in this article!

I want to obtain "real" surveillance cameras, so I'm switching between the default view (camera) and my new view, surv_camera.

Function init_surveillance() is called in main; its purpose is to create a view that has the same size and position like the original "camera"

view surv_camera {}

function init_surveillance()

{

  surv_camera.size_x = screen_size.x;

  surv_camera.size_y = screen_size.y;

  surv_camera.pos_x = 0;

  surv_camera.pos_y = 0;

}

Every surveillance camera (fish.mdl in my example) has this action attached to it:

action surveillance_camera

{

   if (my.skill1 + my.skill2 + my.skill3 + my.skill4 + my.skill5 + my.skill6 == 0) {beep; beep; return;}

   while (1)

   {

         my.skill10 = abs(ang(player.pan) - ang(my.pan));

         if ((vec_dist(player.x, my.x) < 100) && (my.skill10 > 150) && (my.skill10 < 210))

         {

               camera.visible = off;

               surv_camera.x = my.skill1;

               surv_camera.y = my.skill2;

               surv_camera.z = my.skill3;

               surv_camera.pan = my.skill4;

               surv_camera.tilt = my.skill5;

               surv_camera.roll = my.skill6;

               surv_camera.visible = on;

               my.skill11 = 0;

         }

         else

        {

               if (my.skill11 == 0)

              {

                   surv_camera.visible = off;

                   camera.visible = on;

                   my.skill11 += 1;

               }

        }

        wait (1);

   }

}

If we forget to fill in at least one of these skill1...skill6 values, we hear two beeps and then the camera model is removed. We store the distance angle between fish.mdl (camera trigger) and the player in skill10. If the player is closer than 100 quants and the angle stored in skill10 is between 150 and 210 degrees, the player is facing the camera trigger and the corresponding surveillance camera is enabled.

If one of the surveillance cameras is enabled, the camera is hidden and surv_camera is made visible. Surv_camera's coordinates are read from skill1..6 (x, y, z, pan, tilt, roll) so you should get these values in Wed. If you want to deactivate the surveillance camera, simply rotate the player or move back.

If you want to improve this camera code you could add a panel that looks like a TV frame when you are in surveillance mode, play some sounds, etc.

  

Bow and arrow

This time I am going to take you through all the steps that are needed to create the code for a bow and arrows; please note that this example can be used to create (almost) any type of weapon and its bullets.

First of all we define an entity that will be used for the bow:

entity bow_entity

{

   type = <bow.mdl>;

   layer = 10;

   view = camera;

   x = 30;

   y = 8;

   z = -10;

}

We are using the same model (bow.mdl) for the bow that is being placed in the level in Wed. The bow rotates if it hasn't been picked up yet; when the player impacts with the bow, the bow will be removed and bow_entity is made visible. Bow_entity.frame = 2 will show the 2nd frame which contains the bow and the arrow.

action bow

{

   my.enable_impact = me;

   my.event = get_bow;

   while (my != null)  // or while (my)

   {

         my.pan += 3 * time;

         wait (1);

   }

}

 

function get_bow()

{

   wait (1);

   ent_remove (me);

   bow_entity.frame = 2;

   bow_entity.visible = on;

}

We are calling function init_bowarrow() in main:

function init_bowarrow()

   {

        while (1)

        {

              if ((mouse_left == 1 || key_ctrl == 1) && bow_entity.frame < 7)

             {

                  bow_entity.frame += 2 * time;

             }

            else

           {

                 if (bow_entity.frame >= 7 && arrow_fired == 0)

                {

                      while (mouse_left == 1 || key_ctrl == 1) {wait (1);}

                      vec_set (temp, player.pos);

                      temp.z += 20;

                      ent_create (arrow_mdl, temp, move_arrow);

                      arrow_fired = 1; // a single arrow

                }

               else // the player isn't shooting

               {

                     arrow_fired = 0; // enable firing

                     bow_entity.frame = 2;

              }

        }

       wait (1);

   }

}

If we press the LMB or the Ctrl key, we animate bow_entity by changing its frame parameter. If bow_entity.frame >= 7, we wait until the LMB or the Ctrl key are released (we do this because we want to disable autofire) and then we create an arrow 20 quants above player's origin. I chose this value because it looked real with my player + bow + arrow combination; you will have to try other values if you are using other models. If the player isn't shooting anymore, we enable firing and we set bow_entity's frame to 2 again. 

The function associated to the arrow is:

function move_arrow()

{

   wait (1);

   my.enable_entity = on;

   my.enable_block = on;

   my.event = hurt_you;

   my.passable = on;

   my.pan = camera.pan;

   my.tilt = camera.tilt;

   my.skill12 = 50; // skill12, 13, 14 act like a var

   my.skill13 = 0;

   my.skill14 = 0;

   my.skill12 *= time;

   while (my.skill12 != 0) // moves until it hits something

   {

        if (vec_dist (my.x, player.x) < 100) {my.passable = on;}

        // don't collide with the player

        else {my.passable = off;}

        ent_move (my.skill12, nullvector);

        wait (1);

   }

}

The arrow is sensitive to entities and level blocks; if it hits a block it will stuck in it and if it hits an entity it will disappear. I'm using skill12, 13, 14 as if they were a single var named skill12; I need to make sure that the first skill is divided by 3 (so I can start with skill3, 6, 9, 12, 15, etc). If the distance between the player and the arrow is smaller than 100 quants, the arrow is passable in order to prevent the arrow from hitting its creator.

The last function is:

function hurt_you()

{

   wait (1);

   if (event_type == event_entity)

   {

       my.skill12 = 0; // stop moving

       you._HEALTH -= 80; // damage = 80;

       ent_remove (me);

   }

   if (event_type == event_block)

   {

       my.skill12 = 0; // stop the arrow

       my.passable = on; // it shouldn't stand in our way

   }

}

If the rocket hits an entity, it will cause 80 hit points damage. If the entity is a tree sprite, it won't matter but if it is an enemy (robot2 in my example) you will see him running away after the first hit.

Here's a small tip: I have used the same model for the bow_entity and for the bow that is placed in Wed although it had an arrow and a hand attached to it all the time. Of course you wouldn't want to see the bow, the arrow and the hand attached to it waiting to be picked up. The models need to have the same number of triangles every frame, so I have decided to hide the hand and the arrow inside the bow (much smaller, of course, but they're there). I'm using the first bow.mdl frame before picking up the bow and frames 2..7 for the animated bow + arrow + hand.

What about those screams you were talking about?

I was just joking, but you can easily add them with a ent_playsound instruction placed in robot2's template code.