Right now, our hero character is having too much fun just shooting bullets aimlessly. The game will also be boring without some elements of challenge, and danger. So let's introduce some enemies!
There is a Spider MovieClip in the library that we will use to make enemy instances. Similar to the bullets, let's just drag a few instances of these spiders to the stage. Place them anywhere you like, because the code we'll write will give them new locations anyway. Give them instance names (using the properties panel) of spider0, spider1, and spider2. Of course, you may have already guessed that our code is going to associate them as a group using an array. Therefore, add this line to the code:
var spiderArray:Array = new Array[spider0, spider1, spider2];
Having these spiders in an array is going to allow us to easily process them using a for loop. Where do you place this new line of code? Insert a line right after the line that declared the bulletArray and place it there. In my tutorials I will often give you new lines of code to insert, but when the code gets long, I must wait till the end of the page to show the whole thing so far. At that point, your code should at least somewhat resemble mine. If you get a thing or two in a slightly different order (the order functions appear usually isn't critical), as long as it works, that's okay.
What's important at this point is to have a general idea of how these enemies are going to move, and to have a vision of how we're going to accomplish it. For example, I envision that the spiders are going to come down from above the top of the screen, and their y value is going to increase by a few pixels each frame, and when they finally get past the bottom of the screen, they should start at the top again. So I am picturing in my mind the area just above the screen. Suppose I consider an area the same width as the screen, and perhaps 500 pixels or so high? Wouldn't it be cool to have a function that could place a given spider in a random x and y location within this area, just before it begins its descent?
That's exactly what we'll do. We'll call the function recycleEnemy. We'll make the function accept one parameter, which will be a reference to whatever spider we want to act upon. We'll give this parameter a type of MovieClip. In other words, we will create a general purpose function that recycles a spider to the top of the screen! All we have to do is call this function, sending it a reference to whichever spider we want it to act upon.
The fact that we will give each spider a random location in this unseen area above the screen means that the spiders will appear fairly unpredictably, even though they will all fall at the same rate of speed. I am going to show you how to do what I have envisioned, but I want to also add that this is an area where you can really get creative if you want to. For example, if you'd like your enemies to fall at random speeds, you can do that. If you'd like your enemies to zig and zag as they fall (by manipulating their x location somehow), you can do that too! I encourage you to experiment with this later on, because that will make an even more interesting and challenging game. But for now, let's just continue on with my own simpler, more modest vision.
Now let's consider how we'll place the enemy at a random location in this field above the screen. First let's consider the x direction (random horizontal placement). I've prepared a series of illustrations to help you picture this:
It should be clear from the above illustrations how the random x location is determined. By providing a left and right margin like this, and considering that the symbol for the enemies is also centered on its registration point, we can thus make sure that enemies can never appear in an awkward position along the left or right hand edge that would make them impossible for the player to shoot.
Next, let's consider the y direction (random vertical placement). I've likewise prepared a series of illustrations for this also:
By allowing for a margin of half the enemy's height (they're centered on their registration point in that direction, too), we make sure that enemies always appear at least slightly above the top of the screen, out of view, before they begin their descent into the visible area. Note that the use of a 500 pixel range for the negative y values was purely arbitrary, and has no special significance whatsoever. It just seemed like a good amount of variance to me, but feel free to change it if you want to.
Now that we've worked out the formulas for both the x and y directions, we can put these into a function that we can call at will:
function recycleEnemy(enemy:MovieClip):void {
enemy.x = 25 + Math.random() * (stage.stageWidth - 50);
enemy.y = -500 * Math.random() - 25;
}
This function will come in mighty handy, as there are several situations where we'll want to recycle the enemies. First, we'll want to start off the program with all the enemies at random locations above the screen, so we'll use this function on all of them right away (using a for loop, of course!). Secondly, if an enemy makes it past the bottom of the screen without the player shooting it, we'll want to recycle it. Thirdly, if an enemy gets shot by one of the player's bullets, we'll want to recycle it. And finally, if an enemy collides with the player, we'll want to recycle it (and the player as well, but we'll get to that later).
The for loop that does this at the beginning of the program goes like this:
for(var i:int = 0; i < 3; i++){
recycleEnemy(spiderArray[i]);
}
You can place this code near the top of all the other code, but right after the variable declarations. Since it's not in a function, it will run right away. From our study of for loops on the previous page, you should now have a clear idea of what this little piece of code does, but I'll explain it anyway. The loop runs three times. The first time through the loop, when i = 0, spiderArray[0] gets recycled. The next time through the loop, when i = 1, spiderArray[1] gets recycled. The third time through the loop, when i = 2, spiderArray[2] gets recycled. Finally, the loop counter goes to 3, the comparison test fails, and the loop ends with all three spiders having been recycled to the top of the screen at random locations.
Having placed the enemies at random locations at the top of the screen, now let's write a function that will continually move them down the screen. Remember, continuous action needs a continuous event, so this function will be the next one in the list that gets called by the enter frame handler, and we'll call it moveEnemies. This function will cycle through the enemies (using yet another for loop, of course!), and increment their y value by three pixels. It will test each one to see if it has gone off the bottom of the screen, and if so, will recycle it back to the top of the screen:
function moveEnemies():void {
for(var i:int = 0; i < 3; i++) {
spiderArray[i].y += 3;
if(spiderArray[i].y > (stage.stageHeight + 25)) {
recycleEnemy(spiderArray[i]);
}
}
}
Next, add a call to this new moveEnemies function to our enter frame handler:
function stage_onEnterFrame(event:Event):void {
controlPlayer();
moveBullets();
moveEnemies();
}You can now press CTRL-ENTER to test the movie. Just like the list in the enter frame handler indicates, you can now control the player, the bullets you shoot will move, and the enemies will come down from the top of the screen and get recycled again when they reach the bottom. Here's the final code:
import flash.events.KeyboardEvent;
import flash.events.Event;
import flash.display.MovieClip;
var rightArrow:Boolean;
var leftArrow:Boolean;
var spaceBar: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 bulletIndex:int = -1;
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);
function stage_onKeyDown(event:KeyboardEvent):void {
if(event.keyCode == 39) {
rightArrow = true;
}
if(event.keyCode == 37) {
leftArrow = true;
}
if(event.keyCode == 32 && spaceBar == false) {
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();
}
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 = 595;
}
}
}
}
function moveEnemies():void {
for(var i:int = 0; i < 3; i++) {
spiderArray[i].y += 3;
if(spiderArray[i].y > (stage.stageHeight + 25)) {
recycleEnemy(spiderArray[i]);
}
}
}
function recycleEnemy(enemy:MovieClip):void {
enemy.x = 25 + Math.random() * (stage.stageWidth - 50);
enemy.y = -500 * Math.random() - 25;
}
And here's how the swf now behaves:
(Once again, you must click on the swf to activate the keyboard controls). Notice that we can move left and right, shoot bullets, and the enemies come after us. But our bullets don't "harm" the enemies, nor do the enemies "harm" us. Well, of course not--we haven't programmed that part yet! Taking it one step at a time, on the next page we will see how to use collision detection to handle interactions between the enemies and the bullets.