7 days of WordPress plugins, themes & templates - for free!* Unlimited asset downloads! Start 7-Day Free Trial
  1. Code
  2. Games

Make a Tower Defense Game in AS3: Enemies and Basic AI

Scroll to top
Read Time: 20 mins

Hey Flash Developers, welcome to the second part of my Tower Defense Game tutorial. In the first part, we developed the basic mechanism of creating turrets and making them shoot towards the point of mouse click. But that's not what turrets are for! In this part we'll extend the game to include enemies, basic artificial intelligence (AI) in turrets, and some more game elements. Are you ready?

Final Result Preview

This is the game we are going to create in this tutorial:

Click the orange circles to place turrets. The red circles are enemies, and the number on each represents its hit points.

Step 1: Recap

In the previous tutorial we developed a game which had placeholders for the turrets. We could deploy turrets by clicking those placeholders, and the turrets aimed at the mouse pointer and shot bullets towards the point where the user clicked.

We finished with a Main class which had the game loop and game logic. Apart from that we had the Turret class which had nothing much except the update function that made the turret rotate.

Step 2: A Separate Bullet Class

We previously created the bullets in Main class and attached an ENTER_FRAME listener to move it. The bullet did not have enough properties earlier to consider it a making a separate class. But in such a game bullets can have many varieties like speed, damage, and so on, so it is a good idea to pull out the bullet code and encapsulate it in a separate Bullet class. Let's do it.

Create a new class called Bullet, extending the Sprite class. The basic code for this class should be:

Next we put the code to draw the bullet graphic, taken from Main, in Bullet. As we did with the Turret class, we create a function called draw in the Bullet class:

And we call this function from the Bullet constructor:

Now we add some properties to the bullet. Add four variables: speed, speed_x, speed_y and damage, before the Bullet constructor:

What are these variables for?

  • speed: This variable stores the speed of the bullet.
  • speed_x and speed_y: These store the x and y components of the speed, respectively, so that the calculation of breaking the speed into its components does not have to be done again and again.
  • damage: This is the amount of damage the bullet can do to an enemy. We keep this variable public as we will require this in our game loop in the Main class.

We initialize these variables in the constructor. Update your Bullet constructor:

Notice the angle variable we receive in the constructor. This is the direction (in degrees) in which the bullet will move. We just break the speed into its x and y components and cache them for future use.

The last thing that remains in the Bullet class is to have an update function that will be called from the game loop to update (move) the bullet. Add the following function at the end of the Bullet class:

Bingo! We are done with our Bullet class.

Step 3: Updating the Main Class

We moved a lot of bullet code from Main class to its own Bullet class, so a lot of code remains unused in Main and much needs to be updated.

First, delete the createBullet() and moveBullet() functions. Also remove the bullet_speed variable.

Next, go to the shoot function and update it with the following code:

We no longer use the createBullet function to create bullet rather use the Bullet constructor and pass the turret's rotation to it which is the direction of the bullet's movement and so we don't need to store it in the bullet's rotation property as we did earlier. Also we don't attach any listener to the bullet as the bullet will be updated from within the game loop next.

Step 4: Saving the Bullet References

Now that we need to update the bullets from the game loop, we need a reference of them to be stored somewhere. The solution is the same as for the turrets: create a new Array named bullets and push the bullets onto it as they are created.

First declare an array just below the turrets array declaration:

Now to populate this array. We do so whenever we create a new bullet - so, in the shoot function. Add the following just before adding the bullet to the stage:

Step 5: Update the Bullets

Just like how we update the turrets the game loop, we will update the bullets, too. But this time, instead of using a for...each loop, we'll use a basic for loop. Before this, we must add two variables to the top of the game loop, so that we know which variables are used within the game loop and can set them free for garbage collection.

Go ahead and add the following code at the end of game loop:

Here we traverse over all the bullets on the stage every frame and call their update function which makes them move. Note here that we iterate the bullets array in reverse. Why? We'll see this ahead.

Now that we have a turret variable declared outside already, we don't need to declare it again inside the for...each loop of turrets. Modify it to:

Finally we add the boundary check condition; this was previously in the bullet's ENTER_FRAME but now we check it in the game loop:

We check whether the bullet is out of the stage's boundary, and if so we first remove its reference from the bullets array using the splice function, and then remove the bullet from the stage and continue with the next iteration. This is how your game loop should look:

If you now run the game, you should have the same functionality as in Part 1, with code that is much more clean and organized.

Step 6: Presenting the Enemy

