AS3 Avoider Game Tutorial, Part 2: Multiple Enemies

by Michael James Williams on September 22, 2008 · 185 comments

in Avoider Game Base,Tutorial

(This tutorial is also available in Spanish, Polish, and Italian.)

Introduction

In this part of my AS3 conversion of Frozen Haddock‘s tutorial, I’ll show you how to add multiple enemies to your game. Check out what you’ll be working towards by clicking the image below.

screenshot

Setting Up

If you didn’t follow along with the first part of the tutorial, grab the zip file here and extract it to your hard drive, making sure it keeps the folder paths intact.

If you did follow the first part, I recommend making a backup of your existing game files by copying the main folder (I called mine AvoiderGame-MJW, remember) and naming the copy something like AvoiderGame-MJW-part1. This way, you can look back at the early game in the future and see how much you’ve progressed!

Either way, open the FLA file. Open the document class file (mine’s called AvoiderGame.as) and the Enemy.as file too, since we’re going to be editing them a lot.

Taking Control of the Enemy

Take another look at the Enemy’s constructor (it’s located in the Enemy.as file):

?View Code ACTIONSCRIPT3
6
7
8
9
10
		public function Enemy() 
		{
			x = 100;
			y = -15;
		}

This little bit of code means that every single instance of the Enemy class will start off at (100,-15). This will not make for a very interesting Avoider game. It’s also not going to be any use when we start making enemies that move upwards — if they start above the screen, they’ll never make it onto the playing field!

Change the constructor function like so:

?View Code ACTIONSCRIPT3
6
7
8
9
10
public function Enemy( startX:Number, startY:Number ) 
{
	x = startX;
	y = startY;
}

We’ve added parameters to the constructor function. Now when we create an instance of Enemy in the document class, we can pass x and y values to it to specify where it should appear.

Switch to your document class (that’s AvoiderGame.as) and change the code that creates a new enemy from:

?View Code ACTIONSCRIPT3
15
enemy = new Enemy();

to:

?View Code ACTIONSCRIPT3
15
enemy = new Enemy( 100, -15 );

If you run the game (Control > Test Movie, remember), you’ll see that the enemy starts at (100,-15) — which is exactly as we’d expect. We’ve passed the values 100 and -30 to the Enemy constructor, which has first set startX = 100 and startY = -15, and then set x = startX and y = startY. Of course you can change the numbers in Enemy(100,-15) to make it start out in different places. Try it out.

Irresponsible Cloning

How can we make more than one enemy appear? Let me show you an example of what not to do. It’s the simplest method: we literally copy and paste the enemy until we have as many as we need.

First, define a few more enemies as public vars in your document class (lines 10-12):

