Adding progressive difficulty

Next, we'll tackle making the game progressively more difficult. There are many, many ways to do this--limited only by your imagination! I'm going to use the strategy of just progressively increasing the downward speed of the enemies. This is really easy to do. We'll introduce a variable called spiderSpeed. It needs to be a Number type rather than an integer, so that it can handle fractions. We'll set it to an initial value of 3:

var spiderSpeed:Number = 3;

Next, we'll substitute this variable in the moveEnemies function in place of the previous hard-coded number 3:

spiderArray[i].y += spiderSpeed;

Now we just need a way of increasing this spiderSpeed variable by some factor. A good place to do this is in the enemiesHitTest function, at the point where an enemy has been hit, and the 10 points have been added to the score. So insert this line right after the updateScore(10) line:

spiderSpeed = spiderSpeed * 1.01;

This will make the speed of the enemies increase by 1% each time an enemy is hit, the idea being that shooting them only makes them increasingly madder! This line causes the spiders to get faster and faster, and fairly quickly, too! But not so quickly as to be ridiculous. This makes the game a bit more fun and challenging. There are still many ways that you could improve on this, though. Here is where you can let your imagination soar, and here are some more ideas:

  • Make a version that uses the mouse instead of the keyboard.
  • Program different keyboard keys to your own taste, or even make it configurable by the user!
  • Gradually increase the speed of the player as well, to match the speed of the enemies, or make it almost as much.
  • Add some more animations to the player and the spiders. Give them some animations on their timelines, put a stop in their first frame, and decide to play their timeline in strategic places. This way, you can make animations of explosions, shriveling, or whatever your mind can conceive of as a way to "die."
  • You can certainly start off with a larger number of enemies if you want to. Be sure to adjust any for loops so that the "condition" to keep looping uses this larger number instead.
  • Keep track of how many enemies have gone by. After a certain number, go to a new level where there an even larger number of enemies to deal with. 
  • On succeeding levels, make the enemies fire bullets at the player.
  • On succeeding levels, make the enemies move in different ways.
  • Make the enemies move side to side in "space invaders" fashion, so that they don't come down until they hit the edge of the stage. Make their motion get faster and faster as the game progresses, just like we did above.

All of the above ideas are possible, but I'm only going to take you so far in this tutorial. The rest is up to you. I wanted to give you some basics for a foundation, and hopefully I've accomplished that. But you should really understand that I have definitely not showed you the only way to make a game, or even the right way. It's just a beginning. You might also want to get it off the main timeline and use my Better Flash Navigation using AS3 Classes system instead, which will also make it much easier to create new levels. 

I made a couple of small improvements to the game, based on my observations while playing it:

I moved the player to the bottom of the screen, and also moved all the bullets down, so that they are out of sight below the bottom of the screen. This was begging to be fixed. The hard number 595 in the moveBullets function was changed to 617.

I dragged the player layer upward in the timeline's layer stack, so that it is above the spiders layer. It looked a bit funny to see spiders emerging from the top, but the ones that came down from the upper right were layered in front of the "remaining lives" instances.

Next, I added a few sounds to make the game more interesting. I had so much fun doing this! I had a collection of sounds already on hand, and I chose a few of them for certain game events.

To get a sound into your game, the easiest way is to import it to the library. Then, right click it, choose "Properties," then check off "Export for Actionscript." You'll need to supply a class name. Don't accept the default one suggested by Flash. It will likely be based on the file name, complete with a .wav extension or whatever the extension is. Instead, choose a name that makes sense to you in the context of the game, and that's easy to remember. For example, I used "PlayerHit" for the class name of the sound I wanted to associate with that. When you click OK on this dialog box, just click OK again when Flash tells you that the class couldn't be found in the classpath. It's all right. We want Flash to create the class for us.