Now we add one of the most important elements of the game: the Enemy. First thing is to create a new class named Enemy extending the Sprite class:

Now we add some properties to the class. Add them before your Enemy constructor:

We initialize these variables in the Enemy constructor:

Next we create the draw and update functions for the Enemy class. These are very similar to the ones from Bullet. Add the following code:

Step 7: Timing the Game Events

In our game we need to have many events that take place at certain times or repeatedly at certain intervals. Such timing can be achieved using a time counter. The counter is just a variable that gets incremented as the time passes in the game. The important thing here is when and by how much amount to increment the counter. There are two ways in which timing is generally done in games: Time based and Frame based.

The difference is that the unit of step in time based game is based on real time (i.e. number of milliseconds passed), but in a frame based game, the unit of step is based on frame units (i.e. the number of frames passed).

For our game we are going to use a frame based counter. We'll have a counter which we'll increment by one in the game loop, which runs each frame, and so will basically give us the number of frames which have passed since the game started. Go ahead and declare a variable after the other variable declarations in the Main class:

We increment this variable in the game loop at the top:

Now based on this counter we can do stuff like creating enemies, which we'll do next.

Step 8: Let's Create Some Enemies

What we want to do now is create enemies on the field after every two seconds. But we are dealing with frames here, remember? So after how many frames should we create enemies? Well, our game is running at 30 FPS, thus incrementing the global_time counter 30 times each second. A simple calculation tells us that 3 seconds = 90 frames.

At the end of the game loop add the following if block:

What is that condition about? We use the modulo (%) operator, which gives the remainder of a division - so global_time % 90 gives us the remainder when global_time is divided by 90. We check whether the remainder is 0, as this will only be the case when global_time is a multiple of 90 - that is, the condition returns true when global_time equals 0, 90, 180 and so on... This way, we achieve a trigger at every 90 frames or 3 seconds.

Before we create the enemy, declare another array called enemies just below the turrets and bullets array. This will be used to store references to enemies on the stage.

Also declare an enemy variable at the top of the game loop:

Finally add the following code inside the if block we created earlier:

Here we create a new enemy, position it randomly at the right of the stage, push it in the enemies array and add it to the stage.

Step 9: Updating the Enemies

Just like we update the bullets in the game loop, we update the enemies. Put the following code below the turret for...each loop:

Just like we did a boundary check for bullets, we check for enemies too. But for enemies we just check whether they went out of the left side of the stage, as they only move right-to-left. You should see enemies coming from the right if you run the game now.

Step 10: Give the Enemies Some Health

Every enemy has some life/health and so will ours. We will also show the remaining health on the enemies. Lets declare some variables in the Enemy class for the health stuff:

We initialise the health variable in the constructor next. Add the following to the Enemy constructor:

Now we initialize the health text variable to show on the center of enemy. We do so in the draw function:

All we do is create a new TextField, set its color, position it and set its text to the current value of health Finally we add a function to update the enemy's health:

The function accepts an integer to add to the health, updates the health text, and returns the final health. We'll call this function from our game loop to update each enemy's health and detect whether it's still alive.

Step 11: Shooting the Enemies.

First lets modify our shoot function a bit. Replace the existing shoot function with the folowing:

The shoot function now accept two parameters. The first is a reference to a turret which will do the shooting; the second is a reference to a enemy towards which it will shoot.

The new code here is similar to the one present in the Turret class's update function, but instead of the mouse's position we now use the enemy's cordinates. So now you can remove all the code from the update function of the Turret class.

Now how to make the turrets shoot at enemies? Well the logic is simple for our game. We make all the turrets shoot the first enemy in the enemies array. What? Lets put some code and then try to understand. Add up following lines in the end of the for...each loop used to update the turrets:

For every turret we now update it, then iterate the enemies array, shoot the first enemy in the array and break from the loop. So essentially each turret shoots at the earliest created enemy as it is always at the beginning of the array. Try running the game and you should see turrets shooting the enemies.

But wait, what's that bullet stream flowing? Looks like they are shooting too fast. Lets see why.

Step 12: Turrets Are Shooting Too Fast

As we know, the game loop runs every frame i.e. 30 times a second in our case, so the shooting statement we added in the previous step gets called at the speed of our game loop and hence we see a stream of bullets flowing. Looks like we need a timing mechanism inside the turrets too. Switch over to the Turret class and add the following code:

  1. local_time: Our counter is called local_time in contrast to the global_time in the Main class. This is for two reasons: first, because this variable is local to the Turret class; second, because it doesn't always go forward like our global_time variable - it will reset many times during the course of the game.
  2. reload_time: This is the time required by the turret to reload after shooting a bullets. Basically its the time difference between two bullet shoots by a turret. Remember all time units in our game are in terms of frames.