?View Code ACTIONSCRIPT3
7
8
9
10
11
12
13
14
public class AvoiderGame extends MovieClip 
{
	public var enemy:Enemy;
	public var eric:Enemy;
	public var ernie:Enemy;
	public var emily:Enemy;
	public var avatar:Avatar;
	public var gameTimer:Timer;

Next, set these up with different starting positions in the document class’s constructor, and add (using .addChild) them to the game (lines 20-25):

?View Code ACTIONSCRIPT3
16
17
18
19
20
21
22
23
24
25
public function AvoiderGame() 
{
	enemy = new Enemy( 100, -15 );
	addChild( enemy );
	eric = new Enemy( 160, -120 );
	addChild( eric );
	ernie = new Enemy( 205, -60 );
	addChild( ernie );
	emily = new Enemy( 317, -85 );
	addChild( emily );

Next, in your onTick function, get them all moving:

?View Code ACTIONSCRIPT3
37
38
39
40
41
42
public function onTick( timerEvent:TimerEvent ):void 
{
	enemy.moveDownABit();
	eric.moveDownABit();
	ernie.moveDownABit();
	emily.moveDownABit();

Finally, check each of them for a collision with the player:

?View Code ACTIONSCRIPT3
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
if ( avatar.hitTestObject( enemy ) ) 
{
	gameTimer.stop();
}			
if ( avatar.hitTestObject( eric ) ) 
{
	gameTimer.stop();
}			
if ( avatar.hitTestObject( ernie ) ) 
{
	gameTimer.stop();
}			
if ( avatar.hitTestObject( emily ) ) 
{
	gameTimer.stop();
}

Run the game. Sure, it works, but it’s a pretty very messy solution. Go ahead and undo all of that copying and pasting, it’s unnecessary.

Forming an Army

Copying and pasting enemies like that lets us refer to each one by a specific name. But… do we ever actually need to do that? Is there ever a situation where we need to tell just one enemy to act differently to the rest? Only when something happens to that enemy — when it hits the player, perhaps, or when it leaves the screen — but in those cases we single the enemy out by its situation, not by its name. I’ll show you what I mean in a bit.

What we’re going to do is create a group of enemies, and use the document class as a “general”, telling the group how to behave. I’m going to call this group army, for obvious reasons. We’ll use an Array as the structure for the group; this is basically an ordered list of objects.

First we need to define the new army, just as we did for the enemy. It’s going to have to be accessible for the duration of the game, so we’ll define it within the document class but outside the constructor (line 7):

?View Code ACTIONSCRIPT3
7
8
9
10
11
12
public class AvoiderGame extends MovieClip 
{
	public var army:Array;
	public var enemy:Enemy;
	public var avatar:Avatar;
	public var gameTimer:Timer;

Also, remove that line, public var enemy:Enemy; (line 10 above). Since the enemies are all going to be part of the army, and the army is a public var, we don’t need the enemies to be public vars any more.

Now, alter the game’s constructor like so:

?View Code ACTIONSCRIPT3
14
15
16
17
18
19
public function AvoiderGame() 
{
	army = new Array();
	var newEnemy = new Enemy( 100, -15 );
	army.push( newEnemy );
	addChild( newEnemy );

What have we done?

  • Line 16 — Set the army as a new instance of Array, just as we’ve done for the enemy.
  • Line 17 — So as not to get confused, I’ve renamed enemy to newEnemy, as it will now only be used for creating new enemies. Since there’s no var newEnemy statement (public or otherwise) anywhere, we need to stick var on the front here.
  • Line 18 — Added the new enemy to the army. (“Pushed” it onto the end of the list of enemies.)
  • Line 19 — added the new enemy to the game (all that’s changed here is that enemy has been renamed newEnemy).

Now we need to make the enemy move. Remember this is done in the onTick function. We’re going to need a for each…in loop, which is new to ActionScript 3.

Edit the onTick function so that:

?View Code ACTIONSCRIPT3
31
32
33
34
35
public function onTick( timerEvent:TimerEvent ):void 
{
	enemy.moveDownABit();
	avatar.x = mouseX;
	avatar.y = mouseY;

becomes:

?View Code ACTIONSCRIPT3
31
32
33
34
35
36
37
38
public function onTick( timerEvent:TimerEvent ):void 
{
	for each ( var enemy:Enemy in army ) 
	{
		enemy.moveDownABit();
	}
	avatar.x = mouseX;
	avatar.y = mouseY;

I think it’s actually quite clear what’s happening here. The for each…in loop goes through everything in the army’s list of items and tells it to move down a bit. The confusing part is that it looks like we are telling the loop only to look at items of type Enemy — but that’s not how it works. We are merely telling the loop that it should expect everything inside the army to be of type Enemy. We could have added the avatar to the army back in the constructor function — and then the game would have crashed because the Avatar class doesn’t contain a function called moveDownABit(). Anyway, don’t worry about this too much, it’ll become more intuitive as you use it more.

There’s one more change we need to make before we can run this: checking for collisions. We can just move the collision detection code to be inside the for each…in loop (lines 36-39):

?View Code ACTIONSCRIPT3
31
32
33
34
35
36
37
38
39
40
41
42
43
public function onTick( timerEvent:TimerEvent ):void 
{
	for each ( var enemy:Enemy in army ) 
	{
		enemy.moveDownABit();
		if ( avatar.hitTestObject( enemy ) ) 
		{
			gameTimer.stop();
		}
	}
	avatar.x = mouseX;
	avatar.y = mouseY;
}

Although, this means that we are checking for collisions before we’ve moved the avatar, i.e. we’re checking if the enemy is colliding with where the player used to be, which hardly seems fair. So, rearrange it a bit:

?View Code ACTIONSCRIPT3
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public function onTick( timerEvent:TimerEvent ):void 
{
	avatar.x = mouseX;
	avatar.y = mouseY;
 
	for each ( var enemy:Enemy in army ) 
	{
		enemy.moveDownABit();
		if ( avatar.hitTestObject( enemy ) ) 
		{
			gameTimer.stop();
		}
	}
}

Save it and run it, and you’ll see everything’s working out just as before. Now to add more enemies.

Adding to the Army

Try this:

?View Code ACTIONSCRIPT3
31
32
33
34
35
public function onTick( timerEvent:TimerEvent ):void 
{
	var newEnemy:Enemy = new Enemy( 100, -15 );
	army.push( newEnemy );
	addChild( newEnemy );

You should recognise lines 33-35. We’ve just put the code for creating a new enemy in the onTick, so that every tick it will create a new enemy. What do you expect will happen when we run it?

screenshot

Hm. It’s creating new enemies in the same place at such a fast rate that they’re overlapping. Let’s try to fix this by starting the new enemies off in all different places.

We’ll need the Math.random() function for this. Math.random() returns a random number between 0 and 1. My game is 400 pixels wide, so I’d like the enemies to start off with an x-coordinate of between 0 and 400. Therefore (lines 33-34):

?View Code ACTIONSCRIPT3
31
32
33
34
35
36
public function onTick( timerEvent:TimerEvent ):void 
{
	var randomX:Number = Math.random() * 400;
	var newEnemy:Enemy = new Enemy( randomX, -15 );
	army.push( newEnemy );
	addChild( newEnemy );

So now the enemies will be created at some random point above the screen. Save it and run it, and what do we get?

screenshot

Argh!

All right, so, maybe they’re still coming in at too fast a rate…

Less Enemies per Second, Please

Right now, the enemies are appearing at a rate of one new enemy per tick. Since a tick is 25ms, there are 40 ticks per second, and therefore 40 new enemies per second. I think if we reduced this to four new enemies per second, we’d be good. Since 4 is 1/10 of 40, we need to reduce the new-enemies-per-tick rate to 1/10.

We could do this by making a new enemy appear every ten ticks. I think it would be more fun if we said there was a 1/10 chance of a new enemy appearing on any given tick; this way, sometimes we’d have more than four enemies appearing per second, and sometimes we’d have less, but over time we’d average out at four/sec. The uncertainty involved makes the game a little more exciting, however (though perhaps “exciting” is a little bit of a misnomer at this early stage of the game’s development…).

How can we do this, then? Well, we know that Math.random() generates a random number between 0 and 1. Since these random numbers are evenly distributed, that means that there’s a 1/10 chance of the number generated being between 0 and… well, 1/10. I.e., the chance of Math.random() < 0.1 is 1/10.

So, let’s change our code to make use of this fact (lines 29 & 34):

?View Code ACTIONSCRIPT3
28
29
30
31
32
33
34
35
36
public function onTick( timerEvent:TimerEvent ):void 
{
	if ( Math.random() < 0.1 )
	{
		var randomX:Number = Math.random() * 400;
		var newEnemy:Enemy = new Enemy( randomX, -15 );
		army.push( newEnemy );
		addChild( newEnemy );
	}

(Note: each time you call Math.random() the number generated is different, so this new code isn’t interfering with our random positioning code.)

Save it and run it.

screenshot

Much better! Actually, I think this may now be too easy. Why not fiddle around with the if (Math.random() < 0.1) statement to see what works best for you?

Wrapping Up

That’s it for part two. You can download a zip file with everything I’ve been working on from here.

In the next part, we’ll add a Game Over screen so that finally the game will have an aim! It’s available here.

If you’d like to try expanding upon this part yourself, how about trying to make the starting enemy appear at a random location? I’m sure you can do that now. Also, the enemies sometimes appear partly off one side of the screen. Can you fix that?

{ 183 comments… read them below or add one }

ayumilove May 17, 2010 at 1:11 am

@vllmstl

just try that code , if it works, than its your software problem.
else check the code above it and see whether there are any syntax errors.

vllmstl May 17, 2010 at 2:00 pm

@ayumilove

Thanks for the help, will try it out now and let you know.

:) )

vllmstl May 17, 2010 at 2:07 pm

Hi Michael Williams,

I dont know, i am new to as3 and came across that code for the first time.
and it neither turned blue nor worked for me, Just the “for ‘each’ statement”
let me try to reinstall my flash cs3… may be that might help me.
Thanking you,
vllmstl

vllmstl May 17, 2010 at 2:10 pm

hi Michael Williams,

I forgot to thank you for the awesome tutorial.

hehehe :)

ayumilove May 17, 2010 at 3:49 pm

i tried on my adobe flash,
the “for” turns into blue when i typed “for each”
the each does not turn into blue.

Take note that the syntax coloring in this actionscript code within this blog is not necessarily colors the same in adobe flash.

ProfeaX May 24, 2010 at 6:19 pm

I’m getting error while changing enemy = newEnemy (); to enemy = new Enemy( 100, -15 );
1137: Incorrect number of arguments. Expected no more than 0.

ayumilove May 24, 2010 at 11:23 pm

@Profeax
The new Enemy instance that you are trying to create does not expect any arguments in its constructor

check your Enemy.as class
and you find that your contructor would be like this

public function Enemy ()
{
}

As you can see, the constructor expects zero/none arguments within the round brackets ()

1 solution

To solve this problem, when creating a new instance, do not input the Enemy coordinates 100,-15

2 solution

Have your constructor to take in 2 arguments
public function Enemy (posX : Number, posY : Number)
{
this.x= posX ;
this.x= posY
}

ayumilove May 24, 2010 at 11:25 pm

correction ….

public class Enemy extends Sprite {
public function Enemy (positionX : Number, positionY : Number)
{
x= positionX ;
y= positionY ;
}
}

Michael Williams May 29, 2010 at 12:15 am

@vllmstl: Oh! Ayumilove is right, each is not supposed to turn blue. Silly me.

@Profeax: As usual, ayumilove’s hit the nail on the head :) Check the second code box in “Taking Control of the Enemy”.

ayumilove May 29, 2010 at 12:38 am

Is there any edit button where i can edit my comment if I had made a mistake?

Michael Williams May 29, 2010 at 12:46 am

There used to be… I wonder where it went. Seems it’s still set up to do that; I guess the plugin isn’t compatible with my blog software any more :/
With a bit of luck it’ll be fixed automatically at some point.

Samir Uddin June 5, 2010 at 1:33 pm

thx dude this really helped me out a lot. Although sumtimes after ive written the code and test it it brings back various errors witch i cant seem to solve. BUT, when i rewrite the code out EXACTLY THE SAME as it was before the errors dissapear! WIERD! lol

Michael Williams June 12, 2010 at 1:54 pm

Cheers, Samir :) Haha, yeah, that seems to happen a lot. Mysterious.

ayumilove June 13, 2010 at 1:03 am

@Samir Uddin

To learn from mistake, you need to backup a copy of the class that has the problem, and compare with that class to the rewritten class. From there, you know exactly what causes the error and you can avoid them in the future. If you were to make a game, and this thing happens again, where would you copy the code from? There won’t be any code lying out there for you to copy/rewrite.

Xadjim June 15, 2010 at 6:13 am

Wow man nice tutorial…. i tried to play a little bit with the math.random function and i build in a difficulty with this:

        difficulty+=0.00001
        if (Math.random()<difficulty)
        {
                     blablabla
                    }

the only thing i still dont realy get is the “gameTimer.addEventListener(TimerEvent.TIMER, onTick);” stuff

Dean June 19, 2010 at 6:41 pm

I have received the following error:
TypeError: Error #1034: Type Coercion failed: cannot convert 100 to Enemy.
at AvoiderGame/onTick()
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()

The code for the affected is below:

public function onTick( timerEvent:TimerEvent ):void 
        {
            avatar.x = mouseX;
            avatar.y = mouseY;

        for each ( var enemy:Enemy in army ) 
        {
            enemy.moveDownABit();
            if ( avatar.hitTestObject( enemy ) ) 
            {
            gameTimer.stop();
            }
        }

The error seems to be occuring after the ‘for each…in’ and before the ‘enemy.moveDownABit()’ line of code.
Any help will be greatly appreciated.
I am using Flash Pro CS4.

Michael Williams June 22, 2010 at 3:17 pm

@Xadjim: Cheers :) Nice — what do you put in the blablabla bit?

@Dean: Odd error. Looks like your army array contains the number 100.

Before that “for each”, call:

trace( army.toString() );

That’ll let you see if there’s anything unusual in there. If there is, check your code to see if you can figure out where it’s being added.

Callum June 26, 2010 at 11:56 am

HI there, excellent tutorial!

I am having a problem with Math.random. I am trying to reduce the number of enemies, but no matter what value I enter to replace your <0.1, the game still works but the number of enemies never changes.

ayumilove June 27, 2010 at 3:53 am

@Callum

If you would like to reduce the number of enemies that can appear on the screen at any point of time, you should do an if-else statements on the array length that stores those enemies!

A sample code :
[code]
if ( Math.random() < 0.1 && army.length < 10) { /* spawn enemy */ }
[/code]

ayumilove June 27, 2010 at 3:56 am

You can set a constant value of 10 (as shown below) to limit the enemies that can be on screen.

if ( Math.random() < 0.1 && army.length < 10) { /* spawn enemy */ }

The previous method that you used, (changing the value of 0.1 in Math.random)
simply increases/decreases the probability of the enemy spawn. The bigger the number (closing in to 1) has higher chance to spawn an enemy compare to the lower number (closing in to zero)

Jake June 29, 2010 at 2:59 am

Okay, I can get everything working until the end. Whenever I do

if ( Math.random() < 0.1 )

part I get tons of lag. If I bring it to say, 10, it doesn’t at all. The time that they’re going down doesn’t change at all, it seems to basiclly only change lag or no lag. Here’s my code…

package
{
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;

public class AvoiderGame extends MovieClip
{
    public var army:Array
    public var avatar:Avatar;
    public var gameTimer:Timer;
    public function AvoiderGame()
    {
        army = new Array();
        var newEnemy = new Enemy(100, -15);
        army.push( newEnemy );
        addChild( newEnemy );
        avatar = new Avatar();
        addChild( avatar );
        avatar.x = mouseX;
        avatar.y = mouseY;
        gameTimer = new Timer( 25 );
        gameTimer.addEventListener( TimerEvent.TIMER, onTick );
        gameTimer.start();
    }

public function onTick( timerEvent:TimerEvent ):void    

{ if (Math.random() < 0.1 )
{
var randomX:Number = Math.random() * 600;
var newEnemy:Enemy = new Enemy( randomX, -15 );
army.push( newEnemy );
addChild( newEnemy );
for each ( var enemy:Enemy in army )

    {
    enemy.moveDownABit();
    if ( avatar.hitTestObject( enemy ) ) 
    { gameTimer.stop();

    }

}

avatar.x = mouseX;
avatar.y = mouseY
}

}

}
}

any help would be appreciated, thanks!

Jake

ayumilove June 29, 2010 at 5:23 am

@Jake
sorry, I don’t understand what’s your question about, so I can’t really help you.
Probability of enemy spawning is only from the range of zero to one. Not ten (10).

I don’t see any errors in your code, should be fine.

Jake June 29, 2010 at 10:22 pm

@ayumilove
When I put it at 0.1 or less, it lags a ton. The higher the number it is, the less the lag is, but the enemies per second is the same. Know what’s up?

Thanks!

ayumilove June 30, 2010 at 12:51 am

Don’t know, send me your .fla to my email so I could check it out :)
email : ayumiyoutube(at)gmail(d0t)com

Michael Williams July 5, 2010 at 7:48 pm

@Callum: Not sure what you mean… did ayumilove’s comment about army.length help?

@Jake: That is weird :S Higher number should cause higher lag… maybe your curly braces are in the wrong place? If ayumilove’s generous offer of help doesn’t solve it, post again :)

ayumilove July 6, 2010 at 3:15 am

I did not receive his .fla and .as files
So I think he has a way to manage that problem ;)

Michael Williams July 7, 2010 at 6:55 pm

Let’s hope so :)

PlayHermit August 1, 2010 at 8:04 pm

I hope you’re still reading these comments MJW. I tried to get the little end activity and I figured out how to get the starting enemy to appear at random places, but I could never figure out how to keep them from only spawning within the box and not appear off the screen.

I thought just modifying the x value would do the trick but I guess theres more to it, right?

var randomX:Number = Math.random() * 370;
var newEnemy:Enemy = new Enemy( randomX, -15 );

As you can see, I attempted to fix the problem by lowering the the number in the first line from 400 to 370 but they’re still popping up a little off the screen. =(

Michael Williams August 21, 2010 at 12:27 am

Hey PlayHermit. I’m reading them, just a little behind on them — sorry!

Think about it this way: since the lowest value that Math.random() can be is 0, the lowest value that absoluteX can be using your code above is (0 * 370) = 0. But you need the lowest value to be, what, 15? 25? (I don’t know the width of your avatar.)

Hope that hint helps :)

kamal98 September 27, 2010 at 11:19 pm

WOW this should use full.

Marco Roberto October 20, 2010 at 5:49 pm

Hey Michael, great tutorial you got going on here.

Im interested in learning more about actionscript (after all, im studying to become a programmer), but on thing here makes me a bit confused.

I remember an older tutorial I saw that used a function to something like “getNextHighestDepth” or something like that (I could be wrong about this though), to make unique instances of the enemies on screen. Sont they all have to have diferent instances name? Im a bit confused because, when I see your “army” code to make new instances, dont they all have the same name?

Im sorry if its a stupid question, but im new to this.

Also, thanks for your time to write this tutorial, it means a lot for someone like me just getting started.

Marco Roberto

rigorlicious October 26, 2010 at 7:28 pm

Not sure if anyone is still checking this, I’ve been having the same problem as Profeax and I’ve made the changes in my files, but I still seem to be getting that expected argument 0 error. My file is a little bit different based on how I want the game to play but is pretty much the same. My code is as follows:

Main File:


package
{
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.*;
import flashx.textLayout.formats.BackgroundColor;

    public class SpaceGame extends MovieClip
    {
        public var shower:Array;
        public var ship:Ship;
        public var meteor = Meteor;
        public var gameTimer:Timer;
        public var up:uint = 38;
        public var down:uint = 40;

    public function SpaceGame()
    {
        shower = new Array();
        var newMeteor = new Meteor( 750 , 250 );
        shower.push( newMeteor );
        addChild( newMeteor );

        ship = new Ship();
        addChild( ship );
        ship.x=50;
        ship.y=250;

        gameTimer = new Timer(25);
        gameTimer.addEventListener(TimerEvent.TIMER, moveMeteor);
        gameTimer.start();
        stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownListener);  
    }

    function keyDownListener(e:KeyboardEvent) {
        if (e.keyCode==up){
            ship.y-=10;
        }

        if (e.keyCode==down){
            ship.y+=10;
        }
    }   


    public function moveMeteor(timerEvent:TimerEvent):void{

        if ( Math.random() &lt; 0.1 )
    {
        var randomY:Number = Math.random() * 400;
        var newMeteor:Meteor = new Meteor( 750, randomY );
        shower.push( newMeteor );
        addChild( newMeteor );
    }

    for each ( var meteor:Meteor in shower ) 
    {
        meteor.moveAcross();
        if ( ship.hitTestObject( meteor ) ) 
        {
            gameTimer.stop();
        }
        }
    }

}

}

