Back to Top

Learn escape games programming

Using timers

game timers

So, you want to create an escape game which uses countdown timers. If that is the case, this article will provide exactly what you need. The code is a bit more complex, but please rest assured that I will do my best to explain it all, as always.

var countdown_timer = 10;

SOUND* gottime_wav = "gottime.wav";

We begin with a variable and a sound definition. Then, it's time to discuss the action that will be attached to player's 3D model.

action PlayersCode()

{

var movement_speed = 20;

VECTOR temp;

set (my, INVISIBLE);

player = my;

We define a variable that sets the movement speed, and then a temporary VECTOR. Since we're going to use a first-person player, we will set its 3D model invisible; this means that you can use any model for the player character (even a simple cylinder!) as long as it has an appropriate size.

The loop below allows the player to rotate by changing its pan angle; "7" sets the rotation speed, so you may want to play with that value.

while (1)

{

my.pan -= 7 * mouse_force.x * time_step;

The camera is kept at player's x, y and z coordinates at all times. Actually, the z coordinate is placed 50 units higher, and this allows us to see through player's virtual "eyes". And let's not forget the "sin(my.skill44)" part, which adds and subtracts small values to player's z as it moves, thus creating a realistic head bobbing experience.

camera.x = my.x;

camera.y = my.y;

camera.z = my.z + 50 + 1.1 * sin(my.skill44);

The camera uses the same pan and tilt angles with the player, so the 3D view will always point where the player is looking.

camera.pan = my.pan;

camera.tilt = player.tilt;

The next few lines make sure that player's feet are always kept on the ground; we have used this technique in one of the previous tutorials, so I won't explain it again.

vec_set (temp.x, my.x);

temp.z -= 10000;

temp.z = -c_trace (my.x, temp.x, IGNORE_ME | IGNORE_PASSABLE | USE_BOX) - 2;

The temporary vector is used to move the player; there's a c_move line of code below that does just that.

temp.x = movement_speed * (key_w - key_s) * time_step;

temp.y = movement_speed * (key_a - key_d) * 0.6 * time_step;

It's been a long ride, but we have finally reached the first line of code that deals with timers. If countdown_timer is greater than zero, the x and y components of the "temp" vector are boosted. The z component is used for gravity-related purposes, as you may remember.

if (countdown_timer > 0)

{

temp.x *= 2;

temp.y *= 1.5;

}

c_move (my, temp.x, nullvector, IGNORE_PASSABLE | GLIDE);

The line above moves the player, making sure that it can go through passable stuff and glide along obstacles, rather than getting stuck.

wait (1);

}

}

It's time to see the code for the GetTime power-ups.

action GetTime()

{

These timer entities are passable, and they will wait until the player shows up in the level. Then, another "while" loop keeps them in place until the player comes closer than 50 units to one of them.

set (my, PASSABLE);

while (!player) {wait (1);}

while (vec_dist (player.x, my.x) > 50) {wait (1);}

When this happens, a sound effect is played, and then the timer entity is made invisible. The countdown timer value is increased, and then the entity is removed.

snd_play(gottime_wav, 100, 0);

set (my, INVISIBLE);

countdown_timer += 10;

wait (-2);

ent_remove(my);

}

But how does the countdown work in the first place? Well, here's your answer!

function countdown_startup()

{

while (1)

{

countdown_timer -= time_step / 16;

countdown_timer = maxv(countdown_timer, 0);

wait (1);

}

}

Basically, the code starts with the preset countdown_timer value, and then decreases it by 1 each second. The next line of code ensures that our timer doesn't go below zero.

PANEL* time_pan =

{

layer = 15;

digits(20, 20, 4 ,* , 1, countdown_timer);

flags = SHOW;

}

Finally, we create a panel that displays the countdown timer value. Its "layer" definition is similar with the one used for VIEWs, so choose it wisely if you want it to be displayed on top of a map, etc.