Next, find the place in the code where you would like to play a certain sound. For example, the player is (possibly) hit in the first half of the enemiesHitTest function. Insert a new line right after the one that does the hit testing. It's an if condition, and if the body of this statement executes, the player has been hit by a spider. Whether the game is over or not, we want the sound to play. Insert this line:

new PlayerHit().play();

The new keyword creates a new object. You've seen it so many times being assigned to a new variable, that you might have thought it must always be like that. However, we don't really have any reason to assign this new object to a variable, as once it plays we are finished and done with it. And you may use this format in all the other places around your code, after you strategically figure out where playing a sound is called for. Don't worry, I think you know your way around the code by now, if you made it this far.

Anyway, here are the sounds I added. Their class names should tell you exactly what they are for:

  1. StartGame
  2. FireBullet
  3. EnemyHit
  4. EnemyGotAway
  5. PlayerHit
  6. NewLife
  7. GameOver

I'll paste the code one more time so that you can see where these sounds are played:

import flash.events.KeyboardEvent;
import flash.events.Event;
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.media.Sound;

var rightArrow:Boolean;
var leftArrow:Boolean;
var spaceBar:Boolean;
var betweenLives:Boolean;
var playerHalfWidth:Number = player.width / 2;
var bulletArray:Array = new Array(bullet0, bullet1, bullet2, bullet3, bullet4, bullet5);
var spiderArray:Array = new Array(spider0, spider1, spider2);
var livesArray:Array = new Array(one, two, three, four);
var bulletIndex:int = -1;
var lives:int = 5;
var score:int = 0;
var spiderSpeed:Number = 3;

for(var i:int = 0; i < 3; i++){
	recycleEnemy(spiderArray[i]);
}

stage.addEventListener(KeyboardEvent.KEY_DOWN, stage_onKeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, stage_onKeyUp);
stage.addEventListener(Event.ENTER_FRAME, stage_onEnterFrame);
stage.focus = this;
//sound effect:
new StartGame().play();

