Main Content
Avoider (Part 4)
A copy of the full source code is available. The code for the extra, enemy class is here, don't forget that either.
Welcome to part four of this Foundation Flash free tutorial, about the making of an Avoider type game, the second in a series of Foundation Flash classic game remakes. The game we shall be making is shown below. You are the black circle, try and get the blue squares but avoider the white, 'enemy' circles.
Now, unfortunately, is the moment when we must focus on the hardest part of this games, in my view. Th part to which I am referring is the enemies themselves. Although they have simple movement, it will be a steep learning curve for anyone following (only) these tutorials. That's why I've broken it down for you, into a few little subheadings.
Why is it going to be so difficult?
It is going to be just a bit tricky because for the first time we shall have to introduce a second external class (.as file), import it and use it.
Why?
Here goes: each enemy has a direction - either horizontal, or vertical. Within these it either goes left or right. Now imagine you're a computer and you pick an enemy at random. How are you going to know whether to move it right or left or up or down? Okay, you could set a complicated set of event listeners which switched between one another, but there's a (comparitively) easy way: use a class for the enemy, which hold whether it's a horizontal enemy (from now one: H-Enemy) or vertical one (V-Enemy)
First things first: how do we create the enemy and draw it?
Ah, just like we did with the target and the player. Create a new function-call within the constructor (avoider()) function and call it drawNewEnemy(). NOTE: make sure the function calls are in this order: player, target, enemy! Then it's basically a cut and paste job from the target, information about which you can find if you look at the previous tutorial:
public function drawNewEnemy() { var posX:uint = randRange(50,500); var posY:uint = randRange(50,350); var anenemy:Enemy = new Enemy; anenemy.graphics.beginFill(0xFFFFFF); anenemy.graphics.lineStyle(2,0x000000); anenemy.graphics.drawCircle(10, 10, 10); anenemy.x = posX; anenemy.y = posY; anenemy.graphics.endFill(); addChild(anenemy); anenemy.addEventListener(Event.ENTER_FRAME,touchPlayer); }
Note that instead of creating a new MovieClip, we're creating a new Enemy, we'll be coming to that later so don't worry. Apart from that though, it's quite seem - it will draw the circle in for us, with a black line line, thickness 2, but with white in the middle. It adds it to the display list and then gives it (i.e. every enemy) the touchPlayer enter frame handler.
I think actually.. yes, we'll do the touchPlayer function in a minute. First though, we need to create that extra class.
What information are we going to hold in our extra class?
Well, the thing we have to hold in the current direction of movement, which we'll call "mydirection". We'll also keep a backup variable for disabling the enemy quickly, which will be "hastouched". For more information about variables, see this tutorial. For now though, create a new .as file and save it as Enemy.as (with a capital E, as all classes should begin with a capital). That should tell you that we're calling our class 'Enemy', if you couldn't remember from earlier. Here is all the code you need to put in that:
package{ import flash.display.MovieClip; public class Enemy extends MovieClip{ public var mydirection:uint = 0;//0 = down/right, 1 = up/left public var hastouched:Boolean = false; } }
See how it extends MovieClip? That means it will be like a MovieClip, just with our variables as extra - this is how we managed to use the .graphics.beginFill() function earlier - it had borrowed the function from the MovieClip class.. It's really not too hard to understand if you can get your head round it - someone defined the MovieClip class in just the same way.
touchPlayer()
The touch player function we will use for handling when an enemy touches the player -> get rid of enemies and target, redraw the target, redraw one enemy, wipe out our score, update the score textbox. For getting rid of the enemies, we will use a for loop and the removeChildAt function, which removes from the display list the child at a specified index, which is its only argument. More about that in a previous tutorial. Well, here it is:private function touchPlayer(e:Event) { if (e.target.hitTestObject(player) && !e.target.hastouched) { e.target.hastouched = true; for (var i = (numChildren - 1); i > 5; i--) { getChildAt(i).removeEventListener(Event.ENTER_FRAME,touchPlayer); removeChildAt(i); } e.target.removeEventListener(Event.ENTER_FRAME,touchPlayer); score = 0; scoretext.text = "Score: 0"; drawNewTarget(); drawNewEnemy(); } }
Yeah, so we do all of that stuff which I listed above. Good, eh?
Moving the enemy around
We're one the home stretch now - all we have left to do is attach the event listeners for move left and right, utilising the mydirection variable we created earlier. We're going to do this right after the enemy is created, while we can de facto affect all enemies. Go back to the drawNewEnemy() function then, and add, to the end:
if (randRange(0,100) > 50) { anenemy.addEventListener(Event.ENTER_FRAME,moveVertical); } else { anenemy.addEventListener(Event.ENTER_FRAME,moveHorizontal); }
In effect we use the randRange function to flip a coin. The only reason I have used 100 and not 10, say, is because the larger the number used, the less effect the slight inaccuracies of 'random' numbers have. We've introduced two functions, moveVertical and moveHorizontal - for V-Enemies and H-Enemies respectively. These are, again, self explanatory - just see the if tutorial and the Hit-Testing tutorial. And here it is:
private function moveVertical(e:Event) { if (e.target.mydirection == 0) { e.target.y += 4; } else if (e.target.mydirection == 1) { e.target.y -=4; } if (e.target.hitTestObject(wallbottom)) { e.target.mydirection = 1; } if (e.target.hitTestObject(walltop)) { e.target.mydirection = 0; } } private function moveHorizontal(e:Event) { if (e.target.mydirection == 0) { e.target.x += 4; } else if (e.target.mydirection == 1) { e.target.x -=4; } if (e.target.hitTestObject(wallright)) { e.target.mydirection = 1; } if (e.target.hitTestObject(wallleft)) { e.target.mydirection = 0; } }
Done
And, thankfully, that's it. I mean, that's it. Done. Finished. Finito. Whatever will I write a tutorial about next week? If you now compile your game (CTRL/Command + Enter) you should see that it all works. Yay! If not, use the 'contact' page to drop us a quick message, or use the chat box to the right of all pages. Please join me soon for another free Foundation Flash tutorial.
Harry.