Tutorial: Create a Tower Defense Game in AS2 – Part 3


Written By MrSun at 8:03 am - Saturday, April 25th, 2009
Categories: Flash

Step 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;
			}
		}
	}
}

Final Product

Source Files (Zipped)

3 Comments

John:

what if statement in the Special Directional Road Peace? please mail me at animeislaw@yahoo.com! tnx!


Scotty:

Interesting code info for beginners to flash.
Small error in the code on this page:
} else if(this.directType == ‘LEFT’){
_root.enemyHolder[‘enemy’+i].xSpeed = _root.enemyHolder[‘enemy’+i].maxSpeed;
_root.enemyHolder[‘enemy’+i].ySpeed = 0;
Left should be a negative X speed.


Sam:

I dont get it, where am I supposed to add the first two blocks of code to get it to work?


«
»