and the Meteor file:


package
{
import flash.display.MovieClip;
public class Meteor extends MovieClip
{

    public function Enemy ( positionX:Number, positionY:Number )
    {
        x= positionX ;
        y= positionY ;
    }

public function moveAcross():void
{

    x= x-5;
}

}

}

Any help would really be appriciated.

Juan December 10, 2010 at 5:29 pm

rigorlicious: your problem is in Meteor class, you renamed it to meteor but the constructor inside the class is named Enemy.
so change:
public function Enemy ( positionX:Number, positionY:Number )
for
public function Meteor ( positionX:Number, positionY:Number )
and it should work

Andrew December 19, 2010 at 3:22 am

So far so good – Learning lots!!!

Not being picky but line 17 in the 11th example:

 var newEnemy = new Enemy(100, -15);

Should read

 var newEnemy:Enemy = new Enemy(100, -15);

Otherwise I get compile error for not declairing. (Using FD3)

Alexander Brown December 27, 2010 at 3:42 pm

What i am trying to achieve is when a person click on a star all the enemy change colour.

The code below displays the stars on the workarea

for (var i=1;i<11;i++){
                  var newstar:Star = new Star();
                  newstar.x = 80 * i;
                  newstar.y = 80 * i;
                  newstar.scaleX = 0.5;
                  newstar.scaleY = 0.5;

            power.push(newstar);
            addChild(newstar);
             newstar.stop();
           }

