How to Create a Tower Defense Game in AS2 – Part 3
Part 3: Adding Enemies
Welcome back. In this part of the tutorial, we are going to add enemies to the field and we’re going to program them to move through the paths.
Let’s begin by adding the enemy to the stage. Like the other symbols, we’re going to do it by creating an empty MovieClip and drawing the shape into it. In order to do this, however, we must first define some variables. Do this at the top of the code:
var currentEnemy:Number = 0;//the current enemy that we're creating from the array var enemyTime:Number = 0;//how many frames have elapsed since the last enemy was created var enemyLimit:Number = 12;//how many frames are allowed before another enemy is created var enemyArray:Array = new Array();//this array will tell the function when to create an enemy var enemiesLeft:Number;//how many enemies are left on the field enemyArray = [//defining the array [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],//1's will just represent an enemy to be created [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],//another row means another level [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1] ];
I’ve extensively commented on what each variable does. Next, we need to create an onEnterFrame() function with a few actions, along with a few other stuff. Program this into the bottom of the code:
createEmptyMovieClip('enemyHolder',_root.getNextHighestDepth());//create a movieclip that will hold the enemy _root.onEnterFrame = function(){ makeEnemies();//we'll just make some enemies } function makeEnemies():Void{//this function will add enemies to the field if(enemyTime < enemyLimit){//if it isn't time to make them yet enemyTime ++;//then keep on waiting } else {//otherwise var theCode:Number = enemyArray[currentLvl-1][currentEnemy];//get the code from the array if(theCode == 1){//if it's set as 1 //then create a new enemy and add it to the enemy holder enemyHolder.createEmptyMovieClip('enemy'+currentEnemy,enemyHolder.getNextHighestDepth()); //now we're going to draw the enemy. It'll just be a tiny red circle enemyHolder['enemy'+currentEnemy].beginFill(0xFF0000);//coloring them red gray enemyHolder['enemy'+currentEnemy].moveTo(0, 2.5);//move the entire shape a certain way //create 4 curves so that it'll look like a circle enemyHolder['enemy'+currentEnemy].curveTo(0,10,5,10); enemyHolder['enemy'+currentEnemy].curveTo(10,10,10,5); enemyHolder['enemy'+currentEnemy].curveTo(10,0,5,0); enemyHolder['enemy'+currentEnemy].curveTo(0,0,0,5); enemyHolder['enemy'+currentEnemy].endFill();//end the fill } currentEnemy ++;//move on to the next enemy enemyTime = 0;//and reset the time } }
Now, if you test out the game, a red dot should appear on the top left corner of the screen. But, this isn’t what we want for our game, is it? In order to place the enemy so that it’s right next to the start point, we’re going to have to add some code. Remember the variables startDir and finDir that we created all that time ago? If you don’t here’s what it should look like at around line 11:
var startDir:String;//the direction the enemies go when they enter var finDir:String;//the direction the enemies go when they exit var startCoord:Number;//the coordinates of the beginning of the road
Well, we’re going to use these variables. Find in the makeRoad() function where we create add in the SPECIAL DIRECTIONAL ROAD PIECE (around line 129). Add the following code to the bottom of that if statement:
if(lvlArray[i] == 'START'){//if this is a start block //then define the startDir and StartCoord based on it's coordinates if(roadHolder['block'+i]._x == 0){ _root.startDir = 'RIGHT'; _root.startCoord = roadHolder['block'+i]._y; } else if (roadHolder['block'+i]._y == 0){ _root.startDir = 'DOWN'; _root.startCoord = roadHolder['block'+i]._x; } else if (roadHolder['block'+i]._x == 525){ _root.startDir = 'LEFT'; _root.startCoord = roadHolder['block'+i]._y; } else if (roadHolder['block'+i]._y == 275){ _root.startDir = 'UP'; _root.startCoord = roadHolder['block'+i]._x; } else { //this level won't work if not any of these values } } else if (lvlArray[i] == 'FINISH'){//if this is a finish block //then define the finDir based on it's coordinates if(roadHolder['block'+i]._x == 0){ _root.finDir = 'LEFT'; } else if (roadHolder['block'+i]._y == 0){ _root.finDir = 'UP'; } else if (roadHolder['block'+i]._x == 525){ _root.finDir = 'RIGHT'; } else if (roadHolder['block'+i]._y == 275){ _root.finDir = 'DOWN'; } else { //this level won't work if not any of these values } }
Next, we have to take the variables we just defined in this code and make the enemy use them. We also have to make the enemy move along the path. Go back to the makeEnemies() function and add the following code in the if(theCode == 1){ statement:
//add a few variables to the enemy enemyHolder['enemy'+currentEnemy].maxSpeed = 3;//how fast it can possibly go enemyHolder['enemy'+currentEnemy].xSpeed = 0; enemyHolder['enemy'+currentEnemy].ySpeed = 0; //checking what the start direction is if(_root.startDir == 'UP'){//if it's starting up enemyHolder['enemy'+currentEnemy]._y = 300;//set the y value off the field enemyHolder['enemy'+currentEnemy]._x = _root.startCoord;//make the x value where it should be enemyHolder['enemy'+currentEnemy].xSpeed = 0;//make it not move horizontally enemyHolder['enemy'+currentEnemy].ySpeed = -enemyHolder['enemy'+currentEnemy].maxSpeed;//make it move upwards } else if(_root.startDir == 'RIGHT'){//and so on for other directions enemyHolder['enemy'+currentEnemy]._x = -25; enemyHolder['enemy'+currentEnemy]._y = _root.startCoord; enemyHolder['enemy'+currentEnemy].xSpeed = enemyHolder['enemy'+currentEnemy].maxSpeed; enemyHolder['enemy'+currentEnemy].ySpeed = 0; } else if(_root.startDir == 'DOWN'){ enemyHolder['enemy'+currentEnemy]._y = -25; enemyHolder['enemy'+currentEnemy]._x = _root.startCoord; enemyHolder['enemy'+currentEnemy].xSpeed = 0; enemyHolder['enemy'+currentEnemy].ySpeed = enemyHolder['enemy'+currentEnemy].maxSpeed; } else if(_root.startDir == 'LEFT'){ enemyHolder['enemy'+currentEnemy]._x = 550; enemyHolder['enemy'+currentEnemy]._y = _root.startCoord; enemyHolder['enemy'+currentEnemy].xSpeed = -enemyHolder['enemy'+currentEnemy].maxSpeed; enemyHolder['enemy'+currentEnemy].ySpeed = 0; } enemyHolder['enemy'+currentEnemy]._x += 5;//fixing the x value enemyHolder['enemy'+currentEnemy]._y += 5;//fixing up the y value enemyHolder['enemy'+currentEnemy].onEnterFrame = function(){//give it some functions this._x += this.xSpeed; this._y += this.ySpeed; }
The final thing we have to do in this lesson is make the enemy turn when it should turn. To do this, we must go back to the Directional Block. We’re going to use the directional block to access all of the enemies coordinates. If the coordinates are close enough to the block, then it will make the enemy change direction. Find the if(String(lvlArray[i])){ statement in the makeRoad() function. Add this code to the end of it:
roadHolder['block'+i].directType = lvlArray[i];//accessing the type of block it is roadHolder['block'+i].onEnterFrame = function(){//add some functions to this block //then it'll act as a directioning block for(i = 0;i<_root.enemyArray[currentLvl-1].length;i++){//create a loop //if the enemy's coordinates are too close to this block if(this._x >= _root.enemyHolder['enemy'+i]._x - _root.enemyHolder['enemy'+i]._width*.5 && this._x +6<= _root.enemyHolder['enemy'+i]._x + _root.enemyHolder['enemy'+i]._width*.5 && this._y >= _root.enemyHolder['enemy'+i]._y - _root.enemyHolder['enemy'+i]._height*.5 && this._y +6<= _root.enemyHolder['enemy'+i]._y + _root.enemyHolder['enemy'+i]._height*.5){ //then move the enemy's direction based on what direction this block points to if(this.directType == 'UP'){ _root.enemyHolder['enemy'+i].xSpeed = 0; _root.enemyHolder['enemy'+i].ySpeed = -_root.enemyHolder['enemy'+i].maxSpeed; } else if(this.directType == 'RIGHT'){ _root.enemyHolder['enemy'+i].xSpeed = _root.enemyHolder['enemy'+i].maxSpeed; _root.enemyHolder['enemy'+i].ySpeed = 0; } else if(this.directType == 'DOWN'){ _root.enemyHolder['enemy'+i].xSpeed = 0; _root.enemyHolder['enemy'+i].ySpeed = _root.enemyHolder['enemy'+i].maxSpeed; } else if(this.directType == 'LEFT'){ _root.enemyHolder['enemy'+i].xSpeed = _root.enemyHolder['enemy'+i].maxSpeed; _root.enemyHolder['enemy'+i].ySpeed = 0; } } } }