I’m getting a bit tired of running away from these enemies without having any means of defending myself.
Let’s blast them.
This tutorial is based on my avoider game tutorial. If you followed that, you’ll be able to add these new bullets to your existing game easily. If not, don’t worry about it — just download the base zip file; it contains all the files I’m going to be using.
Space Invaders Shooting
Let’s start with the simplest style of shooting: press space to fire a bullet upwards.
We might as well start by drawing the bullet. Open the FLA and create a new symbol of type Movie Clip (I’m sure you know the drill by now). Call it Bullet and export it for ActionScript with the same class name.
I’ve drawn this very simple shape for mine:

This is zoomed in, of course! A rectangle would look fine.
Time for some code. Open AvoiderGame.as. The first thing we’re going to do is get it recognising the space bar.
Listening for the Space Bar
Remember, there are four places we need to change to allow the space bar to be recognised.
First, we need to define a new Boolean at the class level:
22 23 24 25 26 | public var downKeyIsBeingPressed:Boolean; public var upKeyIsBeingPressed:Boolean; public var leftKeyIsBeingPressed:Boolean; public var rightKeyIsBeingPressed:Boolean; public var spaceBarIsBeingPressed:Boolean; |
Next, we have to set that Boolean to false in the constructor:
43 44 45 46 47 | downKeyIsBeingPressed = false; upKeyIsBeingPressed = false; leftKeyIsBeingPressed = false; rightKeyIsBeingPressed = false; spaceBarIsBeingPressed = false; |
Finally, we have to set that boolean to either true or false in the onKeyPress() and onKeyRelease() functions. Here’s onKeyPress():
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | public function onKeyPress( keyboardEvent:KeyboardEvent ):void { if ( keyboardEvent.keyCode == Keyboard.DOWN ) { downKeyIsBeingPressed = true; } else if ( keyboardEvent.keyCode == Keyboard.UP ) { upKeyIsBeingPressed = true; } else if ( keyboardEvent.keyCode == Keyboard.LEFT ) { leftKeyIsBeingPressed = true; } else if ( keyboardEvent.keyCode == Keyboard.RIGHT ) { rightKeyIsBeingPressed = true; } else if ( keyboardEvent.keyCode == Keyboard.SPACE ) { spaceBarIsBeingPressed = true; } } |
I’ll leave you to figure out the code for onKeyRelease().
OK, now we can detect the space bar, it’s time to make it do something. First, we can just make it create a new bullet. Move to the point in the onTick() function, after the avatar gets moved but before any collision detection takes place, and add these lines:
166 167 168 169 170 171 172 | if ( spaceBarIsBeingPressed ) { var newBullet = new Bullet(); newBullet.x = avatar.x; newBullet.y = avatar.y; addChild( newBullet ); } |
Well… it’s a start. If you hold down space, you can draw pictures. Er, let’s get those bullets moving.
Getting the Bullets Moving
We might as well copy the way the enemies move for this. Remember how that works?
- All enemies are placed in an array,
army - Every tick, we loop through that array and call
moveABit()on each enemy moveABit()changes the enemy’s position slightly (in my code, it just increases y)
So first we need a bullets array. Add public var bullets:Array; to the rest of the public variables, and put bullets = new Array(); in the constructor function, just as we did with army.
Next we need to push the new bullet we created in the code above into our new array:
172 173 174 175 176 177 178 179 | if ( spaceBarIsBeingPressed ) { var newBullet = new Bullet(); newBullet.x = avatar.x; newBullet.y = avatar.y; addChild( newBullet ); bullets.push( newBullet ); } |
Great, now we have an array of bullets. Time to loop through them.
Looping Through the Bullets
I know a lot of people have difficulty with arrays. Just remember, they’re like a numbered list. We move through the list backwards because certain problems would occur if we didn’t.
Here’s the important part of the army loop:
var i:int = army.length - 1; var enemy:Enemy; while ( i > -1 ) { enemy = army[i]; enemy.moveABit(); i = i - 1; } |
If there are ten enemies, they will take up army[0] through army[9], so we start at army[9] and keep going backwards through the list — that’s what i = i - 1 does. We only do this while the number of the enemy that we’re looking at is more than -1; army[-1] doesn’t refer to anything, so we’d get an error if we tried to use it.
Here’s the code we’ll use for the bullets:
181 182 183 184 185 186 187 188 | var j:int = bullets.length - 1; var bullet:Bullet; while ( j > -1 ) { bullet = bullets[j]; bullet.moveABit(); j = j - 1; } |
(I’ve put this after we create the new bullet, but before we do any collision detection.)
Note that I’m using j to move through this loop instead of i. You don’t have to do this; I just think it’s less confusing.
OK, just one more thing we need to do: create the bullet.moveABit() function. Because this code is so similar to the Enemy’s, I’m just going to paste it here for you to copy:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package { import flash.display.MovieClip; public class Bullet extends MovieClip { public var speed:Number; //pixels moved per tick public function Bullet() { speed = 3; } public function moveABit():void { y = y - speed; } } } |
Save that as Bullet.as. Run the game now, and here’s what you’ll get:
That’s better, but we still need to build in collision detection, and slow down the rate of fire.
Bullet-Enemy Collision Detection
We’ve got lots of bullets and lots of enemies, and we need to check whether any bullet hits any enemy. How?
If you read my mini-series on collectibles, you’ll already know. If not, I recommend thinking about it before reading on.
The answer is nested loops.
Rather than checking all of the bullets against all of the enemies, we check all of the bullets against one of the enemies, and then check all of the bullets against the next enemy, then the next, and so on.
Here’s a simplified example:
var i:int = army.length - 1; var enemy:Enemy; while ( i > -1 ) { enemy = army[i]; enemy.moveABit(); j = bullets.length - 1; while ( j > -1 ) { bullet = bullets[j]; //if bullet collides with enemy, destroy them both j = j - 1; } i = i - 1; } |
(Note: I haven’t written var j or var bullet because those are already defined earlier in the function.)
If that’s not clear, grab a piece of paper and a pencil and work through it, imagining that there are five enemies and three bullets, and bullet[1] is colliding with enemy[3].
OK, now we’ve got the basic idea, it’s time to actually plug this code into our existing enemy movement loop. Sure, we could write another loop just to handle enemy-bullet collisions, but that would be wasteful, and will slow things down.
So, here’s my existing enemy movement loop:
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | var avatarHasBeenHit:Boolean = false; var i:int = army.length - 1; var enemy:Enemy; while ( i > -1 ) { enemy = army[i]; enemy.moveABit(); if ( PixelPerfectCollisionDetection.isColliding( avatar, enemy, this, true ) ) { gameTimer.stop(); avatarHasBeenHit = true; } if ( enemy.y > 350 ) { removeChild( enemy ); army.splice( i, 1 ); } i = i - 1; } |
…and here’s my first attempt at enemy-bullet collision detection:
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | var avatarHasBeenHit:Boolean = false; var i:int = army.length - 1; var enemy:Enemy; while ( i > -1 ) { enemy = army[i]; enemy.moveABit(); //new code starts here j = bullets.length - 1; while ( j > -1 ) { bullet = bullets[j]; if ( bullet.hitTestObject( enemy ) ) { removeChild( enemy ); army.splice( i, 1 ); removeChild( bullet ); bullets.splice( j, 1 ); } j = j - 1; } //new code stops here if ( PixelPerfectCollisionDetection.isColliding( avatar, enemy, this, true ) ) { gameTimer.stop(); avatarHasBeenHit = true; } if ( enemy.y > 350 ) { removeChild( enemy ); army.splice( i, 1 ); } i = i - 1; } |
(I’ve used hitTestObject(), even though it’s not very accurate, because it’s much faster than PixelPerfectCollisionDetection.)
This does actually work, the bullets destroy the enemies and themselves, but error messages appear in the Output panel. The problem is, after an enemy gets destroyed by a bullet (removing it from the screen and the array), we still try to use it in the following bit of code (checking for a collision with the avatar, and to see whether it’s moved off the bottom of the screen).
To get around this, we can use the same technique we used for the avatar — the avatarHasBeenHit boolean:
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | var avatarHasBeenHit:Boolean = false; var enemyHasBeenHit:Boolean; var i:int = army.length - 1; var enemy:Enemy; while ( i > -1 ) { enemy = army[i]; enemy.moveABit(); enemyHasBeenHit = false; //new code j = bullets.length - 1; while ( j > -1 ) { bullet = bullets[j]; if ( bullet.hitTestObject( enemy ) ) { enemyHasBeenHit = true; //new code removeChild( bullet ); bullets.splice( j, 1 ); } j = j - 1; } if ( enemyHasBeenHit ) //new code { removeChild( enemy ); //new code army.splice( i, 1 ); //new code } else //new code { if ( PixelPerfectCollisionDetection.isColliding( avatar, enemy, this, true ) ) { gameTimer.stop(); avatarHasBeenHit = true; } if ( enemy.y > 350 ) { removeChild( enemy ); army.splice( i, 1 ); } } i = i - 1; } |
(I’ve written //new code throughout the code to make it easier to see what’s changed.)
So now we’re only checking for enemy-avatar collisions, and whether the enemy’s left the screen, if the enemy hasn’t already been hit by a bullet. It’s still not perfect, because we’ve got the same code in two separate parts of the loop (removing the enemy after it’s been hit by a bullet or left the screen) — can you see a way to improve that?
Check out the game so far:
Getting better!
Slowing Down the Rate of Fire
Does the constant stream of bullets look familiar to you?
It’s actually the same problem we had way back in Part 2 of the base tutorial, when a new enemy was being created every tick.
Back then we fixed it by having a one-in-ten chance of an enemy being created each tick. But applying this same “random” approach to how often the player can fire is just going to be frustrating.
We need to make it more exact: the player can only shoot if at least ten ticks have passed since his last shot.
Hey, that’s basically an if statement! if ( ticksSinceLastShot >= 10 )
Let’s work that in. First, we’ll need a public var ticksSinceLastShot:int (remember, an int is just a whole number). Set ticksSinceLastShot = 0; in the AvoiderGame constructor function. Also, in the onTick() function, put:
139 | ticksSinceLastShot = ticksSinceLastShot + 1; |
Now we can use our if statement from above:
175 176 177 178 179 180 181 182 183 184 185 | if ( spaceBarIsBeingPressed ) { if ( ticksSinceLastShot >= 10 ) { var newBullet = new Bullet(); newBullet.x = avatar.x; newBullet.y = avatar.y; addChild( newBullet ); bullets.push( newBullet ); } } |
Great! Try it out:

…what? Oh! We need to reset the ticksSinceLastShot variable after we’ve, er, shot:
175 176 177 178 179 180 181 182 183 184 185 186 | if ( spaceBarIsBeingPressed ) { if ( ticksSinceLastShot >= 10 ) { var newBullet = new Bullet(); newBullet.x = avatar.x; newBullet.y = avatar.y; addChild( newBullet ); bullets.push( newBullet ); ticksSinceLastShot = 0; } } |
Try it out:
Excellent.
Odds and Ends
There are a few small changes I’d like to make, but I’ve covered them all in earlier tutorials so I won’t go into much detail.
First, for garbage collection purposes, we need to remove the bullets once they get above the top of the screen:
188 189 190 191 192 193 194 195 196 197 198 199 200 | var j:int = bullets.length - 1; var bullet:Bullet; while ( j > -1 ) { bullet = bullets[j]; bullet.moveABit(); if ( bullet.y < -10 ) { removeChild( bullet ); bullets.splice( j, 1 ); } j = j - 1; } |
Second, I want to alter the scoring system, so that the player only gets points if he shoots an enemy. This means removing the points awarded when the enemy appears:
141 142 143 144 145 146 147 148 149 | if ( Math.random() < currentLevelData.enemySpawnRate ) { var randomX:Number = Math.random() * 400; var newEnemy:Enemy = new Enemy( randomX, -15 ); army.push( newEnemy ); addChild( newEnemy ); //gameScore.addToValue( 10 ); sfxSoundChannel = enemyAppearSound.play(); } |
…and adding the score in the bullet-enemy collision detection:
215 216 217 218 219 220 221 | if ( bullet.hitTestObject( enemy ) ) { enemyHasBeenHit = true; //new code removeChild( bullet ); bullets.splice( j, 1 ); gameScore.addToValue( 10 ); } |
It might be a good idea to make the player lose points if an enemy gets past the bottom of the screen — but I’ll leave that up to you.
Third, I want to add more sound effects. For this, I’m going to use the awesome (and free!) tool sfxr:
I’ve used the Laser/Shoot setting to make the noise to be played when the player shoots, and the Explosion setting to be played when the bullet hits an enemy. (We’ll look at making explosion animations in a later tutorial.)
Here’s the result:
Wrapping Up
You can download a zip of all the files I used in this tutorial (including the sound files) from this link.
This small addition has changed the entire game. It’s very simple, though. Next time we’ll improve this, so that the player can aim before they fire.
Until then, why not try adding a different kind of bullet that can be fired with the shift key?
Click here to read the next part of this mini-series: Move with the Mouse, Aim with the Keyboard.








{ 1 trackback }
{ 36 comments… read them below or add one }
“I know a lot of people have difficulty with arrays.” aha …….
Nice tutorial however
Thanks
Great tut once again
And a great introduction to sfxr.
nice change to the avoider game
cool job man
Cheers
Hey MJW, another great tutorial
On the topic of shooters, I’ve seen that some have levels with different enemies, that come in a specific order, at specific times. How could you control what enemies come on your levels, and set them up so they come at specific times? (eg. after 3 seconds, make enemy1; after 5 seconds, make enemy1 and enemy3; at 9 seconds, make level1boss…etc)
I found a link on Kongregate which has the same issue, but I can’t make heads or tails of the proposed solution. Any tips? http://www.kongregate.com/forums/4/topics/6306?page=1
Thanks
Thanks Fred
Hmm, interesting question. There’s a huge number of ways you could do this, so I don’t want to say “here is the One True method for doing that”. I’m actually working on a level editor for a game at the moment that’s easy to use but tricky to code.
I like what Phantasmagorica outlined in that forum post, but let’s see if we can make it simpler. Here’s an idea I just came up with, let me know what you think:
We start with an Array called
enemyScript. This array is actually going to contain multiple other arrays, like so:(By the way, you can use square brackets like that to create an array without having to write “var xyz:Array = new Array(); xyz.push()…”)
So here,
enemyScript[0]is { 3, “enemy1″ },enemyScript[1]is [ 5, "enemy1", "enemy3" ], and so on. Therefore,Inside the
AvoiderGameclass, we have a class-level public var calledcurrentScriptNumberwhich is an int that is set to 0 in the constructor function. We also have a public varsecondsPassedwhich is a Number, and keeps track of how many seconds have passed since the start of the game.Every tick, we run code like this:
var currentScript:Array = enemyScripts[currentScriptNumber]; if ( currentScript[0] > secondsPassed ) { var currentInstructionNumber:int = currentScript.length - 1; while ( currentInstructionNumber > 0 ) { if ( currentScript[currentInstructionNumber] == "enemy1" ) { //create new enemy1 } else if ( currentScript[currentInstructionNumber] == "enemy3" ) { //create new enemy3 } //...etc currentInstructionNumber = currentInstructionNumber - 1; } currentScriptNumber = currentScriptNumber + 1; }I’ll admit, that looks confusing. But if you followed the tutorial through you should be able to understand it — write it out on paper and follow it through if not.
Any questions, bugs or improvements?
Thanks! I haven’t had time to try this out, but when I do, I’ll be sure to tell you. This makes a little more sense than the post I read. I think I need to understand arrays a little better, but this helped me get the big picture.
how would i set up the shooter to respond to a mouse click instead of the space bar?
Hey Poe. If you just want to make a click shoot a bullet upwards, then you need to change
spaceBarIsBeingPressedtomouseIsBeingClicked.This involves changing the name of the variable, and also creating a couple new event listeners — one for MouseEvent.MOUSE_DOWN (call it onMousePress()) and one for MouseEvent.MOUSE_UP (call it onMouseRelease()).
I’ll go into this in more detail in the third part of this mini-series, where we’ll also make the bullet shoot towards the mouse cursor.
Hi, I found your tutorials two days ago, when I was looking for some advice for Action Script coding. I enjoyed your 12 part tutorial.
Anyway I followed this tutorial and got problem. When I play and first enemy spawns, it pops up Error #1009 and after that only moves last created enemy on screen, until bullet is shot and moving. Multiple bullets can be shot.
With debugging it points to “if (bullet.hitTestObject(enemy)) {” line. This occurs when no bullets are shot/on screen, so does this have something to do with bullet having “null” value or did I mess something else where?
Hey Waari. It sounds to me like your loops aren’t nested correctly. Do you have your bullet movement loop, followed by a separate enemy movement loop which contains another loop that does the enemy-bullet collision detection?
I did compare my code with yours in zip file. Loops are nested in same way as yours. I checked also other bullet and enemy related code and didn’t seem to find anything.
Enemies and bullets do move normally without “if (bullet.hitTestObject(enemy)) { ……. }” colliding test code. With that code, problem occurs only when no bullets are in array and when there is at least one enemy in army array. I tried to add collide check “if (bullets[0] != null) {” before collide check while loop, but with it some bullets got through enemies.
Oh wow, I found small typo in word “length”, which caused all that mess. Altough it hilights that word normally, I didn’t notice it before I did same typo when adding collectibles.
D’oh! Ah, I hate when small mistakes like that send you off on huge searches for a problem that isn’t even there. Glad you fixed it
Michael, great tutorial, all yours are great, they helped me make Circle Dash (www.kongregate.com/games/djice555/circle-dash) but im working on another game, a tank needs to shoot a projectile in the direction of the tank, i used asgamer.coms asteroids style 360 degree movement tut for the tank movement (www.asgamer.com/2009/as3-character-movement-asteroids-style-360-degree-movement) can you help me get the bullets to move, they just kinda sit there on the end of the turret.
Thanks Patrick!
Have you given the bullets a moveABit() function, and are you calling that function of each bullet every tick?
i added them and now the bullets wont show up, is there a way to send my swf and classes to you
I’m pretty busy currently but if you send them to the address on my About page I’ll try to get to them tomorrow.
I like this article so far. I just had a bug that reminded me of the need to watch for capitalization errors…
Every time I would press the space bar, my bullets would immediately be at the top of the screen. After using trace() and commenting out lines for a while, I changed
to
and it worked fine! So after a couple more minutes I noticed I named the constructor function bullet instead of Bullet and so speed was being seen as NaN… D’oh.
Bigfoot´s last blog ..MJW Avoider Game ep11ch1
Hey Michael- I’m trying to troubleshoot this bug. It happens when I try to remove a bullet, after it hits an enemy:
j = bullets.length - 1; while ( j > -1 ) { bullet = bullets[j]; if( bullet.hitTestObject( enemy ) ) { enemyHasBeenHit = true; trace("Before Error"); removeChild( bullet ); trace( bullet ); trace("After Error");bullets.splice( i, 1 ); } j -= 1; }
I shoot, and when it hits an enemy, I get at least one (usually a bunch) of these in my Output window:
Before Error? ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller. at flash.display::DisplayObjectContainer/removeChild() at AvoiderGame/gameTick() at AvoiderGame/onTick() at flash.utils::Timer/flash.utils:Timer::_timerDispatch() at flash.utils::Timer/flash.utils:Timer::tick() Before Error? [object Bullet] After Error?This page http://lassieadventurestudio.wordpress.com/2008/09/29/common-as3-errors/ had some interesting information on errors, but I wasn’t able to figure out what the name of the ‘parent’ would be…
Bigfoot´s last blog ..MJW Avoider Game ep11ch1
D’oh… my code said
instead of
Bigfoot´s last blog ..MJW Avoider Game ep11ch1
Hey Bigfoot,
Interesting that you happened to come across that bug with the bullets appearing at the top of the screen. Scarybug said he came across it as well, but I wasn’t sure why. Anything I could do to make it clearer?
Re. that second error… d’oh!
Hi so I’ve been looking around the internet for better way’s of hittesting then in my current game, Since when I have 25 enemies as soon as the bullet count hits about 10 the FPS of the game drops to about 5.
The code is basically doing the same array search method as in this but it still laggs. Do you remove bullets when there off the screen? Since I didn’t see any code for it but I wasn’t really looking
Here is my code (Bit messy but hey I didn’t write it lol other developer)
for (var i:Number=0; i =1) { eRemaining+=1; for (var j:Number=0; j < bulletArray.length; j++) { if (bulletArray[j].hitObject==false) { var htobj:Rectangle=com.adventuresinactionscript.collisions.HitTest.hitTestObject(bulletArray[j],level_mc.walls,true,255); if (htobj!=null) { bulletArray[j].killSelf (); bulletArray.splice (j,1); } if (enemyArray[i].hitTestObject(bulletArray[j])==true) { try { bulletArray[j].hitObject=true; bulletArray[j].killSelf (); bulletArray.splice (j,1); } catch (e:Error) { } try { enemyArray[i].healthRem-=player_mc.weaponDamage; } catch (e:Error) { } try { if (enemyArray[i].healthRem<0) { enemyArray[i].healthRem=0; }Hey Taylor,
Yep, bullets get removed once they get above the top of the screen (see the ‘Odds and Ends’ section).
I’m not really sure what you’re asking here… are you saying the game started to lag after you followed this tutorial, so you wrote some new code (pasted) which still lagged?
No the other developer on this project (www.code.google.com/p/advancedflashengine) had written this code before I went looking for a more efficient way of bull,enemy hit testing. In this game I was able to fill the play to the top of the screen with bullets and still have 20 enemies before it started to lagg. And seeing as my code is just the same hittesting with some health calculations in it I don’t see why it laggs so badly.
Oh OK I see. Well, let’s narrow it down. Try temporarily commenting out or removing every line of code that has nothing to do with bullet-enemy hit testing, like the health calculations and the bullet-wall hit tests. What’s the fps like then?
Well I did remove the wall hittesting didn’t make a difference. Haven’t tried removing the health calculations I’ll try at school (Most likely won’t be able to post back since this website has the word “Game” in it and my school will block it)
OK, let me know how it goes.
Problem solved the other developer on the project had for some reason unknown to everyone done the same hit testing twice with different pixel perfect hit detection.
Aha, well, that explains it
hey guys can anyone help, i have a basic error but can not solve it,
Source:
i thought this meant that public function getFinalScore():Number simply needed to be within a public, private, etc, can anyone help??? thanks Alex
Note for anyone else reading: Alex and I talked about this via email; turned out it was caused by a mismatched brace.
Micheal great stuff you have here.
The pixleperfect hit detection is awesome but certainly it can cause strains correct?
So wouldn’t it be a good idea to first run a loop to hittestobject then if hit is detected to then run pixelperfect collision, to reduce overhead?
A nested loop inside of a loop?
Then the next question if this approach is valid how to write the nested loop?
Thanks
Hey JimE — thanks!
Yep, you’re right, it can slow things down. You’ve got a good idea there, doing the simpler hitTest before the slow pixel perfect check.
Actually, you wouldn’t need to nest two loops, but rather two if-statements, like so:
if ( avatar.hitTestObject( enemy ) ) { if ( pixelPerfectCollisionDetection.isColliding( avatar, enemy ) ) { //they are colliding } }Make sense?
Me again.. I keep getting errors when I attempt this tutorial :/
if ( spaceBarIsBeingPressed ) { var newBullet = new Bullet(); newBullet.x = avatar.x; newBullet.y = avatar.y; addChild( newBullet ); } var j:int = bullets.length - 1; var bullet:Bullet; while ( j > -1 ) { bullet = bullets[j]; bullet.moveABit(); j = j - 1; }Is there an error in there that would cause either of these errors? 1119: Access of possibly undefined property length through a reference with static type Bullet. Warning: 3596: Duplicate variable definition.