3: Spawning Enemies with Basic AI

This tutorial builds on Part 2 of the six-part tutorial series on building a Space Shooter and you will use some of the same techniques as used there. We will now create enemies and spawn them in as we require.

Prerequisites: Please complete Tutorial 2 first.

Variables: Arrays (multiple values denoted by an index).

Tools & Techniques: random numbers for random positioning of the enemy.

Start by creating a new symbol for an Enemy, much as we did for the Bullets, and again change the advanced properties (either on creation, or later right-click the symbol in the library, select properties, and expand the ‘Advanced’ section.

Draw anything that resembles an enemy, I used a rocket/bullet look that could have instead been used for my bullets. Make sure the enemy faces to the left and place it so the cross-hair is on the left and vertically central.

Go back to your stage (clicking on ‘Scene 1’ at the top left).

Navigate back to the first frame on the ‘actions’ layer and reopen the actions window if it is not already open.

Your coding will begin with the addition of a new array to hold the enemies, much as we did for the bullets. Place the array declaration with all other global variables at the top of your code, under the following bullets_arr declaration:

    var bullets_arr:Array = [];

var enemies_arr:Array = [];

We need to set/reset the array inside our 'initialise' subroutine. So place this code under the resetting of the following bullet_arr array reset:

    bullets_arr = [];

enemies_arr = [];

Next on our 'playerMovement' (EnterFrame) event we wish to call a subroutine that will control the behaviour of our enemies every time a new frame is played (30 times per second). I would advise placing your subroutine call below that for the bullet:


//subroutine to add enemies if required

//subroutine to move all enemies

Finally we simply need to create the subroutines themselves. These are very similar to the addBullet and moveBullet subroutines with some minor adjustments.

We set the ‘x’ position to the far right of the stage and the ‘y’ position to a random number between 0 and the height of the stage.

function addEnemy():void
    //limit number of enemies on screen
    if(enemies_arr.length < 5)
        //declare an object instance from the enemy Class
        var e:Enemy = new Enemy();
        //set the enemy start point to the far right of the stage
        var startX:int = stage.stageWidth;
        //Randomise where the enemy starts on the right
        var startY:int = Math.random() * stage.stageHeight ;

        //set the new bullet's x,y coordinates
        e.x = startX;
        e.y = startY;

        //add the new enemy to the stage
        //store the object in an array

In addition to moving the enemy much as we did the bullet, we will also included an IF...THEN statement that moves the enemy vertically to match that of the player ship (basic AI).

Add the following code at the end and check the comments in the code (lines starting with ‘//’) as these detail what the code is doing.

function moveEnemy():void
    //loop through all instances of the enemy
    //loop from '0' to 'number_of_enemies'
    for (var i:int = 0; i < enemies_arr.length; i++)
        //if the enemy is below the ship then move up
        //else if the enemy is above the ship then move down
        if(enemies_arr[i].y > player_mc.y) 
            enemies_arr[i].y -= 2
        else if(enemies_arr[i].y < player_mc.y) 
            enemies_arr[i].y += 2

        //assume no vertical movement otherwise
        //move the enemy
        enemies_arr[i].x -= 10;
        //if the enemy flies off the screen, remove it
        if(enemies_arr[i].x < 0)
            //remove the enemy from the stage
            //remove the enemy from the array

Random Number Generation

Math.random() - is a pre-defined function in ActionScript 3 to generate a random decimal number equal to or greater than 0, and less than (not equal to) 1.

Similar to many 'between' statements that include the lower value but not the upper. This way, one can have ranges 0-10, 10-20, 20-30, etc, where the value 10 falls in the '10-20' bracket (and not the '0-10' range).

We can force an integer (whole number) value without explicitly converting it by assigning the result to an integer variable:

var rnd:int = Math.random();

This, however, will produce only zero each time. Numbers don't round up/down unless expressly stated, instead the decimal value is simply removed. As Math.random() produces a number between 0 and 0.999 (recurring 9s) inclusive, we simply get the 0.

We could use Math.round() to round the value to its nearest whole number, and pass the Math.random as a parameter. Rounding works as you  would expect in maths, 0.5 or more = 1, 0.499 or less = 0.

For example:

var rnd:int = Math.round(Math.random());

I would advise against using Math.round in this example. It results in more computing power, albeit not a large amount and our application is hardly considerate to resource usage. It is also more simple to simply change our random function.

Instead, multiply Math.random by a value 1 higher than you need. So for a number from 0 to 99 we could write this:

var rnd:int = Math.random() * 100;

The problem with all these numbers is they all start at zero. What if we want a dice roll, 1 to 6 inclusive? We can create a random number between 0 and 5, then add 1 to any result. The line below creates a random number between 1 and 6 inclusive:

var dice:int = Math.random() * 6 + 1;

Using the rules regarding order of precedence (search BIDMAS), the multiplication occurs before the addition (otherwise 6 + 1 = 7, and Math.random * 7 would give a random number between 0 and 6 inclusive...not what we're after).

You could always use brackets to be sure (I recommend):

var rnd:int = ( Math.random() * 6 ) + 1;