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 →
Hi,
I created games in C and VB 6. I always wanted to create web based games. Your tutorial is so great to get started with. I know a lot about programming and now I know a lot about AS3 just by reading your tutorial.. Thanks…!
It is well structured and reads verry fluent. Especialy with the jokes in between.
great job!.
Hey, sorry it’s taken me so long to reply to all these comments — I’ve been unexpectedly without Internet for a while.
@stella: Have you tried creating a new Screen for your movie clip and using the same method you use for the MenuScreen, PlayScreen (etc) to play it in the right place?
@OldGameProgrammer: Hey, I used to be a VB6 programmer! Thanks so much for your kind words
Glad you liked the lame jokes, haa.
Aha! Finally, I am finished!
Thank you for this wonderful tutorial mate, I will now begin customising this game
Awesome, congrats Sean, and thanks
You should mention one damn important thing:
Calling removeChild() within the child that needs to be removed WONT work, no matter how hard you try!
Best regards
Cannot edit any longer :/
So well, heres the code thats buggy.
while(i2 > -1) { anotherpop = pops[i2]; if(anotherpop.existTime > (60/stage.frameRate)*3) { // only if Document Class is valid parent if(anotherpop.parent == this) { anotherpop.cacheAsBitmap = false; removeChild(anotherpop); } else { // else it is child of the inter_face.trace(anotherpop) gives me out -> [Object Pop] even though its used to be removed….
Im building a massive game, so I have to hog any bit of performance I get, and this is a major issue that I cannot ignore, because a Pop gets created anytime an enemy dies, and there are lots…. lots of enemies…
Aswell using removeChild() on the enemies themselves doesnt work properly, and I truly aint got a damn single clue why…
Besides that, the tracing gives me out, the object is still there, BUT I cannot acces any read-only properties of that object, neither is it visible (I tried without splicing to proof my theory).
Hope someone can help me out.
Best regards
Michael,
Finally I got through all the tutorials… The result: starting from scratch, I learnt quite a lot, quite fast! I’m sure I’ll get plenty of profit out of this tutorial in future programming!
Thank you!!! … for your easy and clear way of setting things up, explaining them, making them funny and interesting, …
But (off course, what would you’ve expected…) I also have one remark/idea:
Since you’ve written a manual which is great for newbies, it would have been a nice finishing touch to MASK the game area (so we cannot see enemy’s outside the playfield). A very simple thing, but for a total newbie it might be fast result and fun!
And another thing I’d like to share with you: I don’t remember in which tutorial it was, but you asked us for an easy way to untick all the “Export to frame 1″ boxes of all our MovieClips in the Library at once…
Well: in case you did not find out yourself yet, here is a small tutorial, for you this time:
- Open your library
- Using the buttons SHIFT and CONTROL, select all the library-items you want to change, make sure the ones you don’t want to change are not selected
- RightClick one of the selected Library-Items and choose “Properties” in the pop-up menu
- Now you’ll see all the common properties of the selected items. And you can simply change them. You only have to tick the boxes of which you want the values changed and set the value you want it to be changed to.
E.g.: tick the box next to “Export to frame 1″ and then set the value next to it to “No”.
- Now click “OK” and the changes will have effect on all your previously selected library-items
(I am using CS4, so it might differ a little with older versions, but the principle should be the same I guess…)
Finally: Keep up the good work! I’m sure you paved the way to flash for a lot of interested people…
@default0: Not sure why removeChild() wouldn’t be working — how about trying this:
if ( anotherpop.parent != null )
{
anotherpop.parent.removeChild( anotherpop );
}
But successfully removeChild()-ing the object won't alter the output of
trace( removepop )! The variableremovepopis still pointing at the actual object, and the actual object still exists; it's just not on the screen any more. You'll have to makeanotherpoppoint to something else for that -- likeanotherpop = null;@Bert: Wow thanks Bert!
Masking is a good idea, yeah. Perhaps I'll write a small add-on tutorial for that. (Have you seen the additional avoider game tutorials? They're all up on avoidergame.com.) Or alternatively... would you be interested in writing something about it?
Oooh that tip for changing all the properties of all those objects at once is extremely useful. Thank you for that! I will add it in to the tutorial. (Sadly it doesn't work in CS3, but I seem to be the only person still using that anyway
)
Please keep me updated with what you get up to
Too lazy to login.
(Sadly it doesn’t work in CS3, but I seem to be the only person still using that anyway
)
Is what you said, but Im saying: Im using CS3, too, and I actually dont think CS4 is better as the whole interface of it sucks, thats why I took CS3
Best regards
Damn, I just did what you said (using anotherpop = null, same for the enemies) but the lagging just wont stop…. >.<
Its truly annoying, might help if I share my document class and you can take a look at it (Document class is the code where I remove just anything):
Download it
Besides that I wanna mention that I try to build something similar to Bloons Tower Defense, and if you know this game, then you also know why I need to be very careful with my performance
Hey default0,
Ha, OK, so two of us are using CS3
The CS5 public beta will be out soon, are you going to check it out?
I took a look at your code but it is a little too much for me to absorb it all. Since you’re making something complex (yep, I’ve played Bloons TD!) I’d recommend you read up on optimisation.
A great introduction is this talk by Grant Skinner (use left and right arrow keys to move through it). It’s all worth reading, but the stuff I think you’ll find the most immediately useful starts at slide #37.
Thanks for the Link
I wont check CS5 out, Ill wait till its public and then maybe get it, lets see.
But after all, this wont help my problem, even though I must admit that this is REALLY helpful for optimization and stuff
Still, it aint that hard to understand all that code, I might explain it now:
Well, Im having two arrays, one for bloon color and the other for the waves
From those Arrays I create the enemies (how exactly aint important) calling the “spawn” function.
So, for creating and removing all the functions that are required are:
spawn()
spawnAt()
removeEnemy()
and in onTick() I come to remove the “pops”, that appear everytime removeEnemy() gets called.
A little more exact:
spawn() pulls in totally new enemies
spawnAt() pulls in enemies spawned by other enemies
removeEnemy() removes enemies and pulls in pops and calls the spawnAt() function
removeBullet() removes Bullets
onTick() removes Pops, handles turret aiming and other stuff
Best regards
Hmm. Well OK, let’s narrow it down another way. Is it lagging after a certain amount of time, or a certain amount of enemies? Or is it bullets that’s affecting it? If you stop spawning new enemies after a few minutes, does the lag eventually go away? Experiment, see what you find
Sorry, dont have the SWF on this computer, but it are the enemies, cuz the more enemies appear each wave, the faster it laggs and becomes slow, so I guess either the enemies or the pops cause this problem….
EDIT: Another thing that makes this sound right is the fact that in higher waves it laggs more and faster
E.g. I play the last 3 waves, the last of those waves laggs, but if I play all waves, it runs perfectly in the first waves, only later, when more enemies appear each wave, the lagging starts
Best regards
OK, sounds like you’re getting somewhere. So is it due to the number of enemies in the current wave, or the total number of enemies that have been created so far through the whole game?
Last thing, the total amount.
Starting at wave 12 means that wave 12 wont lagg, wave 13 e.g. will lagg a little, if I start from wave 0, wave 12 will lagg quite much, and waves 13+ are just horrible.
Beside that, now your time theory might pop up, but I dont think so, once I had to go to breakfast, returned, no lagging, but after a while of playing, the game started to lagg again…
Best regards
Nicely narrowed down
Well, I’m pretty stumped, to be honest. Hrm, OK, another test: is it possibly due to the total number of waves rather than enemies? I mean, is there something that happens between waves that could be contributing to the lag?
You could test this by adding new arrays
numberOfEnemies[1][3],numberOfEnemies[1][4]and so on, I think.Nope, thats not it, exactly as I though it MUST be the Pops and/or enemies….
I dont think the bullets could cause such a huge slowdown, because there just arent enough of them….
Still any clues?
EDIT: Just to be sure, I made it up to numberOfEnemies[1][8] I guess this was enough to test it….
Best regards
Sounds like you’re right. I just don’t understand it; why would the total number of enemies created over the length of the game have that big an effect? You’ve got rid of the arrays and there are no event listeners (as far as I can tell), so I would expect them to be garbage collected at some point.
Perhaps my understanding of what exactly is going on “under the hood” is incorrect.
Well, I have an idea for a fix. Have you heard of “object pooling”?
Maybe youll have a look at them, maybe not, but anyway heres the rest of my sources (excluding FLA): Download ‘em
If you have questions, feel free to ask me, but maybe youll find the reason (or maybe not), but still you made me curious: What the heck is object pooling?
Best regards
Don’t really have time to look through those right now, but yeah object pooling might sort it anyway, so that’s worth a try.
The basic idea is that you don’t remove objects (enemies, in this case) once you’re finished with them, you just stop them from doing anything. Then, the next time you need a new enemy, you re-use one of the old ones that aren’t doing anything.
So, for example, you could give all your enemies a
deactivate()function that stops them doing any of their animations and so on, and anactivate()function that starts up the animations again.Then, when you want to remove an enemy, you remove it from your main “army” array, and add it to a different “reserve” array.
Whenever you need a new enemy, you first check to see whether there are any available in the “reserve” array — if so, you call
activate()on it, move it to wherever it needs to be, remove it from the “reserve” array, and put it back in the “army” array.(If there’s nothing in the “reserve” array, you just create a new Enemy in the same way as you’re doing now.)
Make sense?
Nice concept.
Ill try that out
Thanks for the tip
Best regards
Damn I was mistaken, the game still loses performance, but far less than before….
Best regards
Hm, how’s it behaving now?
Yeah, it was my fault…
I jus forgot to pool the bullets, pops AND enemies, before I only pooled pops and enemies.
Now that I also pool bullets, anythings fine
Best regards
Oh wow, that’s great to hear! Congrats
Still, the game laggs, but thats not cuz the number of total, but because of the number of active enemies (which was about 500 by the way
).
Still, its great to have done a game like that, actually the game ain’t really done yet, Im missing a menu and the level editor =D
Best regards
Wow, 500 — I’m not surprised it lags. (You could try blitting to get around that.)
What’re you going to do when the game’s done? Put it on FGL?
Pretty much nothing, this was just kinda trial for me to show that Im able to create massive games that wont lag too much (and to get a free level editor for Bloons TD4 ^^) =D
To the blitting, actually Im using multi-colored circles, cached as bitmaps, no animations, so this wont help any (since Im only moving, not changing the circles, the renderer has to do the same, as if they were bitmaps copied by code).
In fact I guess it is, that I let ANY bullet and ANY turret go through the array of ALL active enemies EACH FRAME, causing (at 500 enemies, and say, 10 bullets + 5 Turrets), a total of 7500 loops each frame, thats quite a lot and owns pretty much any not high-end machine.
I guess changing this is easy anyway, just force the bullet to check which enemies are close and then cycle only through them, instead of directly doing a hittest with any enemy.
For the turrets, I also only need to get the target in the moment they shoot, those two optimizations would reduce lag awesomely
But thanks anyway.
EDIT: Tested the suggestions out just now – no lagg any longer =D
Best regards
No lag at all! Wow, awesome
What’s next?
Next is editor and extra stuff (difficulty settings, e.g.).
After finishing the whole game I will move on to my last game (kinda tribute) to ActionScript 2.
Im working on several games simultaneously (8, actually 7 since one of them is in Visual Basic 6), but if I would change that, I would get bored as hell, so as a cause of that, each game will evolve kinda slow =D
Best regards
Wow, OK! Lots of plates spinning
Since AS files do not work faster as coding on the time line, I still prefer to simply code on different layers in the .fla.
At least I understand AS files, so thanks for that. But a lot of things were very inefficient, like, using number all the time were you could also use int, use “Timer” stuff, instead of “ENTER_FRAME”…… IDK, decent tutorial. Not bad, not good.
Hey!
Just wanted to say thank you again, for the great tutorials! I actually just finished my first game! Here’s a link if you want to check it out!
http://www.kongregate.com/games/Kreg/falling-debris
Although it’s pretty different from yours, I did use these tutorials as my main guide for a lot of the functionality. Thanks again!
Also, I went ahead and recommended your site (I do that quite often actually, but this was a lot more formally
) to anyone learning actionscript, in a topic a friend and I made on how to succeed in a collaboration. There were quite a few people that helped out (beta testing, helping me out with coding difficulties, artwork suggestions, etc), so we didn’t put up a thanks page directly on the game. We instead used the collab board. Here is a link to that as well.
http://www.kongregate.com/forums/8-collaborations/topics/68427-falling-debris-a-successfull-collab
Again, thanks for the incredible effort you put into these tutorials! I can honestly say this has been my most valuable resource in beginning to learn to code.
-Craig
P.S.
I hope this isn’t a bad place to post this… I wasn’t sure really where to put it. I figured the end of the tutorials would be appropriate but let me know if not!
Hey Michael!
I got through your tutorial and am genuinely pleased with myself. I’ve started trying my own stuff out and was wondering if you could help me with a few points.
First off, my game stars a biker riding in a hailstorm, dodging the falling hail. It looks pretty good, and I had this cool idea to have clouds slowly lower down the screen, obscuring the upper portion and making it harder to dodge the hail.
Made my clouds, and they look great, but they don’t obscure the hail. I think the hail is on a layer over the clouds, but I only know how to change the layer order on the actual time-line, and they are different objects wit different time-lines.
Basically I’m asking how to force the hail to spawn underneath the clouds.
Please let me know If there is a better place to put these questions, I took a cursory look around the site but did not see any forum or anything like that.
I have other quandaries but cant think of them at the moment, I’m tired.
Thanks for your help, as always,
-Bruce!
I would solve it this way:
Create two layers (not on the timeline, two empty MovieClips), and as you create them, you code like that:
And now, when you create the hail, you do so
Alternatively, you could use addChildAt(), but Im too lazy to explain this now =D
Oh well, and on the clouds layer, you obviously have to put yer clouds
Best regards
Hey I hate to sound ungrateful, and even more so I hate to sound like a noobie, but that did not explain it well enough for me to understand.
could you explain the first part of that a bit better?
Also, I’ve been looking for solutions elsewhere and they all mention the addChildAt() thing, but they don’t explain it at all. If you could explain it that would be great, but if not, even an expansion of your previous answer would be great.
Thanks!
-Bruce
Kay, choosing an expansion of my previous answer.
Ok, lets explain it step by step
1st: Create two new MovieClips, linked to two empty classes (call them “HailLayer” and “CloudLayer”, that do nothing, except existing).
2nd: In one of the MovieClips, you put your clouds, the other one stays empty
3rd: Then, in the code, you create those MovieClips (variable names like classes, without the first capital letter, I guess you know how to do that).
4th: After creating them (best is directly after), you add those lines of code:
This code sets the cloudLayer above the hailLayer.
And now, each time you create a hail particle, you call “addChild(hail)”, right?
Well, change this to “hailLayer.addChild(hail)”.
Done. Now you have two layers, one containing the clouds, one the hail. The cloud layer is above, and so, any Child of the “hailLayer” cannot be over the clouds, since the whole layer is under them.
Oh well, above I kinda rushed through it, dont worry about not understanding it
EDIT: If you like to, I could just create you a small minigame in which you have to dodge the hail, some clouds that are over the hail, to make it harder to detect, etc. Thats not much work for me, as Im a freak, yes, thats true
Best regards
Argh I cannot get this to work.
Okay, so I made the two classes, named like you said, HailLayer, and CloudLayer. I did not understand what you meant when you said to put the clouds in one of the movieclips, the clouds are currently being add-childed in the same way as an enemy. (separate from enemies of course)
I had my AvoiderGame class create the Layers, which is what i think you mean by “in the code”.
Then I put in those two lines of code in the avoider games constructor function, which did not work, So I put tried putting them in the Layer’s respective constructor functions, but it still did not work.
It says its calling them to a possible undefined thingamabob.
I’m fed up at the moment, so I commented out everything so it would work again, and have decided to work on it more later, when I have cooled down.
Thanks for your quick reply’s to my questions, and your help. Sorry I’m not being easier to work with, but I think if you told me exactly where to put the code, I would do better.
Again, thanks,
-Bruce.
Okay, Ill make your things clearer
If you “addChild” the clouds, then always, when you addChild() a cloud, you simply have to use “cloudLayer.addChild(cloud);” instead of simply “addChild(cloud);”
Have you put the lines (with the “setChildIndex”) below the lines, where you create the layers?
If not, it cannot work.
And get them outta the constructor functions in the classes, thats not where they belong
Hope you finally understand it
Like always, best regards
Hi all,
This is my version of the game. I also tested mochiadds instead of the preloader.
http://games.mochiads.com/c/g/avoid-game/avoidGame.swf
kind regards
Um… somehow I missed a bunch of comments. Sorry!
@Vexagon: Ack! Mediocrity! The worst possible review
Cheers for your opinions, I appreciate them. I disagree with you on timeline coding being just as fast as using AS files, though; although timeline code may run as fast as code in AS files, that doesn’t make it a faster way of programming.
And yeah, this is definitely underoptimised. Perhaps I should make it more obvious that this is to teach the basics rather than how to write perfect code?
@default0: Cheers for helping out again! It’s so awesome to pop by and see that
@Bruce: Did you get your problem sorted in the end? If not, you may want to check out this tutorial: Add Depth to Your Game with Parallax Scrolling. It’ll show you how to create different layers within your game, so you can add the clouds on a higher layer to everything else.
Also, take a look at Understanding Flash’s Coordinate Systems for a more in-depth article on the technical side of addChild().
@OldGameProgrammer: Thanks for sharing! Looks cool, I really like your clean graphics
I managed to get 2010 points, yay me
Did you ever find out what was up with the fonts?
Hey Michael, thanks for letting me know about that, I haven’t done anything flash related for a few days, since I got fed up last time, but I will check out that tutorial!
And good times were had by all,
Bruce
@Craig: Whoops, your comment was swallowed by Wordpress!
Cheers for the link to your game! It looks awesome, and I love all the little touches you added. Like, how the ship rolls from side-to-side, how it accelerates rather than just moving at a constant speed, and how the missiles don’t hurt you if they hit the flame trail. Great stuff.
Oh, and thanks so much for the shout-out over on that post! I really appreciate that
@Bruce: Whoa, fast reply
Great, well, let me know how it goes.
Hey Michael, I went through your other tutorial and I have a few questions, putting them here as a continuation of our conversation.
First off, how did you get all the hills to be behind one another? Did it just work out that way or is there some trick behind it? I want the same thing to work with my hail and clouds.
Second off, when I tried to get the trick to work with my hail and clouds, by adding the movieClips like in the scrolling tutorial and putting them in those movieClips, i got some strange output.
No compiler errors, but the output panel showed this when I clicked the start button (which did not work)
NavigationEvent
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at AvoiderGame()
at DocumentClass/onRequestStart()
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at MenuScreen/onClickStart()
NavigationEvent
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at AvoiderGame()
at DocumentClass/onRequestStart()
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at MenuScreen/onClickStart()
I have a hunch that it may have something to do with the fact that I decided to change when my playscreen becomes null. In my game, I made the gameOver screen transparent, and I liked seeing the playscreen in the background, so Instead of making it null when the avatar is hit and the game over screen pops up, I have it set to null once you click the restart button.
I don’t see how this would affect it, but then again I’m new at this and to me, anything is possible. This problem is really weird considering that what seems to make it occur is the change that I just made, putting the clouds and hail on their own movieclips, which is not connected to the start button at all.
Completely confused, thanks for any advice and help
Bruce!
Well I thought it had something to do that an embedded font can only be used in one style.
So I tried to embed it again in other style but no diffrence..
So Not yet an answer. I wich I had and if I find it I’ll share it.
Hey Bruce,
First off, how did you get all the hills to be behind one another? Did it just work out that way or is there some trick behind it? I want the same thing to work with my hail and clouds.
It’s all due to the order in which they’re added:
hillsContainer = new MovieClip();
hillsContainer.addChild( hills );
hillsContainer.addChild( hills2 );
stage.addChild( hillsContainer );
stage.addChild( roadContainer );
Inside the roadContainer, the car is on top of road2, which is on top of road1, because that’s the order they were addChild()-ed to roadContainer.
Likewise, inside the hillsContainer, hills2 is on top of hills1.
But the roads and car are on top of the hills because the roadContainer is addChild()-ed to stage after the hillsContainer. Make sense?
Not sure what’s causing your second problem; use the debugging guide to find out which exact line is causing it and let me know.
@OldGameProgrammer: good theory, cheers for sharing. Yeah I’ve no idea either… silly Flash.
Okay cool, thanks for your answer to question 1. I’m gonna try the debugging guide now
Hey Michael
By commenting out part of the code, I found the part that sets off the output error. It boops-up when I add the line:
stage.addChild( cloudLayer );
(cloudLayer is my cloud container)
Could It be the stage part that is messing it up?
Thanks again
Bruce
← Previous Comments
Next Comments →
{ 1 trackback }