The next part shows the code that i am using to change the colour of all the enmies

for each (var star:Star in power)
            {
                if (avatar.hitTestObject(star))
                {
                //trace("hello star");
                //army.push( newEnemy );
               // addChild( newEnemy );
                newEnemy.gotoAndStop(2);

            // change the colour of all the enemy to blue
            // the next step is to make it so when you have discovered 
            }

    }

This is the error i recieve when i run the code
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at AvoiderGame/timerGeneration()
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()
Please could you lend assistance
from alex

Ntr0pi January 10, 2011 at 11:31 am

A quick note, althou I’m sure you know this already. hitTestObject works within the confines of the whole square of the image. So there are some errors in the visual at this point being that the game will stop before you’ve actually collided, (ie since it hits the box frame of the area)

Not trying to correct your or anything. I just remembered this from a class I had a while back and thought to post it. Excellent tutorial at this point and i will be heading to the next step after a 20 min break :)

Dethstix February 21, 2011 at 10:17 pm

I’m not sure if this is a problem since the game is simple but after you play for a while, would it turn into a problem that the computer has to coordinate the smiley faces that fall off the bottom of the screen? Would it be more efficient to remove them once they are off the screen?
I’ve tried using the following code to no avail.

for each ( var enemy:Enemy in army ) 
    {
        if ( enemy.y > 300 )
                {
                           removeChild( enemy );
                 }
    }

