Code snippets

Top  Previous  Next

Intelligent cameras

Many of you have asked me about the best method to create some cameras that will act like the ones in Resident Evil. I came up with a simple solution that has the advantage that the cameras are constantly looking at the player so they can’t miss the hero if you place a reasonable number of cameras in your level.

This example was created for 50 cameras but you can have as many as you want. To test the code, include recam.wdl and call fixed_cameras() in main. Place some dummy models in your level (I have used fish.mdl) set their pan, tilt and roll angles in Wed and attach the recam action to them. Don’t forget to set skill1for these models to 1..50; you don’t have to set it in a particular order; just make sure that you don’t have two cameras with the same skill1 value set in Wed. The values set for skill1 are used by the wdl to select the camera with the best view at a certain moment. If you want, you can load and run my modified office.wmp to see an example.

I don’t want to modify the templates so I have to disable the current view and enable the new re_camera view. Let’s take a look at the recam action first:

action recam
{
     my.invisible = on;
     my.passable = on;
     re_camera.tilt = my.tilt;
     re_camera.roll = my.roll;
     if (my.skill1 == 0) {remove me; beep; beep; return;}
     while (1)
     {
          camera_position[my.skill1] = vec_dist(my.x, player.x);
          if (winner > camera_position[my.skill1] - 50)
          {
               re_camera.x = my.x;
               re_camera.y = my.y;
               re_camera.z = my.z;

               vec_set(temp, player.x); // re_camera's pan
               vec_sub(temp, my.x);
               vec_to_angle(re_camera.pan, temp);
         }
         wait (1);
    }
}

The dummy models are made invisible and passable; their orientation (tilt, roll) is used by re_camera. Pan is computed every frame to make the cameras look at the player without missing it for a second.

I’m using the array camera_position[50] to store the distance between every camera and the player; camera_position[1] holds the distance between the player and camera that has its skill1 set to 1 in Wed, camera_position[35] holds the distance between the player and the camera that has its skill1 set to 35 and so on. I’m using a simple vec_dist(my.x, player.x) to compute the distance between the player and the camera. I have declared a variable named winner – this is the smallest distance between the player and any camera. If we find a winner, we set re_camera to the new (fish) coordinates and we constantly rotate it towards the player using a simple vec_to_angle instruction.

function fixed_cameras()
{
     camera.visible = off;
     re_camera.visible = on;
     while (1)
     {
          temp_counter += 1;
          if (temp_counter == 50)
          {
               temp_counter -= 49;
          }
          if (camera_position[temp_counter] < winner && camera_position[temp_counter] > 0)
          {
               winner = camera_position[temp_counter];
               found_camera = temp_counter;
          }
          else
          {
               winner = camera_position[found_camera];
          }
          wait (1);
    }
}

Function fixed_cameras includes a while loop that constantly looks for winners. If the distance between the camera and the player is smaller than winner, this camera will be activated. We have to make sure that camera_position[temp_counter] is bigger than zero because our level could use less than 50 cameras – all the unused values in the array are zero but this shouldn't make them winners.

I hope that you will have fun with this camera code.

Earthquake

If you need to add an earthquake to your 1st person game, there's a simple solution: store player’s eye height (eye_height_up) from templates, then play with it and with player’s roll angle. Restore the original values when the earthquake is over and everything will work as before.

The good thing with this code is that you can't jump out of the level because you aren't moving at all (of course you can add code for that); unfortunately, your customer doesn't know this, so he will certainly fall in that lava pool because he will move in order to keep the player in a safe area :)

The earthquake starts when you run into an entity (attach it the quakegen action, make it invisible if you want). I would use a visible stair (built as a wmb entity) that leads to a rope bridge placed above the lava pool:

action quakegen
{
    my.enable_impact = on;
    my.event = earthquake;
}

function earthquake
{
    my.skill9 = eye_height_up;
    my.skill10 = random(100) + 20;
    my.skill11 = random(100) + 100;
    waitt(my.skill10);
    while (my.skill11 > 0)
    {
        if (random(1) > 0.9)
        {
            play_sound eq_snd, 30;
        }
        if (eye_height_up > 0.2)
        {
            eye_height_up += 0.1 - random(2)/10;
        }
        player.roll += 10 - random(20);
        my.skill11 -= 0.1 * time;
        waitt(2);
    }
    eye_height_up = my.skill9;
    player.roll = 0;
}

Skill10 gives the initial delay (so the player can’t tell when / if he has triggered the earthquake) and skill11 gives the duration; play with these values.