Increment the local_time variable in the update function and initialize the reload_time in the constructor:

Next add the following two functions at the end of the Turret class:

isReady returns true only when the current local_time is greater than the reload_time, i.e. when the turret has reloaded. And the reset function simply resets the local_time variable, to start it reloading again.

Now back in the Main class, modify the shoot code in the game loop we added in the previous step to the following:

So if now the turret isn't ready (isReady() returns false), we continue with the next iteration of the turret loop. You will see that the turrets fire at an interval of 30 frames or 1 second now. Cool!

Step 13: Limit the Turret Range

Still something not right. The turrets shoot at enemies irrespective of the distance between them. What's missing here is the range of a turret. Each turret should have its own range inside which its can shoot an enemy. Add another variable to the Turret class called range and set it to 120 inside the constructor:

Also add a function called canShoot at the end of the class:

Every turret can shoot an enemy only when it meets certain criteria - for example, you could let the turret shoot only red enemies with less than half their life and not more than 30px away. All such logic to determine whether the turret is able to shoot an enemy or not will go in the canShoot function, which returns true or false according to the logic.

Our logic is simple. If the enemy is within the range return true; otherwise return false. So when the distance between the turret and enemy (Math.sqrt(dx * dx + dy * dy)) is less than or equal to range, it returns true. A little more modification in the shoot section of the game loop:

Now only if the enemy is within the range of the turret, will the turret shoot.

Step 14: Collision Detection

A very important part of every game is the collision detection. In our game collision check is done between bullets and enemies. We will be adding the collision detection code inside the for...each loop which updates the bullets in the game loop.

The logic is simple. For every bullet we traverse the enemies array and check if there's a collision between them. If so, we remove the bullet, update the enemy health and break out of the loop to check other enemies. Let's add some code:

We use ActionScript's hitTestObject function to check for collision between the bullet and enemy. If the collsion occurs, the bullet is removed in the same way as when it leaves the stage. The enemy's health is then updated using the updateHealth method, to which bullet's damage property is passed. If the updateHealth function returns an integer less than or equal to 0, this means the enemy is dead and so we remove it in the same way as the bullet.

And our collision detection is done!

Step 15: Why Reverse the "For" Loops?

Remember that we traverse the enemies and bullets in reverse in our game loop. Let's understand why. Let suppose we used an ascending for loop. We are on index i=3 and we remove a bullet from the array. On removal of the item at position 3, its space is filled by the item then at position 4. So now the item previously at position 4 is at 3. After the iteration i increments by 1 and becomes 4 and so item at position 4 is checked.

Oops, you see what happened just now? We just missed the item now at position 3 which shifted back as the result of splicing. And so we use a reverse for loop which removes this problem. You can see why.

Step 16: Displaying the Turret's Range

Let's add some extra stuff to make the game look good. We'll add functionality to display a turret's range when the mouse is hovered on it. Switch over to the Turret class and add some variables to it:

Next update the draw function to the following:

We break the graphics of the turret into two parts: the body and the range graphic. We do this so as to give an ordering to the different parts of the turret. Here we require the range_circle to be behind the turret's body, and so we add it first to the stage. Finally, we add two mouse listeners to toggle the range graphic:

Now attach the listeners to the respective events at the end of the constructor:

If you run the game and try to deploy a turret, you will see a flickering when hovering on the placeholders. Why is that?

See the flicker?

Step 17: Removing the Flicker

Remember we set the mouseEnabled property of the ghost turret to false? We did that because, the ghost turret was capturing mouse events by coming in between the mouse and the placeholder. The same situation has arrived again as the turret itself has two children now - its body and the range sprite - which are capturing the mouse events in between.

The solution is the same. We can set their individual mouseEnabled properties to false. But a better solution is to set the ghost turret's mouseChildren property to false. What this does is restrict all the children of ghost turret from receiving mouse events. Neat, huh? Go ahead and set it to false in the Main constructor:

Problem solved.

Step 18: What Next?

We could extend this demo to include much more advanced features and turn it into a playable game. Some of which could be:

  1. Better AI logic for selecting and shooting enemies.
  2. Different type of turrets, bullets and enemies in the game.
  3. Complex enemy paths instead of straight lines.

Let's see what you can come up with from this basic demo. I'll be glad to hear about you tower defense games, and your comments or suggestions for the series.

Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.