function stage_onKeyDown(event:KeyboardEvent):void {
	if(event.keyCode == 39) {
		rightArrow = true;
	}
	if(event.keyCode == 37) {
		leftArrow = true;
	}
	if(event.keyCode == 32 && spaceBar == false) {
		//sound effect:
		new FireBullet().play();
		spaceBar = true;
		bulletIndex++;
		if(bulletIndex > 5) bulletIndex = 0;
		var bullet:Bullet = bulletArray[bulletIndex];
		bullet.x = player.x;
		bullet.y = player.y - 1;
	}
}
function stage_onKeyUp(event:KeyboardEvent):void {
	if(event.keyCode == 39) {
		rightArrow = false;
	}
	if(event.keyCode == 37) {
		leftArrow = false;
	}
	if(event.keyCode == 32) {
		spaceBar = false;
	}
}
function stage_onEnterFrame(event:Event):void {
	controlPlayer();
	moveBullets();
	moveEnemies();
	enemiesHitTest();
}
function controlPlayer():void {
	if(rightArrow == true) {
		player.x += 10;
		if(player.x > stage.stageWidth - playerHalfWidth) {
			player.x = stage.stageWidth - playerHalfWidth;
		}
	}
	if(leftArrow == true) {
		player.x -= 10;
		if(player.x < playerHalfWidth) {
			player.x = playerHalfWidth;
		}
	}
}
function moveBullets():void {
	//cycle through all six bullets in the bullet array
	//using a FOR LOOP:
	for(var i:int = 0; i < 6; i++) {
		//if the bullet is above the player, move it up 10 pixels every frame:
		if(bulletArray[i].y < player.y) {
			bulletArray[i].y -= 10;
			//if the bullet has gone off the top of the screen, 
			//put it back at the player's feet again:
			if(bulletArray[i].y < 0) {
				bulletArray[i].x = i * 70 + 100;
				bulletArray[i].y = 617;
			}
		}
	}
}
function moveEnemies():void {
	for(var i:int = 0; i < 3; i++) {
		spiderArray[i].y += spiderSpeed;
		if(spiderArray[i].y > (stage.stageHeight + 25)) {
			//spider got away... penalty sound effect:
			if(betweenLives == false) {
				updateScore(-5);
				new EnemyGotAway().play();
			}
			recycleEnemy(spiderArray[i]);
		}
	}
}
function enemiesHitTest():void {
	//for each of the three spiders
	for(var i:int = 0; i < 3; i++) {
		if(spiderArray[i].hitTestObject(player)) {
			//sound effect:
			new PlayerHit().play();
			lives--;
			if(lives > 0) {
				changePlayer();
				livesArray[lives - 1].visible = false;
			} else {
				gameOver();
				break;
			}
		}
		//the each of the six bullets
		for(var j:int = 0; j < 6; j++) {
			//don't consider bullets that aren't in play:
			if(bulletArray[j].y > player.y) continue;
			if(spiderArray[i].hitTestObject(bulletArray[j])) {
				//sound effect:
				new EnemyHit().play();
				updateScore(10);
				//make the spiders get faster:
				spiderSpeed = spiderSpeed * 1.01;
				recycleEnemy(spiderArray[i]);
				bulletArray[j].x = j * 70 + 100;
				bulletArray[j].y = 617;
			}
		}
	}
}
function recycleEnemy(enemy:MovieClip):void {
	enemy.x = 25 + Math.random() * (stage.stageWidth - 50);
	enemy.y = -500 * Math.random() - 25;
}
function changePlayer():void {
	betweenLives = true;
	player.x = stage.stageWidth + 100;
	stage.removeEventListener(KeyboardEvent.KEY_DOWN, stage_onKeyDown);
	stage.removeEventListener(KeyboardEvent.KEY_UP, stage_onKeyUp);
	rightArrow = false;
	leftArrow = false;
	//create a two second delay:
	var timer:Timer = new Timer(2000, 1);
	timer.addEventListener(TimerEvent.TIMER, afterDelay);
	timer.start();
}
function afterDelay(event:TimerEvent):void {
	//sound effect:
	new NewLife().play();
	
	betweenLives = false;
	player.x = stage.stageWidth / 2;
	for(var i:int = 0; i < 3; i++){
		if(spiderArray[i].y > 400) { 
			recycleEnemy(spiderArray[i]);
		}
	}
	stage.addEventListener(KeyboardEvent.KEY_DOWN, stage_onKeyDown);
	stage.addEventListener(KeyboardEvent.KEY_UP, stage_onKeyUp);
}
function gameOver():void {
	//sound effect:
	new GameOver().play();
	rightArrow = false;
	leftArrow = false;
	spaceBar = false;
	stage.removeEventListener(Event.ENTER_FRAME, stage_onEnterFrame);
	stage.removeEventListener(KeyboardEvent.KEY_DOWN, stage_onKeyDown);
	stage.removeEventListener(KeyboardEvent.KEY_UP, stage_onKeyUp);
	gotoAndStop(3);
}
function updateScore(amount:int):void {
	score += amount;
	if(score < 0) score = 0;
	score_txt.text = String(score);
}

(Note, there is some code on frames 1 and 3 also, but I haven't chosen to paste it here. It's very basic, just a couple of CLICK listeners. Download the fla file to see it. You won't have any trouble with it). 

Here is how the swf behaves now. You must admit that the sounds add a completely new dimension to it:

FAIR WARNING! This SWF plays SOUNDS!! Adjust your volume before clicking!

Alas, the "software" is never finished (imgagine ME writing "software")! But I feel like this tutorial is, at least for now. What I would like to add in the future, though, is a checkbox for turning the sounds on and off, and make them off by default, just for Internet politeness. But right now I must leave that for another day, and a follow up page.

Thank you for hanging in there with me, and I hope you enjoyed this! Thanks in advance for comments!

Jody Hall