Table of contents for AS3 Avoider Game Tutorial
- Learn ActionScript 3 by Following this Simple Avoider Game Tutorial
- AS3 Avoider Game Tutorial, Part 2: Multiple Enemies
- AS3 Avoider Game Tutorial, Part 3: Game Over
- AS3 Avoider Game Tutorial, Part 4: Menus and Buttons
- AS3 Avoider Game Tutorial, Part 5: A Score and a Clock
- AS3 Avoider Game Tutorial, Part 6: Several Small Improvements
- AS3 Avoider Game Tutorial, Part 7: Keyboard Control
- AS3 Avoider Game Tutorial, Part 8: Adding a Preloader
- AS3 Avoider Game Tutorial, Part 9: Music and Sound Effects
- AS3 Avoider Game Tutorial, Part 10: Multiple Levels
- AS3 Avoider Game Tutorial, Part 11: Saving and Loading
- AS3 Avoider Game Tutorial, Part 12: Garbage Collection
So far, every programming concept we’ve covered has helped to add a new gameplay element. This part will be the exception to that rule; while the changes we’re about to make are very important for the creation of bigger, more complex games, they will not be obvious to the player.
In this, the final part of my AS3 and Flash CS3 conversion of Frozen Haddock’s avoider game tutorial, we’ll deal with “garbage collection”.
Click the image below to check it out — but you won’t notice a difference unless you play for a long time.
If you’ve not been following the tutorial, grab the zip file of the game so far here and extract it somewhere. Otherwise, copy the files you’ve been working on so far to a new folder, as usual. Open the FLA file, and let’s get started.
What are Variables?
What happens when we type something like:
var score:Number = 100;
Intuitively, it’s like we create a box, write “score” on the lid, and put the number 100 inside it.

That’s a pretty good way of thinking about it, and it’s true for Strings, Booleans, and all types of Numbers. What about this line:
var avatar:Avatar = new Avatar();
Presumably that does the same thing, creating a box, writing “avatar” on the lid, and making a new Avatar object to go inside? Actually, no. The box and the Avatar are kept separate, with the Avatar seemingly floating around in space, and the box contains directions to the actual Avatar object. It’s like the box is tied to the Avatar with a piece of rope:

This is the case for any type of Object other than Strings, Booleans, and Numbers.
That’s interesting and all, but what does it actually mean? Well, consider this code:
var score:Number = 100; var newScore:Number = score;
Here, the variable newScore will copy the contents of score into its own insides:

But with this code:
var avatar:Avatar = new Avatar(); var newAvatar:Avatar = avatar;
the variable newAvatar will actually only copy the link, the so-called reference, to the same Avatar object — no new Avatar object is created or copied!

This can cause confusion when trying to change something about a variable. For example, using the above code, if you wrote:
newScore = 250; trace( "score is:", score ); trace( "newScore is:", newScore );
then the trace statements would output:
score is: 100 newScore is: 250
which is what you’d expect. The contents of the boxes are different, and can be altered separately.

Now let’s try a similar thing with the avatars:
avatar.scaleY = 1; newAvatar.scaleY = 2; trace( "avatar.scaleY is:", avatar.scaleY ); trace( "newAvatar.scaleY is:", newAvatar.scaleY );
This will output:
avatar.scaleY is: 2 newAvatar.scaleY is: 2
This seems surprising, but actually makes perfect sense when you consider that there is only one Avatar object and that both avatar and newAvatar are referring to the same thing.
Incidentally, scaleY is used to stretch or squash an image vertically, so the situation would look like this:

In earlier parts of this tutorial, I have said that setting an object equal to null essentially deletes them. This was a gross oversimplification. For Strings, Numbers, and Booleans it’s true:
score = null;
…but for any other object, all setting it to null does is remove the link from the box (variable) to the actual object:
avatar = null;
Here, the avatar variable is no longer linked to the actual Avatar object, so trying to trace avatar.scaleY will just result in an error. The Avatar object still exists, though, and the newAvatar variable is still linked to it, so tracing newAvatar.scaleY will return 2, as before.
This is useful, as it lets us create an object in one class or function and pass it to another class or function to do something else with, rather than messing around copying all the contents of an object and deleting the original. It does raise an interesting question, though: what happens if we now set newAvatar to null?
newAvatar = null;
Now the Avatar is in no-man’s land; we’ve destroyed all our references to it and so can’t access it any more. And yet, it still exists, and it’s still taking up space in the player’s computer’s RAM, even though it’ll never be used again. This might not seem like a big deal, but when you consider that the same thing happens with all the enemies, the background music, the sound effects, the menu screen… it adds up, and even a simple game like ours would eventually fill up the user’s computer with these “dead objects”, making it very slow.
Or at least, it would, if not for the Flash garbage collector.
Garbage Collection in Flash
The Flash Player has a built-in tool to clear these dead objects. Every so often — I hate to use such a vague phrase, but we just don’t know when exactly this will take place — the “garbage collector” checks to see if there are any objects that don’t have any variables linking to them. If so, they get removed.
Additionally, if a variable does link to an object, but that variable itself is contained in another object that isn’t linked to by another variable, it’ll get removed. For instance, in our game, avatar belongs to the playScreen, which in turn belongs to the document class:

If we now remove the reference from the document class to the play screen:
playScreen = null;
…then both the playScreen and the avatar objects will be garbage collected.
And this can be extended even further. Any object that does not have a direct or indirect chain of links from the document class (or stage) will be garbage collected. (For much more information on exactly how this works, check out Grant Skinner’s excellent series of posts.)
Aside from setting variables, links are also created with addChild. Let’s take a look at this. Run your game, and stretch the window so that it’s taller than it should be:


Start playing. When you click the start button, remember this code is run:
62 63 64 65 66 67 68 69 70 71 | public function onRequestStart( navigationEvent:NavigationEvent ):void { playScreen = new AvoiderGame(); playScreen.addEventListener( AvatarEvent.DEAD, onAvatarDeath ); playScreen.x = 0; playScreen.y = 0; addChild( playScreen ); menuScreen = null; } |
menuScreen is set to null, and yet:

We can still see a bit of it! It could be that the garbage collector just hasn’t been run yet, but that’s not the case here (feel free to test it by playing for a while though
). What’s happening is, the menuScreen still has a link from the document class, since it was addChild-ed. To remove this link, we need to use the (unsurprisingly named) removeChild function:
62 63 64 65 66 67 68 69 70 71 72 | public function onRequestStart( navigationEvent:NavigationEvent ):void { playScreen = new AvoiderGame(); playScreen.addEventListener( AvatarEvent.DEAD, onAvatarDeath ); playScreen.x = 0; playScreen.y = 0; addChild( playScreen ); removeChild( menuScreen ); menuScreen = null; } |