This causes no more smileys to fall once the first one reaches a y-value of greater than 300. Is there a way to remove just the smileys that fall off the screen?

Dethstix February 22, 2011 at 8:16 pm

I made may previous comment before reading the Garbage Collection section of the tutorial. oops.

numbus March 16, 2011 at 2:01 am

It’s not that it’s too easy, in fact it’s very hard with the collision thing because it detects it from so far away =/

Chris April 4, 2011 at 9:58 pm

Hi

I have a 800 x 480 size stage. im having a problem with the stage, the enemies are only falling down on the left half of the stage. What do i need to change for the enemies to occupy the whole stage.

Regards
Chris

James April 12, 2011 at 5:46 pm

Just wanted to say thanks for the tutorial. I’m finally taking the plunge and trying to learn how to use flash and this is perfect :D

I just wanted to point out that when you changed the variable from enemy to newEnemy, you didn’t mention in the tutorial to change the other variables that are mentioned in the script. I tried to run it and it didn’t work. Maybe others who aren’t programmers will not notice this and get stuck. Hope that helps :)

Thanks again!

James April 12, 2011 at 5:49 pm

In response to Chris:

You have changed the width of your stage, which is fine, but you have to think about the code you are making. The code (for the X position) uses a Math.random() * 400. This means that the minimum output is 0 and the maximum output is 400. If your stage is 800 pixels wide, what would you have to do?

