Tutorial: Create a Tower Defense Game in AS3 – Part 5


Written By MrSun at 8:05 am - Saturday, February 28th, 2009
Categories: Flash

Step 5: Winning/Losing the Game

Welcome back to the 5th installment of this tutorial series. In this lesson, we’ll make some playable levels, along with a winning and losing situation. Let’s dig in, shall we?

Lets start off by opening up the main source file. Find where this code is:

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]
			  ];

Let’s review this code for a bit. Each of those arrays within that enemyArray represents a level. So, right now, we’re set up for 3 different levels, with an increasing amount of enemies in each level. Now that we’ve covered this, we can continue on to making it possible to advance levels.

In order to do this, we must open up “Enemy.as”. Find the destroyThis() function. Add this code to the bottom.

_root.enemiesLeft --;

Next, we’ll have to go back to “source.fla”. Find the eFrame() function. There should only be one line of code in there right now. We’re going to add some. Add the following code to the bottom of the eFrame() function:

if(enemiesLeft==0){//if there are no more enemies left
	currentLvl ++;//continue to the next level
	currentEnemy = 0;//reset the amount of enemies there are
	startGame();//restart the game
}

Now, try testing out the game. Functionally, it’s working 100%. Practically, it’s not a great game. In order to make this game better, we’re going to have to show some information to the user while they’re playing, like the current level, the score, etc. This is exactly what we’re going to do now.

Create four dynamic text boxes at the bottom left portion of the stage, each at 12 point font. Here’s an example of what yours should look like, with an example of what information we’re going to put into them later:

The Text Fields

Got that? Now, we just have to give each of these dynamic text fields an instance name. Label them accordingly:

  • txtLevel
  • txtMoney
  • txtLives
  • txtEnemiesLeft

Now, let’s dive into some code, shall we?

The first thing we need to do is actually define the money and the lives variables. Just add this code to the top:

var money:int=100;//how much money the player has to spend on turrets
var lives:int=20;//how many lives the player has

Okay, good stuff. Let’s first make these two variables mean something before we update the text. We first have to make it so the player loses lives so he/she can lose the game. Open up “Enemy.as” and find this code:

//checking what direction it goes when finishing the path
if(_root.finDir == 'UP'){//if it finishes at the top
	if(this.y <= -25){//if the y value is too high
		destroyThis();//then remove this guy from the field
	}
} else if(_root.finDir == 'RIGHT'){//and so on for other directions
	if(this.x >= 550){
		destroyThis();					
	}
} else if(_root.finDir == 'DOWN'){
	if(this.y >= 300){
		destroyThis();
	}
} else if(_root.startDir == 'LEFT'){
	if(this.x <= 0){
		destroyThis();
	}
}

All we have to do is make the player lose a life after all of these conditionals. It should look like this now:

//checking what direction it goes when finishing the path
if(_root.finDir == 'UP'){//if it finishes at the top
	if(this.y <= -25){//if the y value is too high
		destroyThis();//then remove this guy from the field
		_root.lives --;//take away a life
	}
} else if(_root.finDir == 'RIGHT'){//and so on for other directions
	if(this.x >= 550){
		destroyThis();					
		_root.lives --;
	}
} else if(_root.finDir == 'DOWN'){
	if(this.y >= 300){
		destroyThis();
		_root.lives --;
	}
} else if(_root.startDir == 'LEFT'){
	if(this.x <= 0){
		destroyThis();
		_root.lives --;
	}
}

Next, we'll make each of the turrets cost a certain amount of money. I'm thinking $20 is a good price. Open up "EmptyBlock.as" and find the thisClick function. Change it to this:

private function thisClick(e:MouseEvent):void{
	if(_root.money >= 20){//if the player has enough money
		_root.makeTurret(this.x,this.y);//make the turret
		//remove all the listeners so it can't be clicked on again
		this.buttonMode = false;
		this.graphics.beginFill(0x333333);
		this.graphics.drawRect(0,0,25,25);
		this.graphics.endFill();
		this.removeEventListener(MouseEvent.MOUSE_OVER, thisMouseOver);
		this.removeEventListener(MouseEvent.MOUSE_OUT, thisMouseOut);
		this.removeEventListener(MouseEvent.CLICK, thisClick);
		
		_root.money -= 20; //spend the money
	}
}

Now, we can update these text fields. Once again, find the eFrame() function in "source.fla". Add the following code which will update all the text fields with the needed information:

//Updating the text fields
txtLevel.text = 'Level '+currentLvl;
txtMoney.text = '$'+money;
txtLives.text = 'Lives: '+lives;
txtEnemiesLeft.text = 'Enemies Left:  '+enemiesLeft;

Now, let's create some winning and losing scenarios for the player. When the player has beaten all of the levels, then a win screen should show up. The same thing should happen with a lose screen when the player loses all of his/her lives. Let's create these two frames, shall we?

Before, we create the frames, we have to add a layer called "labels". This will just let us easily navigate to the required frames. Next, create a frame labeled "win" and add whatever message you want to inform the player that they've won. Do the same with a "lose" frame.

Now, we have to make it possible for the player to restart the game. We'll let them do it by clicking anywhere on the screen. Copy and paste this code to the "win" frame.

stage.addEventListener(MouseEvent.CLICK, restartGame);//adding a mouse event listener for clicking the stage
function restartGame(e:MouseEvent):void{
	gotoAndStop(1);//go to the first frame
	stage.removeEventListener(MouseEvent.CLICK, restartGame);//remove the listener
}

We don't need to define the function again in the "lose" frame, so you can just add this code to it:

stage.addEventListener(MouseEvent.CLICK, restartGame);//adding a mouse event listener for clicking the stage

All right, the next thing we have to do is navigate to the desired frame when the player wins or loses. Go back to "source.fla" and find the eFrame() function. Add the following code to the very beginning of it:

//if there aren't any levels left
if(currentLvl > enemyArray.length){
	gameOver=true;//set the game to be over
	
	//reset all the stats
	currentLvl = 1;
	currentEnemy = 0;
	enemyTime = 0;
	enemyLimit = 12;
	enemiesLeft = 0;
	
	removeEventListener(Event.ENTER_FRAME, eFrame);//remove this listener
	removeChild(roadHolder);//remove the pieces of road
	gotoAndStop('win');//go to the win frame
}
if(lives<=0){//if the user runs out of lives
	gameOver=true;//set the game to be over
	
	//reset all the stats
	currentLvl = 1;
	currentEnemy = 0;
	enemyTime = 0;
	enemyLimit = 12;
	enemiesLeft = 0;
	
	removeEventListener(Event.ENTER_FRAME, eFrame);//remove this listener
	removeChild(roadHolder);//remove the pieces of road
	gotoAndStop('lose');//go to the lose frame
}

Sweet. This concludes this installment of the tutorial series. Join us next time when we expand on the game!

Final Product

Source Files (Zipped)

5 Comments

Scott King:

When you either win or lose the game, the ‘Enemies Left’ number is not correct and will not send the second wave after you reset the game.


Anonymous:

“When you either win or lose the game, the ‘Enemies Left’ number is not correct and will not send the second wave after you reset the game.”
How to fix this?


john:

i cant seen to get the enemies to go left at all. do i have to change the this.x speed to a negative?


Levi Reynolds:

Re: Scott King’s comment

In order to fix that, modify the tutorial’s code for the root frame’s action script to initialize the enemiesLeft int to 0.

var enemiesLeft:int = 0


SomeOne:

When i add the code for when you go to next level it throws
TypeError: Error #1010: A term is undefined and has no properties.


«
»