That’s better. Except, no, it’s not, because we’ve lost keyboard control. What the heck?
Clicking on the game lets us control it again, and that gives us a hint for the cause of the problem. In Part 7 we found that the special stage object was what we used to actually listen to the keyboard. More specifically, the stage contains a reference to yet another object which has keyboard focus; this object passes the keys pressed through to the stage, which is why we can always use it to listen to the keyboard events.
(Imagine we made an application in Flash that let you type your name, email address, and website URL into different text input boxes. At any one time, only one of the boxes has the “focus”; when you type something into the “name” box, it doesn’t affect the email or URL box. However, each of them lets the stage know what you’re typing.)
When we clicked the button to start the game, we gave it the focus — and then we removed it from the stage so that it couldn’t pass information about the keys being pressed back to the stage any more. D’oh.
This is easy to fix, though! We can just tell the stage that the play screen now has the focus:
62 63 64 65 66 67 68 69 70 71 72 73 74 | public function onRequestStart( navigationEvent:NavigationEvent ):void { playScreen = new AvoiderGame(); playScreen.addEventListener( AvatarEvent.DEAD, onAvatarDeath ); playScreen.x = 0; playScreen.y = 0; addChild( playScreen ); removeChild( menuScreen ); menuScreen = null; stage.focus = playScreen; } |
Only trouble is, we end up with this ugly yellow border around the game:

It’s because the stage has an option to highlight the object that currently has the focus. This might be useful in certain circumstances, but we don’t need it here. It can be turned off with one line; just add this to the document class:
24 | stage.stageFocusRect = false; |