If you don’t know what I mean, change the line of code from:

var randomX:Number = Math.random() * 400;</pre

to

var randomX:Number = Math.random() * 800;

or whatever width you want :) if they are appearing wider than the stage, you won't see them though.

Hope that helps.

Andy April 16, 2011 at 9:26 pm

Hi, great tutorial!
I just got a little question:
When you put:

public function onTick( timerEvent:TimerEvent ):void 
{
    for each ( var enemy:Enemy in army ) 
    {
        enemy.moveDownABit();
    }
    avatar.x = mouseX;
    avatar.y = mouseY;

You actually define the variable enemy on that parenthesis? Or is it defined before?

Thanks!

Mr. Mr. April 20, 2011 at 5:16 am

Good stuff. Thanks.

Jos June 14, 2011 at 8:49 am

Fantastic tutorials. I had managed to cobble together a few different simple as3 tut’s but never really acquired the knowledge to make them function together. Your in depth descriptions of not only what to put where but WHY are invaluable to as3 newbs like myself. My newfound power in as3 has the creative juices flowin!

Thanks.

Michael James Williams June 14, 2011 at 8:54 am

Thanks so much, Jos! It’s wonderful to hear that :D

ElectronicDude June 18, 2011 at 6:18 pm

Hi, thank you for the tutorial!

I succesfully followed the Avoider game tutorial, but now I have some little doubts.

In that game, you only have some enemies and the player, and so the update method loops through them.

But what if my enemies could shoot bullets? How can I update them in the main update method? And how can i reference the player to check collision with it?

In a few words, I would like to know how to efficiently handle references through the game…

Thank you in advance!

Seb July 26, 2011 at 1:37 pm

Hi,

Firstly thank you for the tutorials, they’ve so far been very helpful.

The only thing so far I don’t understand so far is in the ‘forming an army’ section, where you change the name of instances of Enemy to newEnemy, but then you still refer to it as ‘enemy’ in your ‘for each…in’ code and it still works. I’ve checked and it also works if you refer to it as ‘newEnemy’, which makes sense to me, but I was wondering why it still works if you put ‘enemy’. Anyone know?

thomar August 9, 2011 at 10:50 am

I keep getting this error and I have no idea why

C:\Users\Jesse\Documents\AvoiderGame-JRv1.1\Classes\AvoiderGame.as, Line 18 1120: Access of undefined property enemy.

this is what I have there

army = new Array();
var newEnemy = new Enemy( 100, -15 );
army.push( newEnemy );
addChild(enemy);

any help would be greatly appreciated

BM August 20, 2011 at 7:13 pm

Hi!
Thank you for the tutorials, they are awesome.
I have a question though: I`m using FlashDevelop to create my first game and for some reason it always freezes when the enemy touches the wall and sometimes it displays this error message:The supplied DisplayObject must be a child of the caller.
I have an enemy class which contains a textbox (the player has to type the word to kill it). Here is my code (related to the enemy):

public function onTick(timerEvent:TimerEvent):void
        {
            if (Math.random() < 0.0125)
            {
            var newEnemy = new Enemy(0,50);
            army.push(newEnemy);
            addChild(newEnemy);
            }
            for each (var enemy:Enemy in army)
            {
                moveEnemy();
                if (wall.hitTestObject(enemy))
                {
                    wallHealth = wallHealth - 1;
                    army.pop();
                    removeChild(enemy);
                }
                if (wallHealth == 0)
                {
                    gameTimer.stop();
                    dispatchEvent( new AvatarEvent(AvatarEvent.DEAD));
                }
                if (wallHealth == 2)
                {
                    removeChild(life3);
                }
                if (wallHealth == 1)
                {
                    removeChild(life2);
                }

        }

}
public function moveEnemy():void
{
    for each(var enemy:Enemy in army)
    {
        enemy.x = enemy.x + enemySpeed;
    }
}&lt;/pre&gt;

and the enemy class:

package
{
    import flash.display.Sprite;
    import flash.text.TextField;

/**
 * ...
 * @author ToMiKi
 */
public class Enemy extends Sprite 
{
    public var enemyLine:Number;
    public var enemyText:TextField;
    public function Enemy(startX:Number,startY:Number) 
    {
        x = startX;
        y = startY;
        enemyText = new TextField();
        enemyText.text = String("blablabla");// I will make words appear here later
        enemyText.x = startX;
        enemyText.y = startY;
        addChild(enemyText);
    }

}

}

Leave a Comment

Writing code? Write <pre> at the start and </pre> at the end to keep it looking neat.

Anti-Spam Protection by WP-SpamFree

{ 2 trackbacks }

Previous post:

Next post: