Code snippets

Top  Previous  Next

Planet Survivors

 

aum43_shot12

 

This month I have added a new enemy (the alien gunner), a new weapon (the sniper rifle), I have improved the movement code and a few more things.

 

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);

   }

}

 

The code above is attached to the cannon model; it creates a shield and the alien_mdl models. As long as skill20 = 1 the cannon will rotate towards the player, with its lower tilt limit being set to -35 degrees. If the player has come closer than 17,000 quants, every 1.5 seconds (total_frames % 90 = 1 at 60 fps) we will trace from a position that is placed 150 quants above the canon to the player. If the player is visible we get the correct position of the firing vertex, and then we create the projectile. When skill20 != 1 the alien gunner is dead so the cannon tilts upwards.

 

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);

   }

}

 

The function above is attached to the shield, keeping it in sync with the cannon. The shield will have a blueish random glow.

 

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;

}

 

The functions above are driving the alien: the first one keeps it in sync with the cannon model if it isn't dead and stops the turret when the alien is hit. The second function is the event that kills the alien if the player manages to shoot it.

 

aum43_shot13

 

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);

   }

}

 

The projectile fired by the alien gunner moves with 1000 quants * time / frame and plays a 3D sound while it is moving.

 

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);

}

 

aum43_shot14

 

If the projectile hits something, it checks if the player is closer than 300 quants to it and if this is true it damages the player. We play an explosion sound and several explosion effects from my explosions.wdl file.

 

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;

}

 

The action above is attached to the sniper rifle; it waits until the player comes close to it and then it sets got_sniper_rifle to 1 and disappears. Btw, the rifle is placed at the entrance of the first base.

 

aum43_shot15

 

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;

 

The rifle can be used with or without zooming in; press the right mouse button to toggle the sniper mode on and off. The rifle will only work if we have reached the 3rd level (this level) and only if the player has picked up the rifle. The zooming factor will range from 1 (camera.arc = 70) to 7 (camera.arc = 10).

 

The alien gunners are pretty tough to beat; therefore, I have added a cheat that is enabled if you press the F5 key:

 

function cheater()

{

   got_sniper_rifle = 1;

   players_ammo = 999;

   players_shield = 999;

}

 

on_f5 = cheater;

 

If you can't finish the level with 999 shield points and 999 bullets you can make those values even bigger. Please note that we've got 3 aliens and 2 ants in the level; you should add more enemies but we are interested in making it to the getaway ship:

 

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;

}

 

This ship waits until the player comes close to it, and then it moves away until its y is bigger than 25,000 quants. The game ends by calling the "exit" instruction.

 

I have changed the movement code as well; now you can fall smoothly and (more important) you can fly by pointing your nose upwards. This way you can jump over obstacles and get to the end of this big level in only a few minutes.

 

 

 

 

Torch

 

This month we will learn to create a torch that can be picked up and carried around, lighting up the surrounding areas.

 

aum43_shot16

 

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);

   }

}

 

The torch model is passable and waits until the player model is created; as soon as this happens, the torch starts to create particles at its origin, using the "effect" instruction. Each and every particle will behave according to what the "flame_init" function instructs it to do. The torch emits a yellowish light whose range varies from 200 to 205 quants, giving a slight flickering effect. If the player has come really close to the torch (closer than 70 quants) the torch is picked up, being placed 50 quants in front of the player and 20 quants sideways (to the right side of the screen). The torch model is placed 25 quants above player's origin on the z axis and will inherit player's pan, tilt and roll angles.

 

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;}

}

 

The functions above take care of the fire particles; we set a random speed on the x and y axis (ranging from -0.5 to 0.5), as well as on the z axis (ranging from 1 to 2). The fire particles start with an initial transparency factor of 70; play with this value until you are happy with the result. The function that controls the particles decreases their alpha quickly; we can't afford to use smaller values because the torch will move together with the player, and it would create a huge, unrealistic trail behind the player. The last line of code removes the particles that can't be seen anymore. You can use another "effect" line of code inside action "torch" and slightly modified particle functions if you want to add smoke as well.

 

Here's a trick: I have used a torch model with a weird origin; this way I didn't have to use complicated math (but simply my.x) in order to make sure that the flames start inside the torch model. Well, the needed math is here anyway (look at the formulas that bind the player and the torch together) but I thought that this idea might be helpful in one of your future projects.

 

aum43_shot16