Now, let’s apply these ideas throughout the document class. I’ve collapsed this code box so that it doesn’t take up lots of room; click the little triangle to expand it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | package { //Avoider Game Tutorial, by Michael James Williams //http://gamedev.michaeljameswilliams.com import flash.display.MovieClip; import flash.events.Event; import flash.events.ProgressEvent; public class DocumentClass extends MovieClip { public var menuScreen:MenuScreen; public var playScreen:AvoiderGame; public var gameOverScreen:GameOverScreen; public var loadingProgress:LoadingProgress; public function DocumentClass() { loadingProgress = new LoadingProgress(); loadingProgress.x = 200; loadingProgress.y = 150; addChild( loadingProgress ); loaderInfo.addEventListener( Event.COMPLETE, onCompletelyDownloaded ); loaderInfo.addEventListener( ProgressEvent.PROGRESS, onProgressMade ); stage.stageFocusRect = false; } public function onCompletelyDownloaded( event:Event ):void { removeChild( loadingProgress ); gotoAndStop(3); showMenuScreen(); } public function onProgressMade( progressEvent:ProgressEvent ):void { loadingProgress.setValue( Math.floor( 100 * loaderInfo.bytesLoaded / loaderInfo.bytesTotal ) ); } public function showMenuScreen():void { menuScreen = new MenuScreen(); menuScreen.addEventListener( NavigationEvent.START, onRequestStart ); menuScreen.x = 0; menuScreen.y = 0; addChild( menuScreen ); stage.focus = menuScreen; } public function onAvatarDeath( avatarEvent:AvatarEvent ):void { var finalScore:Number = playScreen.getFinalScore(); var finalClockTime:Number = playScreen.getFinalClockTime(); gameOverScreen = new GameOverScreen(); gameOverScreen.addEventListener( NavigationEvent.RESTART, onRequestRestart ); gameOverScreen.x = 0; gameOverScreen.y = 0; gameOverScreen.setFinalScore( finalScore ); gameOverScreen.setFinalClockTime( finalClockTime ); addChild( gameOverScreen ); removeChild( playScreen ); playScreen = null; stage.focus = gameOverScreen; } public function onRequestStart( navigationEvent:NavigationEvent ):void { playScreen = new AvoiderGame(); playScreen.addEventListener( AvatarEvent.DEAD, onAvatarDeath ); playScreen.x = 0; playScreen.y = 0; addChild( playScreen ); removeChild( menuScreen ); menuScreen = null; stage.focus = playScreen; } public function onRequestRestart( navigationEvent:NavigationEvent ):void { restartGame(); } public function restartGame():void { playScreen = new AvoiderGame(); playScreen.addEventListener( AvatarEvent.DEAD, onAvatarDeath ); playScreen.x = 0; playScreen.y = 0; addChild( playScreen ); removeChild( gameOverScreen ); gameOverScreen = null; stage.focus = playScreen; } } } |
There’s not a lot to change, really.
Now, let’s take a look at the play screen:

Look at all those enemies below the visible area! None of them can be garbage collected until the game is finished, as they’re still on the screen and in the army array. If the player manages to stay alive for a long time, these enemies will just pile up and slow the game down to a crawl. So I think we’d better change this.
First, let’s get rid of that one enemy that’s always “manually” created in the constructor function. Just delete these three lines:
47 48 49 | var newEnemy = new Enemy( 100, -15 ); army.push( newEnemy ); addChild( newEnemy ); |
You don’t have to do this, but I don’t think we need it any more, since we’ve got plenty of enemies being generated randomly. Also, I think we should use the LevelData class if we want to create enemies at specific positions.
Next we have to remove the enemies from the army.
Removing Objects From An Array
Here’s something that trips everyone up the first time they try it. We want to remove any enemy that gets too far below the play screen, right? So, it seems all we need to do is this:
158 159 160 161 162 163 164 165 166 167 168 169 170 | for each ( var enemy:Enemy in army ) { enemy.moveABit(); if ( PixelPerfectCollisionDetection.isColliding( avatar, enemy, this, true ) ) { gameTimer.stop(); avatarHasBeenHit = true; } if ( enemy.y > 350 ) { //remove enemy here } } |
(That’s in the onTick() function, and lines 166-169 are the new ones. I’ve left out the actual removal code for now to make this point.)
This code will often lead to problems. See, Arrays are like lists, and each item on the list is a reference to an actual object. For example, army[0] refers to the first enemy in the army, army[1] to the second enemy, and so on.
When we write for each ( var enemy:Enemy in army ), it’s like saying “set enemy = army[0], then do the following code, then set enemy = army[1], then do the following code, and repeat until we reach the last member of army”.
Here’s the trick. If our for each gets to, say, the enemy stored at army[4], and decides to remove it from the array, then rather than making army[4] empty, it will instead refer to the enemy in army[5]. army[5] will, in turn, change to refer to army[6], which will change to refer to army[7], and so on. But our for each loop says, “right, we’ve dealt with army[4], now let’s move on to army[5]” — and it misses out the new ***army[4]* entirely**.
To illustrate this, let’s suppose we’ve got a numbered shopping list (we’re very organised shoppers). We look for each item in turn, rather than grouping them into aisles they’re likely to be on (so OK we’re not that organised), and if the shop doesn’t have any, we cross it off the list and move the numbers down. I’ll use bold to indicate the item we’re currently looking for. We start with item #1:
- Bacon
- Peas
- Apples
- Cabbage
- Potatoes
They’ve got bacon, great. Now onto item #2:
- Bacon
- Peas
- Apples
- Cabbage
- Potatoes
They have peas too. Yum. Now for item #3:
- Bacon
- Peas
- Apples
- Cabbage
- Potatoes
They don’t have apples, damn. Cross it off and re-number the list:
- Bacon
- Peas
- Cabbage
- Potatoes
Wait, nothing’s bold any more, what are we looking for? Well, we just did item #3, so I guess we should move on to item #4:
- Bacon
- Peas
- Cabbage
- Potatoes
Ah, excellent, they have potatoes. Well, that’s everything we wanted except apples, right? Not bad. Except then we get home and, damnit, we totally missed out cabbage! How can we make our famous “baconed potatoes with peas and cabbage” tonight? We can’t, the dinner party is ruined, and we’re the laughing stock of the town.
Er, back to programming.
This means that during this tick, we don’t check army[4] for collisions, we don’t check to see whether it’s got too low on the screen, or anything like that. This can cause really weird behaviour that appears to occur randomly — at least until you understand the reason.
The solution is simple. All we need to do is start at the end and work backwards. So in the shopping example, we start with #5:
- Bacon
- Peas
- Apples
- Cabbage
- Potatoes
Now onto #4:
- Bacon
- Peas
- Apples
- Cabbage
- Potatoes
(They do have cabbage.) Next is #3:
- Bacon
- Peas
- Apples
- Cabbage
- Potatoes
No apples, so cross it off and re-number the list:
- Bacon
- Peas
- Cabbage
- Potatoes
Where were we? Oh yes, #3. On to #2 then:
- Bacon
- Peas
- Cabbage
- Potatoes
Got peas, finally we do #1:
- Bacon
- Peas
- Cabbage
- Potatoes
And yes, they still have bacon. Success!
We can’t force a for each loop to work backwards, unfortunately, so we have to put a bit more work in. Remember back in Part 5 I introduced the while loop? To recap, it’s basically an if statement, but the code inside the curly braces gets run over and over again for as long as the statement is true. We can use a while loop to run through an Array backwards, like this:
var i:int = army.length - 1; //int just means a whole number var enemy:Enemy; while ( i > -1 ) { enemy = army[i]; //do other code here i = i - 1; } |
See how that works?
- var i:int — an int is just like a Number, but it only allows whole numbers, i.e. 1 and 5 are fine, but 2.38 isn’t
- army.length – 1 — since the first item in an array is numbered 0, the second item will be numbered 1, the 20th will be numbered 19, and so on. army.length is the number of items in the Array, so army.length – 1 is the number of the last item in the Array
- var enemy:Enemy; — we’re not setting it to refer to any specific enemy just yet
- while ( i > -1 ) — as long as i is equal to 0 or higher, army[i] will refer to an enemy within the army Array
- i = i – 1 — this is very important! This is what makes the code move backwards in the Array. Forget this, and you’ll get an infinite loop, and have to wait 30 seconds for Flash to decide something fishy is going on and stop running the game.
Let’s see how this looks in our onTick() function:
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | 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 ) { //remove enemy here } i = i - 1; } |
Now we need to remove the enemy’s reference from army. Every Array has a built-in splice() function for this. We pass this two numbers; the first is the position of the object we want to remove within the array (so in this case, that’s i), and the second is the number of objects we wish to remove (in this case, 1). Replace that “remove enemy here” comment as so:
169 170 171 172 | if ( enemy.y > 350 ) { army.splice( i, 1 ); } |
Save and run your game, stretch it vertically again, and start playing:

As the enemies reach a certain point, they are removed from the army, and so their moveABit() functions no longer get run and they stop moving. It’s pretty funny to watch, but sadly we can’t, as we need to removeChild() them if we want to clear them out of the player’s computer’s memory:
169 170 171 172 173 | if ( enemy.y > 350 ) { removeChild( enemy ); army.splice( i, 1 ); } |
Run your game with this code and you’ll see that the enemies just vanish after they get to a certain point below the screen. Great!
Tidying Up After Yourself
Aside from variables and addChild(), there’s another way of setting a reference to an object: event listeners! Sometimes functions can behave like objects; when you write “addEventListener( Event.WHATEVER, someFunction )”, the someFunction event handler function is treated like an object. As long as the event listener exists — i.e., as long as you don’t run “removeEventListener( Event.WHATEVER, someFunction )” — someFunction cannot be garbage collected.
Fortunately, Flash gives us a really easy way of dealing with this. It’s called weak referencing. You can tell Flash to use a “weak reference” to an event handler when creating an event listener, and when it does the garbage collection, it’ll ignore any such weak references. That means that if a function has a bunch of weak references, it’ll be garbage collected.
Obviously this takes a lot of work out of our hands, which is great. And all we have to do is change the way we add our event listeners, from this:
addEventListener( Event.WHATEVER, someFunction ); |
to this:
addEventListener( Event.WHATEVER, someFunction, false, 0, true ); //weak ref |
Please ignore the third and fourth parameters for now; they basically control the order in which an event listener should be triggered, and I don’t want to go into details at the minute (check here for more info).
Setting the fifth parameter to true like this will force Flash to use these weak event listeners. Grant Skinner recommends getting into the habit of doing this for all listeners, and I agree.
Here’s what the document class looks like with all event listeners weakly referenced:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | package { //Avoider Game Tutorial, by Michael James Williams //http://gamedev.michaeljameswilliams.com import flash.display.MovieClip; import flash.events.Event; import flash.events.ProgressEvent; public class DocumentClass extends MovieClip { public var menuScreen:MenuScreen; public var playScreen:AvoiderGame; public var gameOverScreen:GameOverScreen; public var loadingProgress:LoadingProgress; public function DocumentClass() { loadingProgress = new LoadingProgress(); loadingProgress.x = 200; loadingProgress.y = 150; addChild( loadingProgress ); loaderInfo.addEventListener( Event.COMPLETE, onCompletelyDownloaded, false, 0, true ); loaderInfo.addEventListener( ProgressEvent.PROGRESS, onProgressMade, false, 0, true ); stage.stageFocusRect = false; } public function onCompletelyDownloaded( event:Event ):void { removeChild( loadingProgress ); gotoAndStop(3); showMenuScreen(); } public function onProgressMade( progressEvent:ProgressEvent ):void { loadingProgress.setValue( Math.floor( 100 * loaderInfo.bytesLoaded / loaderInfo.bytesTotal ) ); } public function showMenuScreen():void { menuScreen = new MenuScreen(); menuScreen.addEventListener( NavigationEvent.START, onRequestStart, false, 0, true ); menuScreen.x = 0; menuScreen.y = 0; addChild( menuScreen ); stage.focus = menuScreen; } public function onAvatarDeath( avatarEvent:AvatarEvent ):void { var finalScore:Number = playScreen.getFinalScore(); var finalClockTime:Number = playScreen.getFinalClockTime(); gameOverScreen = new GameOverScreen(); gameOverScreen.addEventListener( NavigationEvent.RESTART, onRequestRestart, false, 0, true ); gameOverScreen.x = 0; gameOverScreen.y = 0; gameOverScreen.setFinalScore( finalScore ); gameOverScreen.setFinalClockTime( finalClockTime ); addChild( gameOverScreen ); removeChild( playScreen ); playScreen = null; stage.focus = gameOverScreen; } public function onRequestStart( navigationEvent:NavigationEvent ):void { playScreen = new AvoiderGame(); playScreen.addEventListener( AvatarEvent.DEAD, onAvatarDeath, false, 0, true ); playScreen.x = 0; playScreen.y = 0; addChild( playScreen ); removeChild( menuScreen ); menuScreen = null; stage.focus = playScreen; } public function onRequestRestart( navigationEvent:NavigationEvent ):void { restartGame(); } public function restartGame():void { playScreen = new AvoiderGame(); playScreen.addEventListener( AvatarEvent.DEAD, onAvatarDeath, false, 0, true ); playScreen.x = 0; playScreen.y = 0; addChild( playScreen ); removeChild( gameOverScreen ); gameOverScreen = null; stage.focus = playScreen; } } } |
And here’s AvoiderGame:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 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 | package { import flash.display.MovieClip; import flash.utils.Timer; import flash.events.TimerEvent; import flash.ui.Mouse; import flash.events.KeyboardEvent; import flash.ui.Keyboard; import flash.events.Event; import flash.media.SoundChannel; public class AvoiderGame extends MovieClip { public var army:Array; public var enemy:Enemy; public var avatar:Avatar; public var gameTimer:Timer; public var useMouseControl:Boolean; public var downKeyIsBeingPressed:Boolean; public var upKeyIsBeingPressed:Boolean; public var leftKeyIsBeingPressed:Boolean; public var rightKeyIsBeingPressed:Boolean; public var backgroundMusic:BackgroundMusic; public var bgmSoundChannel:SoundChannel; //bgm for BackGround Music public var enemyAppearSound:EnemyAppearSound; public var sfxSoundChannel:SoundChannel; //sfx for Sound FX public var currentLevelData:LevelData; public function AvoiderGame() { currentLevelData = new LevelData( 1 ); setBackgroundImage(); backgroundMusic = new BackgroundMusic(); bgmSoundChannel = backgroundMusic.play(); bgmSoundChannel.addEventListener( Event.SOUND_COMPLETE, onBackgroundMusicFinished, false, 0, true ); enemyAppearSound = new EnemyAppearSound(); downKeyIsBeingPressed = false; upKeyIsBeingPressed = false; leftKeyIsBeingPressed = false; rightKeyIsBeingPressed = false; useMouseControl = false; Mouse.hide(); army = new Array(); avatar = new Avatar(); addChild( avatar ); if ( useMouseControl ) { avatar.x = mouseX; avatar.y = mouseY; } else { avatar.x = 200; avatar.y = 250; } gameTimer = new Timer( 25 ); gameTimer.addEventListener( TimerEvent.TIMER, onTick, false, 0, true ); gameTimer.start(); addEventListener( Event.ADDED_TO_STAGE, onAddToStage, false, 0, true ); } public function onBackgroundMusicFinished( event:Event ):void { bgmSoundChannel = backgroundMusic.play(); bgmSoundChannel.addEventListener( Event.SOUND_COMPLETE, onBackgroundMusicFinished, false, 0, true ); } public function onAddToStage( event:Event ):void { addEventListener( KeyboardEvent.KEY_DOWN, onKeyPress, false, 0, true ); addEventListener( KeyboardEvent.KEY_UP, onKeyRelease, false, 0, true ); } 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; } } public function onKeyRelease( keyboardEvent:KeyboardEvent ):void { if ( keyboardEvent.keyCode == Keyboard.DOWN ) { downKeyIsBeingPressed = false; } else if ( keyboardEvent.keyCode == Keyboard.UP ) { upKeyIsBeingPressed = false; } else if ( keyboardEvent.keyCode == Keyboard.LEFT ) { leftKeyIsBeingPressed = false; } else if ( keyboardEvent.keyCode == Keyboard.RIGHT ) { rightKeyIsBeingPressed = false; } } public function onTick( timerEvent:TimerEvent ):void { gameClock.addToValue( 25 ); 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(); } if ( useMouseControl ) { avatar.x = mouseX; avatar.y = mouseY; } else { if ( downKeyIsBeingPressed ) { avatar.moveABit( 0, 1 ); } else if ( upKeyIsBeingPressed ) { avatar.moveABit( 0, -1 ); } else if ( leftKeyIsBeingPressed ) { avatar.moveABit( -1, 0 ); } else if ( rightKeyIsBeingPressed ) { avatar.moveABit( 1, 0 ); } } if ( avatar.x < ( avatar.width / 2 ) ) { avatar.x = avatar.width / 2; } if ( avatar.x > 400 - ( avatar.width / 2 ) ) { avatar.x = 400 - ( avatar.width / 2 ); } if ( avatar.y < ( avatar.height / 2 ) ) { avatar.y = avatar.height / 2; } if ( avatar.y > 300 - ( avatar.height / 2 ) ) { avatar.y = 300 - ( avatar.height / 2 ); } 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; } if ( avatarHasBeenHit ) { bgmSoundChannel.stop(); dispatchEvent( new AvatarEvent( AvatarEvent.DEAD ) ); } if ( gameScore.currentValue >= currentLevelData.pointsToReachNextLevel ) { currentLevelData = new LevelData( currentLevelData.levelNum + 1 ); setBackgroundImage(); } } public function setBackgroundImage():void { if ( currentLevelData.backgroundImage == "blue" ) { backgroundContainer.addChild( new BlueBackground() ); } else if ( currentLevelData.backgroundImage == "red" ) { backgroundContainer.addChild( new RedBackground() ); } } public function getFinalScore():Number { return gameScore.currentValue; } public function getFinalClockTime():Number { return gameClock.currentValue; } } } |
The only other classes you need to alter are GameOverScreen and MenuScreen, and they each only have one event listener.
Do bear in mind that timers will still tick and sounds will still play until they get picked up by the garbage collector. Since we can’t predict when exactly that will happen, it’s best to stop them manually in your code.
That’s about it for garbage collection! OK, sure, there are smaller issues we could delve into, but these three basic ideas — set reference variables to null, remember to removeChild(), and use weakly-referenced event listeners — will cover you for all but the most huge and complex projects.
There’s just one more thing we should change before ending this tutorial…
Manually Declare Stage Instances
Remember wayyyy back in the first part of this tutorial, when I told you to tick the box marked “Automatically declare stage instances” in File > Publish Settings > Flash > Settings? Well, twelve parts later, we’re finally going to untick it.
What does it do, though? Actually it’s very simple. Take a look at the PlayScreen movie clip. It contains a score object and a clock object, but no avatar object. Now if you look at the corresponding AvoiderGame class, it has the code “public var avatar:Avatar;”, but there’s no corresponding code for the score or the clock.
All the “automatically declare stage instances” box does is make Flash insert the “public var clock:Clock;” and “public var score:Score;” lines when the game is run. If we uncheck it, we have to write those lines in ourselves.
Why would we want to give ourselves that extra work? One simple reason: Flash CS3′s built-in code editor is rubbish. When I write code, I use the free FlashDevelop software, which automatically inserts the various import statements, generates event handler code, lets me search through all my AS files for a specific keyword, and so much more. It’s not the only code editor of its kind, either. The one problem is… you have to turn off “automatically declare stage instances” in order to get the most from these kinds of software. I believe this small inconvenience is worth it.
Here’s how to do it. First, navigate to File > Publish Settings > Flash > Settings and untick that box:

Now save your game, and try to run it. You’ll get a bunch of errors:

All you need to do is double-click each error to open the corresponding class file, work out what object it’s talking about, and then add a “public var” statement to the top of that class.
For example, the first error I get is:
1120: Access of undefined property gameClock.
Double-clicking this takes me to AvoiderGame, line 122:
122 | gameClock.addToValue( 25 ); |
So, I just go to the top of the file, and manually declare the gameClock as a public variable of type Clock:
12 13 14 | public class AvoiderGame extends MovieClip { public var gameClock:Clock; |
Repeat this process until you no longer get any errors. It won’t take long!
Then, go download FlashDevelop (or Eclipse). Enjoy
Challenges
Like I said, this is the final part of this tutorial… but that doesn’t mean I won’t be writing more.
A lot of great ideas for new features have been suggested in the comments and via email, like having the avatar follow the cursor, making the play screen slowly turn to greyscale when the avatar dies, and putting a maze of walls around each level. I’d love to work these into the tutorial, but there are two problems: first, I can see it becoming 30 Parts long, which is going to be very overwhelming to anyone finding it for the first time; second, not everyone is going to want to implement every one of these features — but if they skip a specific part of the tutorial, it might be difficult to understand the next part that does contain a feature they’d like.
The best solution I can see is to declare this as a cut-off point. Future pieces of the tutorial will all start from this one part, so that anyone that’s got this far will be able to pick and choose from all the other pieces that will be written, without worrying about skipping over something important.
But this opens things up. Now anyone can write a piece, because everyone is starting from the same base. And that’s what this challenge is going to be.
I’d like you to write a tutorial. It doesn’t have to be long, it doesn’t have to be complex, it doesn’t even have to be in English. I know you guys have been experimenting with different features, often coming up with solutions I wouldn’t have thought of, and I’d like to see what you’ve invented.
FrozenHaddock and I have created a new site to catalogue all of these creations. It’s called AvoiderGame.com. If you’ve got a blog, you can post your tutorial there and we’ll link to it; if not, we’ll host it for you for free. Later on, we’ll put up the games you’ve created as well. For now, though, please contact me if you’d like to take part.
I’ll continue writing this tutorial for as long as I have ideas — and I hope you’ll join me.
Wrapping Up
Perhaps garbage collection wasn’t the most fun topic to end on, but I hope you can see how important it is. Using a while loop when removing objects from an array is also a useful tip to remember.
As always, you can grab a zip file with all the files relating to this part of the tutorial here.
Thank you very much for reading this tutorial, and for all the comments, emails, and kind words regarding it. I really appreciate it all


{ 267 comments… read them below or add one }
← Previous Comments
Next Comments →
Hey Doom
Hmm. For the first problem, you’ll need to find out which line is causing the error. Check out the debugging guide for help with that.
For the second part, it sounds like it’s not saving the values to the SharedObject correctly. What does your SharedObject code look like?
Sorry that this has happened right near the end
But you will be able to fix it
(And in the future, I recommend using Git
)
Hello
public function setFinalScore( scoreValue:Number ):void { finalScore.text = scoreValue.toString(); try { if ( sharedObject.data.bestScore == null ) { sharedObject.data.bestScore = scoreValue; } else if ( scoreValue > sharedObject.data.bestScore ) { sharedObject.data.bestScore = scoreValue; } bestScore.text = sharedObject.data.bestScore.toString(); sharedObject.flush(); } catch ( sharedObjectsError:Error ) { trace( "Caught this error:", sharedObjectsError.name, sharedObjectsError.message ); bestScore.text = "???"; } }That’s the code for the SharedObject.
About the first problem (the error spamming) I solved it now ( i took a 2nd look at it right now). It was due to the “clockDisplay” that i didn’t know how to define it really. I thought it was “public var clockDisplay:Clock;” since “clockDisplay” is the instance name of the movieClip “Clock”. But then I tried “public var clockDisplay:MovieClip;” and now everything works :3 (except saving my SharedObject ofcourse
(and yes I can see why Git could be useful..
)
I have a problem with my game.
Sometimes it works fine but most of the times it just stops when you hit an enemy without showing de game over screen.
Also the score doesn’t work properly, it jumps numbers and goes back to 0.
Sorry for my bad english.
@Jucru , about the scores, it might be something like me, I didn’t embedd the fonts at first, and it was doing exactly the same thing, and I didn’t check the box saying I wanted to embedd the numbers for this font. If you haven’t done it, give it a try, and if it doesn’t work…well don’t really know :/
@Doom: Glad you fixed the first bug
This SharedObject one is odd. Is it giving you an error, and setting the bestScore text to “???”? If not, are you resetting the best score anywhere?
@Jucru: Check out the debugging guide to narrow down your problem. This will help when trying to solve it.
@Kcrik: Thanks for helping Jucru out
Good advice.
@Michael.
I’m working on a pacman-like game, so using Tiles, Tiled (map editor), BitmapDatas, etc…
.
?
I will write a tutorial about how to make this kinda of game because I have implemented my own Per Pixel collision, raycast collision, A* pathfinder, etc… I had to go through them and understand those stuff, and It’s not that easy and could help many people to have a clear and not barbarian mathematical explanations about them
So I thought about writing a tutorial about my game since I use them there and I was wondering if you’d have time, when it’s done, to have a look at it, to see if it’s ok to understand
I’m a programmer, so it would be much more programmer-oriented
Hey Kcrik,
Sounds like a cool tutorial! Sure, I’ll take a look (though I’m very busy at the moment). Where are you planning to publish it? We might be interested over at Activetuts+, if you haven’t got a site in mind…
@Kcrik: Thaaattt fixed my game!
Sos groso, sabelo!
I got all the way through the base level tutorials and got to the “uncheck automatically declare stage instances” part. I handled the gameClock:Clock issue as described in the tutorial but got the following error:
1119: Access of possibly undefined property levelDisplayText through a reference with static type Classes:LevelDisplay.
1119: Access of possibly undefined property levelDisplayText through a reference with static type Classes:LevelDisplay.
Now, levelDisplayNumber is an instance of the LevelDisplay class which I created. My plan was to modify tutorial #10 (Multiple Levels) where the background is changed as you progress. Instead, as you complete a level, a text field pops up and states what level the player is now on. My method was to create the LevelDisplay field which was modeled off of the Avatar class – it’s really an empty class for the most part. An associated MovieClip contains two text fields. One for “Level” (with instance levelDisplayText) and the other for the level number (with instance levelDisplayNumber) which is being pulled from the LevelData class into the AvoiderGame class. I pop the text in when a new level is reached and then fade it out.
Here is some related code from the AvoiderGame class if it helps further explain my problem. From within onTick:
if ( gameScore.currentValue >= currentLevelData.pointsToReachNextLevel ) { currentLevelData = new LevelData( currentLevelData.levelNum + 1 );Imported in AvoiderGame:
import flash.text.TextField;Declared class variables in AvoiderGame:
public var currentLevelData:LevelData; public var levelCounter:Number; public var alphaValNumber:Number; public var alphaValText:Number; public var gameClock:Clock; public var levelDisplay:LevelDisplay;In AvoiderGame function (before onTick):
levelDisplay = new LevelDisplay(); addChild(levelDisplay); levelDisplay.x = 130; levelDisplay.y = 100; //levelDisplay.visible = false; levelDisplay.levelDisplayText.text = "Level"; //note: alpha doesn't work on TEXT FIELDS unless the text is embedded in the main document! levelDisplay.levelDisplayText.alpha = 0; levelDisplay.levelDisplayNumber.text = "01"; levelDisplay.levelDisplayNumber.alpha = 0;If anyone can help, I’d really appreciate it. I’m so close completing the base tutorials.
I can upload or email the fla also.
Thanks
Sorry I got some things confused in my last post.
The second error should be for levelDisplayNumber not levelDisplayText (levelDisplayText was the first error)
levelDisplay is the instance of the levelDisplay class
I couldn’t find the button to edit posts so sorry again.
@Michael : Actually I have got a friend who’s a game designer and making a website for people to store their code and have the opportunity to have professional looking at their code. He told me he would like to put the tutorial on his website.
, quite hard to do
.
I have almost completed the code, but it’s massive, and I have to write it, keeping in mind, people who are not programmer might read it
@Rootzm : It would be much easier to fix your probem if you upload your fla
@Rootzm
The solution should be to add the following inside your LevelDisplay class:
public var levelDisplayText:TextField;
Whatever is on your stage has to be declared manually like that within all of your classes, as explained above in Michael’s tutorial.
http://www.box.net/shared/ivt6hf33oj
That is the link to my fla zip. Let me know if it doesn’t work. And enjoy the newbie code commenting =-)
Hey Rootzm,
I think I have fixed your issue. I don’t have any compilation error about that any way, but Don’t you have a problem in Game Over screen as well ?
I have got a bigger problem, none of your button works, I get the same error on every dynamic text or button through the game when I compile :/
I don’t know if it’s because I’m on CS5 and you CS4, but if you try to comment the lines where you get the errors, and you get the same problem, in GameOverScreen, MainMenu, etc… then it’s a deeper problem
But something which is true is : don’t use alpha on text, since you want to fade in/out the MovieClip that contains the level text and level number text, just use the alpha of the MovieClip itself
I think you shouldn’t access the dynamic text of LevelDisplay this way, I’m not sure, but I think it’s declared as a private attribute by Flash, so use this kind of stuff, it’s safer and well I think better ^_^ :
public function setLevelNumber(levelNb:String):void { levelDisplayNumber.text = levelNb; }I have edited the code where you put the alpha on your text and change them from :
(I think you should set up properly the levelDisplay object before adding it as a child)
levelDisplay = new LevelDisplay(); addChild(levelDisplay); levelDisplay.x = 130; levelDisplay.y = 100; //levelDisplay.visible = false; levelDisplay.levelDisplayText.text = "Level"; //note: alpha doesn't work on TEXT FIELDS unless the text is embedded in the main document! levelDisplay.levelDisplayText.alpha = 0; levelDisplay.levelDisplayNumber.text = "01"; levelDisplay.levelDisplayNumber.alpha = 0;to :
levelDisplay = new LevelDisplay(); levelDisplay.x = 130; levelDisplay.y = 100; levelDisplay.visible = false; levelDisplay.setLevelText("Level"); levelDisplay.setLevelNumber("01"); levelDisplay.alpha = 0; addChild(levelDisplay);Unfortunately I can't go further since I dunno if it's something wrong with my Flash
Try to comment the lines where you get errors, and let me know if you get errors in GameOverScreen as well
@Rootzm: Your LevelDisplay variables don’t exist. It’s a relatively simple fix:
Do the same thing for all other stage instances. Remember that you’re manually declaring them now, Flash used to automatically do this for you within each of your classes.
Thanks for checking my errors Kcrik. I should be able to try your suggestions later today.
Seems like I tried to make the MovieClip’s alpha modifiable instead of the text/number fields inside the MovieClip and it failed. That may have been before I discovered that text fonts had to be embedded. It sounds like it works after embedding based on your response.
I’m hoping the GameOverScreen issue is just a version difference – I am using CS3. The only error I got initially was for the LevelDisplay class stuff. I have noticed though that Flash doesn’t show all error sometimes. It seems to give you one set to fix and then after those are taken care of, it shows you what else you’ve goofed on.Either way, weird errors since I figured it would just require declaring variables somewhere in the code since it worked just fine in the Flash environment with the box checked.
Thanks again. I’ll post what happened here when I get a chance to test.
Thank you for your help Kcrick. I figured it out. I changed the alpha process as you described and it works well.
After that, all my other problems were just declaring more public class variables for TextFields, MovieClips, SimpleButtons, etc. That’s why my GameOverScreen was freaking out. It wanted publically declared button variables such as ‘public var returnToMainMenu:SimpleButton;’ There were a couple odd ball ones that I had to review MJW’s tutorial fla file like ‘public var clockDisplay:MovieClip;’ in the clock class file. I had it as clockDisplay:Clock for awhile until MJW’s file showed me my silliness.
Thanks again.
Also – haven’t formally said it yet so THANK YOU so much MJW for a exceptional set of tutorials for AS3 game programming. I really hope you continue to add more at some point in the future.
Glad I was of any help
That’s cool you made it work eventually
You still have plenty of tutorials out there, check out the ones on http://www.retrohello.com/
Have fun !
@Dan,
Do you know why he needs to do that, because I have dynamic textField in my game, and I don’t need to declare them, I can access them directly in my classes. Is it because I am using Flash CS5 ?
We’ve turned off ‘Automatically declare stage instances’ in the publish settings. Michael explains in his tutorial that his IDE inserts the import statements for him in his classes so that there’s no need for Flash to automatically declare them.
On a side note, I’ve read somewhere that automatic declaration only occurs during runtime, so anything that requires a reference at compile time won’t work (e.g. Flex objects). So it’s better to do manual declaration and prevent this problem.
CS5 should have a similar setting as described in their help docs: http://help.adobe.com/en_US/flash/cs/using/WS3e7c64e37a1d85e1e229110db38dec34-7fa4a.html
Just uploaded my version!!! YAY learned alot!
http://www.kongregate.com/games/Narinik/nariniks-avoider-game
I’m back from holiday!
@Kcrik: Is your tut online now? Can I see it?
@Kcrick, Dan: Great advice for Rootzm! Sounds like it’s all sorted out now, right? And Dan, good explanation of what the issue was. I’ve run into that problem with Flex objects before, very frustrating.
@Narinik: Fantastic, congratulations!! I love the comments between levels
Hey Michael,
It’s not ready yet…since I’m still working on the game itself. I’m refactoring some part of the code
.
I am wondering if I should write the tutorial and assuming people aren’t programmers at all. I thought about it, and doing so is going be a real pain, because it will lead me to explain every single line of code, from the point of view of some one who doesn’t know anything about it.
It would be a lot of work to do it this way…would be great though
I am think of releasing a first version for people with some base in programming, then do something much deeper for people who haven’t got any previous programming skills.
If you’d see the code ( you will
), the code is mad, so many classes. I am using Tiled map software, so I’ll have to explain it quickly as well
. I will give all bases for people to add easily stuff. But won’t be too generous either, Hey they have to work out some stuff as well
At the moment, the game has got a menu, credits ( Haha
), controls, and pause menu. A game over and victory screen. The in-game itself, you can play through 4 levels, with particles 
I will have a separate module that manage the sounds, and one which manages the controls (keyboard, mouse).
The tutorial will be :
(I say if I’m nice since it took me a lot of time to test particles, etc.. to have the game running smoothly).
-How to load a level
-Manipulate Bitmap and BitmapDatas
-Controls of pacman, basic AI for ghosts
-Objects and Fruits in the game
-Particle system => Maybe if I’m nice
So I think a solid tutorial to let people create games with tiles, like Bomberman, Boulder dash (old game I know), Tetris, etc…
Wow, sounds like it’s really detailed! Should be very useful, please send me a link when it’s done
I think your idea of starting with a version aimed at people with some programming experience is smart. I’ve found it’s very difficult to write a tutorial aimed at everyone.
I was thinking of a version for people with no previous programming Xp skills, because a couple of artist friends want to learn it, and they don’t know anything about code
I don’t have any website at the moment (need to rewrite one, but programmer = lazy…
), so it will end up on this website probably
I can write how to load the maze at the moment, and display it obviously
, I will have a GameObjectManager and CharacterManager. I had the code for managing objects and characters in my In-game class before, and thought, well I could do it better
Do you think it’s ok to write one tutorial by one. Like since I can write how to load the maze, to write this one, then finish the stuff with managers, then write how to load objects and characters. etc… ?
My approach was to fully write my game, then when I’m statisfied, I write the tutorials since I won’t change anything to the code.
Either way works, just avoid aiming for both audiences, I say.
Writing it in a modular fashion like that can be useful, yeah, because it means each tutorial has a clear learning outcome. Make sure you don’t try so hard to do it in a logical order that the game itself can’t be played until near the end!
Good call on writing all the code first, then explaining it. Personally, I find I like to mess with the code, though, so I would find it hard to leave it alone!
Do you know a way to let an object being able to add an event listener to itself, and to avoid having this object inherith from MovieClip ?
Actually, yes. An object that you can attach an event listener to is called an event dispatcher, and should implement the interface
IEventDispatcher. (Don’t worry if you haven’t come across interfaces yet.)The easiest way to do this is to make the object’s class extend
flash.events.EventDispatcher. But if this is not possible, then check out this method: Implementing IEventDispatcher.@Kcrik: Michael’s tutorials were structured very well, in that each section had a goal with a satisfying result at the end. Even each section had sub-sections where one could stop, analyze, and easily pick up from later. Gonna use the soccer/football metaphor again; teach your students to kick the ball, have fun with it, then teach them the rules of the game.
@Michael: Enjoyed your tutorials immensely, it’s a great way to get back into OOP and have fun with it. I came across a lot of the problems that others had in the comments and shared my solutions. About the metaphor usage, I’d say your explanations are fairly sufficient and the commentary section supplement the rest. Sometimes less is more.
Thanks Michael, I’ll try it, but I’m pretty sure I already tried to use this interface in another part of my code. We’ll see
.
Haha, I am not newbie in programming actually
, I have been working in video games, as a programmer, for 2 years
. (and 6 years at Uni….4 years bachelor’s degree, yeah I wanted to redo my 1st year to be sure I got every thing right
, then 2 years Master’s degree => a master is 2 years in France).
My game is pure OOP
, I think I will use use Singleton and Strategy design pattern.
By The Way, I tried to play around with the Z coordinate, but it’s only in 2D my game, and I have to say, in 2D, that’s quite bad using Z coordinate. I got blury stuff, like I wanted a text in front of my labyrinth, using the z, and it was blury….so my solution was to add the text to the children of the class, and have it added before the Bitmap that contains my labyrinth graphics.
Any idea why it was blury ? In 3D, it doesn’t do it..
@Dan: Thanks! That is a really great metaphor, starting with kicking the ball and having fun rather than going over all the rules first. It’s a sentiment I try to follow.
And yeah, the comments are the best thing about blog-based tutorials. Lots of great discussion, lots of people helping each other out.
@Kcrick: Oh, haha, sorry, I just assumed you were new. Oops. Sounds like you’re actually more qualified than I am
I haven’t experimented with Flash’s built-in 3D stuff yet, so I’m not sure what’s causing the problem. Have you tried Away3D or Papervision3D, out of interest?
Heheh no problem. I doubt I’m more qualified than you
, I’m just 25 years old
I haven’t tried them out…yet.
I will give them a try later on. I need to finish this game first, then write the tutorials
!!
Just published my second game! and its an avoider, with guns! I built it using what I learned from this tut, plus maybe one or two others. Thanks again MJW!
http://www.kongregate.com/games/Narinik/pew-pew-space-edition
Thanks for your all tutorials. I’ve founded a lot of usefull information. Thanks a lot for great tutorials. You are cool man.
I’m having a problem with the code line
whenever I put it in the DocumentClass constructor, it gives me this:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at DocumentClass()
Not entirely sure what I’m missing, and I haven’t seen anybody else with similar problems. Thanks in advance.
So after downloading the zip on part 12 the scoring is all messed up it looks like it keeps reseting itself and does not always appear in the game over screen. Im running Cs5, just thought Id let you know
Thank you man! I’Am from Argentina and I start the Spanish avoider game tutorial but it just finish at the 5 part so I continue this. You know how to teach, telling the necesary and saying where you can read more if you want, that intresting for not tiring reading and learning about the thing we want.
Again, I say thanks to you!
I have been coding in AS3 for a couple of years now, purely for my own amusement, and the Avoider tutorials have really clarified areas of AS3 that I may have used but have not previously fully understood, so thanks!
I have been trying to think of an improvement (or even just a different way of doing things) for the Avoider game and I think there is something that no-one else has suggested…
Another way of managing the garbage collection of the enemies is to ‘reuse’ them; instead of removing them when they disappear off the bottom of the stage, they can be ‘reconstituted’ by setting their y value to a point above the the stage, and their x value to a provide new random horizontal point. This gives the illusion of endless enemies when, in fact, they are just being looped around the screen. Once the required number of enemies has been added to the level, there is no need to add any more.
As I say, it’s not an improvement; just a different way of doing things. Your readers might like to consider how this technique could be used for effects such as moving starfields and snow, etc.
Actually Innes, I consider it as an improvement. Since the CPU won’t have to recreate an Enemy object all the time, but just change 2 int variables, that’s much better for the CPU.
Another thing to improve the game is to use Vector instead of an array to store the enemies, I explain below :
you know the type of the objects are Enemy, you can’t, with array, specify the type of objects inside, so use a Vector and declare it this way :
var army:Vector. = new Vector.();
Vectors objects are optimized, much faster than regular arrays, and you don’t need to cast the objects when getting them, since you know the type already. (You can use Vector without casting though
)
For programmers, it will look like Java Vector declaration, for others, hehe just take it for granted
Blamey, the code didn’t print properly :
var army:Vector.”" = new Vector.”"()
if you see the quotes, they are useless, but I’m trying to write the code, if it still doesn’t write it properly, then after “var army:Vector.”, you are supposed to have the sign “less than” Enemy “greater than” , and same next to the second Vector.
Hey Michael … Great tutorial! I followed all your steps and have successfully recreated the game. Thank you for being so thorough with you explanations, I needed it.
Keep up the great work!
…one ? though… my preloadeder still doesn’t show up at first, and is only starting at around 30. How can i get it to start it from the beginning?
Hello, how can i check if two arrays “colliding”? Example: i have an array for bullets, and an another for enemies and i want to check if any bullet colliding with any enemy.
(sorry for bad english^^)
Thanks for the tutorial. A great way to learn AS3 when switching from another language
.
Instead of the while loop I do something like:
for(var i = 0; i < array.length; i++) { if(array[i] needs to be removed) { array[i] = null; i--; } }TypeError: Error #1009: Cannot access a property or method of a null object reference. at LoadingProgress/updateDisplay() at Counter/reset() at Counter$iinit() at LoadingProgress$iinit() at DocumentClass$iinit()Matyi ->
You don’t have much choice, you need to loop through the first array, then while looping through the first array, you loop for the second one too and check the collision :/
//enemyArray;
//bulletArray;
var enemyObj:Enemy;
var bulletObj:Bullet;
var enemyArrayLength:int = enemyArray.length;
varbulletArrayLength:int = bulletArray.length;
for (var indexEnemy :int = 0; indexEnemy < enemyArrayLength; indexEnemy++)
{
enemyObj = enemyArray[indexEnemy ];
for (var objectIndex:int = 0; objectIndex < enemyArrayLength; objectIndex++)
{
bulletObj = bulletArray[objectIndex];
// Check Collision
if (enemyObj .collide(bulletObj ))
{
// TODO
}
}
}
← Previous Comments
Next Comments →
{ 1 trackback }