Code snippets

Top  Previous  Next

Invaders strikes back
 
A4 includes a powerful 2D engine, too. Let’s see a simple, true 2D invaders demo created with it. The full project is available for download; make sure you copy the Invaders folder inside Game Studio’s folder.

 
PANEL ship_pan {
BMAP ship_map;
LAYER 11;
POS_X 320;
POS_Y 400; // will appear at the bottom of the screen
FLAGS OVERLAY, REFRESH;
}

We define the ship as a panel, but we don’t set its VISIBLE flags yet. We have similar definitions for enemy, rocket (fired by player) and fractal (fired by enemy).

function main()
{
LOAD_LEVEL <invaders.wmb>;
WAITT 16;
CAMERA.PAN = 0; // play with this values to get a better view
CAMERA.TILT = 285;
CAMERA.X = -60;
CAMERA.Y = -170;
CAMERA.Z = -420;

restart (); // initialize the game
move_ship ();
move_enemy ();
move_rocket ();
move_fractal ();
set_collisions ();
}

WAITT 16 waits for the level to load; otherwise we can’t set the camera position and angles. I have added a simple wmb sky that rotates using the ent_rotate action included in the template files.

function move_ship ()
{
       WHILE (1)
       {
               IF (KEY_CUL == ON && ship_pan.POS_X > 40)
               {
                       ship_pan.POS_X -= 2;
               }
               IF (KEY_CUR == ON && ship_pan.POS_X < 600)
               {
                       ship_pan.POS_X += 2;

               }
               WAITT 1;
       }
}

If the left arrow key is pressed and ship’s POS_X is greater than 40, we move the ship to the left; the same thing goes for the right key (ship’s POS_X must be below 600).

function move_enemy ()
{
       WHILE (1)
       {
               IF (enemy_pan.POS_X > 40 && enemy_flag == 1)
               {
                       enemy_pan.POS_X -= 1; // move to the left
               }
               ELSE
               {
                       enemy_flag = 0; // enemy wants to move to the right
                       IF (enemy_pan.POS_X == 40 && enemy_pan.POS_Y < 350)
                       {
                               WHILE (counter < 40)
                               {
                                       enemy_pan.POS_Y += 1; // enemy approaches ship
                                       counter += 1;
                                       WAITT 1;
                               }
                               counter = 0; // we want to use it for the right margin, too
                       }
               }
               IF (enemy_pan.POS_X < 580 && enemy_flag == 0)
               {
                       enemy_pan.POS_X += 1; // move to the right
               }
               ELSE
               {
                       enemy_flag = 1; // enemy wants to move to the left
                       IF (enemy_pan.POS_X == 580 && enemy_pan.POS_Y < 350)
                       {
                               WHILE (counter < 40)
                               {
                                       enemy_pan.POS_Y += 1; // enemy approaches ship
                                       counter += 1;
                                       WAITT 1;
                               }
                               counter = 0; // set it for the left margin
                       }
               }
               WAITT 1;
       }
}

If enemy’s POS_X is greater than 40 and enemy_flag = 1, the enemy will move to the left. When the enemy’s POS_X = 40, the enemy will approach the player using the WHILE (counter < 40) loop. Since enemy_flag = 0 now, the enemy will move to the right. When enemy’s POS_X = 580, the enemy will approach the ship again. The enemy will approach the ship as long as the enemy’s POS_Y is below 350.

function move_rocket ()
{
       WHILE (1)
       {
               IF (KEY_SPACE == ON && ship_pan.VISIBLE == ON)
               {
                       rocket_pan.POS_X = ship_pan.POS_X + 18;
                       rocket_pan.VISIBLE = ON; // show the rocket
                       PLAY_SOUND rocket_snd,100;
                       WHILE (rocket_pan.POS_Y > 10)
                       {
                               rocket_pan.POS_Y -= 4; // move the rocket upwards
                               WAITT 1;
                       }
                       rocket_pan.VISIBLE = OFF; // hide the rocket
                       rocket_pan.POS_Y = 388; // disable collisions if ship is hit
               }
               WAIT 1;
       }
}

If the space key is pressed and the ship isn’t hit, we show the rocket and move it upwards, towards the enemy. We are using 18 = (ship sprite width / 2) - (rocket sprite width / 2) as an offset on X because we want to fire the rocket from the middle of the ship sprite.

function move_fractal ()
{
       WHILE (1)
       {
               IF (enemy_pan.VISIBLE == ON)
               {
                       fractal_pan.POS_X = enemy_pan.POS_X + 10;
                       fractal_pan.POS_Y = enemy_pan.POS_Y + 16;
                       PLAY_SOUND fractal_snd,50;
                       WHILE (fractal_pan.POS_Y < 480)
                       {
                               fractal_pan.VISIBLE = ON;
                               fractal_pan.POS_Y += 4;
                               WAITT 1;
                       }
                       fractal_pan.POS_Y = 72; // disable collisions if enemy is hit
                       fractal_pan.VISIBLE = OFF;
               }
               WAIT 1;
       }
}

The enemy fires fractals all the time; as soon as a fractal disappears, it fires a brand new one. We are using 10 = (enemy sprite width / 2) - (fractal sprite width / 2) and 16 = enemy sprite height / 2 as offsets on X and Y because we want to fire the fractal from the center of the enemy.

The functions used for collision detection and for restarting the game are pretty simple to understand, we let them as an exercise for the user.
 
 

Laser guns how bad do we need them?

This was one of the most requested wdl snippets, so here it is. This laser example is using particles and works fine. The idea is to shoot the wall, get the distance between the player and the wall and then generate particles to cover that distance. The particles are created fast, but we have to remove them even faster, otherwise we get three or four parallel laser beams when strafing. The laser can be improved: you can use bitmap particles, attach it to a gun, etc.

Here’s the code:

ACTION laser_beam // attach it to any entity, it will become invisible
{
       MY.PASSABLE = ON;
       MY.INVISIBLE = ON;
       WHILE (1)
       {
               // set the distance to 5000 quants at first
               laser_temp.X=5000*COS(player.PAN)*COS(CAMERA.TILT)+player.X;
               laser_temp.Y=5000*SIN(player.PAN)*COS(CAMERA.TILT)+player.Y;
               laser_temp.Z=5000*SIN(CAMERA.TILT)+player.Z;

               SHOOT player.POS,laser_temp;
               // now laser_temp holds the RESULT
               ……………….
 
               pos1.X = MY.X;
               pos1.Y = MY.Y;
               pos1.Z = MY.Z + 16;

               pos2.X = PLAYER.X;
               pos2.Y = PLAYER.Y;
               pos2.Z = PLAYER.Z;

               laser_particle();

               WAIT 1;
       }
}

The function laser_particle is derived from particle_line in template and will generate a “line” of particles between pos1 (hit point) and pos2 (the player).

function particle_start()
{
       IF (MY_AGE == 0)
       {
               MY_COLOR.RED = 200; // red laser beam
               MY_COLOR.GREEN = 0;
               MY_COLOR.BLUE = 0;
               MY_SIZE = 100;
               return;
       }
       MY_ACTION = NULL;
}

In this action we destroy the particle as soon as it is created. MY_SIZE could be changed depending on the distance so that the particles that are closer to the player are smaller.