Minimap

3DGS allows us to have several views on the screen at the same time; I have used this great feature to create a top view of the screen.

Let's see the view definition first:

view top_view
{
layer = 15;
pos_x = 0;
pos_y = 0;
size_x = 200;
size_y = 150;
tilt = -90;
arc = 80;
}

The view has 200 x 150 pixels and appears in the upper left corner of the screen. The view loks down because its tilt is set to -90 and its zooming factor was set to 80 (play with this value to see more / less from your level on the top view).

I have used a "starter" function (a function that runs by itself when we run the level) to show / hide the minimap:

starter init_topcam()
{
while (player == null) {wait (1);}
while (1)
{
if (key_t == 1)
{
while (key_t == 1) {wait (1);}
if (top_view.visible == on)
{
top_view.visible = off;
}
else
{
top_view.visible = on;
}
}
top_view.x = player.x;
top_view.y = player.y;
top_view.z = 1000; // play with this value
wait (1);
}
}

We wait until the player appears in the level and then we show or we hide the minimap when the "T" key is pressed. The view will have the same x and y with the player and it will be placed at a height of 1,000 quants. Your levels could have a different height so you should play with this value.

You should add a small frame to the minimap view (use 2 or 4 thin panel stripes).

Water drops

This effect could add a lot of value to your game. I would use it inside my cave levels, for broken pipes and (why not?) for rain!

My example shows drops falling from a broken pipe and producing ripples when they impact with the water pool below. We need to place a drop generator inside our level and this is the action that must be attached to it:

action drop_generator
{
my.invisible = on;
my.passable = on;
while (1)
{
ent_create(drop_mdl, my.pos, falling_drop);
sleep (4 + random(2));
}
}

The drop generator will be made invisible and passable so we can use any model for it; I have used the drop model itself. This generator creates a drop at its position every 4...6 seconds. The drop that is created will run the function named falling_drop:

function falling_drop()
{
my.flare = on;
vec_set(temp, my.pos);
vec_set(drop_height, my.pos);
temp.z -= 5000; // trace 5000 quants below the drop generator
trace_mode = ignore_me + ignore_models + ignore_sprites;
drop_height.z = my.z - trace(my.x, temp) + 2; // place the ripple sprite 2 quants above the water surface
while (my.z > drop_height.z)
{
my.z -= 3 * time;
wait (1);
}
ent_create(ripple_pcx, my.pos, ripple_effect);
ent_remove(me); // remove the drop
}

The drop model will have its "flare" flag set. We trace between the current position of the drop and a position that is placed 5000 quants below, storing the result (the height of the water surface) in drop_height.z. We add two quants to the result because we want to place the sprite used for the ripple above the water surface.

We make the drop fall by changing its z inside a while loop and when it has the same height with the water surface we create the ripple effect (using the sprite named ripple_pcx) and then we remove the drop.

function ripple_effect()
{
ent_playsound (my, drip_wav, 500);
my.oriented = on;
my.flare = on;
my.alpha = 60;
my.tilt = 90;
while (my.scale_x < 5)
{
my.scale_x += 0.03 * time;
my.scale_y = my.scale_x;
if (my.scale_x > 3)
{
my.alpha -= 1 * time;
}
wait (1);
}
ent_remove(me); // remove the sprite
}

We play the drip_wav sound, we set the "oriented" and "flare" flags for the sprite and we choose the proper "tilt" angle and "alpha" value for it. We start to increase the size of the sprite in a while loop, decreasing its alpha factor when its scale is over three. When the scale of the sprites has grown over five, we remove it.