Flash Tutorial Links:
Play Games: HTML5 Tutorials:

Flash Space Invaders Tutorial

The Space Invaders game is a classic hit, and involves simple controls topped up with a firing capability to own your enemies. Come on, the world needs saving!

History of Space Invaders

Space Invaders was an arcade video game that was designed by Tomohiro Nishikado and released by Taito back in the 1978. Various forms or spin offs of this kind of game emerged.

Basically, it involves the player controlling a spaceship that moves horizontally across the screen and firing missiles up at alien invaders. The aliens would come closer as time passes and eventually overrun the player. This game would be a good game to try working on now after the experience you'd gained with the first two tutorials. Again, you'll see how we can apply the framework as consistently as possible to create this new game.

Several features of the original Space Invaders were modified here so as not to inflate the tutorial. After all, it's only tutorial 3. We will not start off with all the aliens on stage and there will be no protective barriers.

Game Scenario

The player controls a space vessel moving across the planet floor. The player fires missiles up towards the alien invaders in the sky to destroy them. The alien invaders slowly advance towards the planet, and the player loses if the aliens touch the planet.

Game Details

  1. Control your space vessel with the LEFT and RIGHT keys.
  2. Press SPACEBAR to fire a missile.
  3. The alien is worth more points the farther away it is from the player.

Download the Game Files

The files you need to create this game can be downloaded from here.

Step 1 - Managing your FLA file

I used vector graphics for all the art assets in this tutorial to show you that you can actually rely on the Flash IDE itself to come up with pretty neat graphics for your game. Photoshop graphics would give you very cool raster graphics where you can tune for a particular screen size, but it's the vector graphics you design in Flash that provides the same look whenever you resize the screen.

You'll find no images in the RAW folder, but 4 MovieClips - Bullet, Enemy, GameStage and Player.

fla files

Right click on Bullet, and check the Linkage that I set. In previous tutorials, we merely linked it and gave it a name such as Bullet. Over here, I used Game.Bullet.

linkage

Previously I mentioned that all the classes for the movieclips we have on stage are usually pretty simple, hence we do not have to rely on an external .AS file to manage them. In this tutorial, I'm going to show you how we can actually use external .AS files to manage our code. If you downloaded the tutorial from the link above, you'll see that the folder Game actually contained two more files, Bullet.as and Enemy.as.

files

When we type Game.Bullet in the Linkage, what we actually do is to point Flash to this file Bullet.as which actually resides in the Game folder. The same applies to the Enemy movieclip.

So just keep in mind now that when you do a new Enemy() anyway in your code later, you're not calling the default constructor that Flash provided, but you're actually calling the constructor you have written in the file Enemy.as which resides in the Game folder.

Step 2 - Starting up the game in your GameController.as

Let's tackle the initial values that we have to set before the game begins. If you do a mental inspection of how this game works, you should be able to start typing out some of these initialization codes. In fact, you should find most of the codes familiar and natural. Let's take a look at what goes on in the startGame function.

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
public function startGame()
{
    //Create player
    player = new Player();
    player.x = C.PLAYER_START_X;
    player.y = C.PLAYER_START_Y;
    mcGameStage.addChild(player);
    
    playerScore = C.PLAYER_START_SCORE;
    
    moveX = 0;
    fireBullet = false;
    lastBulletTime = getTimer();
    
    enemies = new Array();
    bullets = new Array();
    
    mcGameStage.addEventListener(Event.ENTER_FRAME,update);
    
    //Handle event when this game is being preloaded
    addEventListener(Event.ADDED_TO_STAGE, gameAddedToStage ); 
    
    //Handle situations when this game is being run directly
    if (stage != null)
    {
        stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownHandler);
        stage.addEventListener(KeyboardEvent.KEY_UP,keyUpHandler);
    }
}

There isn't a lot of interesting new concepts here that I'd like to elaborate further. Take note that we use 2 arrays to handle the game assets during runtime, and the two arrays are referenced by the variables enemies and bullets. Do note that we need to initialise these arrays during the startGame before using them later on, else you won't be able to do any pushing of items into the arrays.

In line 62, we call the function getTimer() to get the amount of time that have passed since Flash Player started the game. The significance of why we do this will be realised later when we look at the Game Loop.

If you jumped into this tutorial without going through the first two tutorials, then you may want to head over to Tutorial 2: Pong for an explanation of lines 69 to 77.

Step 3 - Key Handlers

We listen for the spacebar key as well to see if the player is firing. The keyCode for the spacebar key is 32.

107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
private function keyDownHandler(evt:KeyboardEvent):void
{
    if (evt.keyCode == 32) //spacebar 
    {
        //Fire bullet
        fireBullet = true;
    }
    else if (evt.keyCode == 37)
    {
        //Move player left
        moveX = -1;
    }
    else if (evt.keyCode == 39)
    {
        //Move player right
        moveX = 1;
    }
}

I mentioned before that the WASD keys are probably better for controlling directional movement in a game because some browsers do not trap the keys and pass them on to the flash game well, but since most webpages are designed without horizontal scrolling these days, I'll show you how to listen for the Left and Right arrow keys. (For the full list, you can either refer to Adobe livedocs or head over to the resource on keycodes here).

Step 4 - Game Loop - User Input

And now, for the main game loop. As usual, we'll respond to the user input first.

117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
private function update(evt:Event)
{
    //******************			
    //Handle User Input
    //******************
    //Handle Player User Input
    if (moveX > 0)
    {
        if (player.x <= C.PLAYER_RIGHT_BOUND)
            player.x += C.PLAYER_SPEED;
    }
    else if (moveX < 0)
    {
        if (player.x > C.PLAYER_LEFT_BOUND)
            player.x -= C.PLAYER_SPEED;	
    }

The code above checks whether the player pressed the keys to move the space vessel. The checks in lines 125 and 130 ensures that the player does not move his space vessel off screen.

134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//Handle Firing of bullets
if (fireBullet)
{
    var currTime = getTimer();
    
    if (currTime - lastBulletTime > C.BULLET_DELAY)
    {
        lastBulletTime = currTime;
        
        var newBullet = new Bullet(player.x, player.y);
        bullets.push(newBullet);
        mcGameStage.addChild(newBullet);
    }
    
    fireBullet = false;
}

Next, we handle the firing logic for the player. We could have simply implemented this in a much easier way, that is, whenever the player presses the spacebar, we create a new bullet. But imagine how unbalanced the whole game will be (especially since we're not implementing ammunition), since a player holding down the spacebar key will be able to shoot a gazillion missiles per second (a little exaggeration here, but you get the idea).

What I did here is to limit the number of missiles the player can fire by imposing a lag time between each bullet. The constant BULLET_DELAY in the constants file C.as indicates how long the player has to wait before firing again. In the game files here, I set the delay to be 1000, which means that there is a 1 second delay between 2 consecutive missiles.

In line 137, the function getTimer() is used to get the amount of time that passed since the entire game started. This is a function which we'll see a lot of in the tutorials to come as a means of time measurement.

In line 143, this is probably something new in this tutorial you see, but if you've been programming for a while, you shouldn't be too surprised by it. The new Bullet( ... ) constructor actually takes in 2 parameters, namely the coordinates of the player.

So far, we have always relied on Flash to create the classes for the movieclips in our library, and along with it, we used the default constructors for each of these classes. In this tutorial, we will be writing our own classes for both the Bullet and the Enemy. If you'd take a quick look at the constructor of the Bullet class, you'll see that we use those parameters to set the starting position of the bullet.

7
8
9
10
11
public function Bullet(xPos:Number, yPos:Number)
{
    this.x = xPos;
    this.y = yPos;
}

For those who need a little refresher, the this keyword is a self reference back to the current object that the code is executing for. When a new bullet is created inside GameController.as, these lines of code above (lines 7 to 11) will be executed. How Flash knows that it must position this latest bullet at the specified position and not reposition all the other bullets in the game instead is because this refers to the current context, which is the latest bullet to be created.

Step 5 - Game Loop - Game Logic

Next, we move on to the actual game logic that takes place every tick of the game loop.

151
152
153
154
155
156
157
158
159
160
161
//******************
//Handle Game Logic
//******************
//Check to spawn new enemies

if (Math.random() < C.SPAWN_ENEMY_CHANCE)
{
    //Create a new enemy
    var newEnemy = new Enemy();
    enemies.push(newEnemy);
    mcGameStage.addChild(newEnemy);
}

I used a very simplified logic to spawn the aliens, similar to how it's done in the previous two tutorials. During each tick of the game loop, a random number is checked against the constant value we specified in C.as under SPAWN_ENEMY_CHANCE. Here, I set it to 0.03, but you're free to experiment with what you want by changing that value.

Once true, we create a new enemy in line 158, push it into the enemies array and add it onto the mcGameStage in line 160.

The difference here is that the constructor Enemy is no longer the default one that Flash creates for us. You may be puzzled how the game knows where to position each enemy once they spawn since we didn't specify the .x and .y coordinates this time.

To solve the mystery, let's open up Enemy.as and see what is happening there.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package Game
{
    import flash.display.MovieClip;
    
    public class Enemy extends MovieClip
    {
        private var facing:Number;
        private var score:Number;
        
        public function Enemy()
        {
            this.x = C.ENEMY_START_X;
            this.y = C.ENEMY_START_Y;
            
            //start moving to the right
            this.facing = C.ENEMY_SPEED;
            
            //Set enemy score
            this.score = C.ENEMY_STARTING_POINTS;
        }

These lines 10 to 20 will be executed immediately when the code var newEnemy = new Enemy(); is executed back in the GameController.as. As you can see, we actually set the x and y position over here in lines 12 and 13.

The variable facing keeps track of which direction the alien should be moving, and at what speed. As you'll see later, the alien actually moves in a zigzag fashion, so the variable facing will take care of that.

The scoring mechanism for the game is such that the further away the enemy is from you, the higher is the score you'll get when you hit it. Therefore, at the moment of spawning of the enemy, we set its score to the max, denoted by ENEMY_STARTING_POINTS. As the alien advances towards the planet, we'll decrease this score.

Let's head back briefly to the GameController.as.

163
164
165
166
167
//Update enemies
for (var i=enemies.length - 1; i >= 0; i--)
{
    enemies[i].update();
}

The next few lines of codes that follow loops through the enemies array to update their game state. But, what happens here is, we only execute one line of code! We merely executed enemies[i].update(). We could have written the usual codes like moving the enemies, checking if the enemy should advance, or checking if the enemy should change its direction all in between the brackets of lines 165 and 167. But we didn't.

This is the key advantage of using external .as files to handle your game objects. If you're working in a team, your team members could handle the Enemy.as instead of you writing all the code by yourself. We put all those game logic affecting each enemy that should take place during each tick of the game loop into this update function.

To make things clearer, let's see what this update function really is about. The code below is what you see in the update function of Enemy.as. Do not confuse this update with the main game loop we always see in the GameController.as.

22
23
24
25
26
27
28
29
30
31
32
public function update()
{
    this.x += this.facing;
    
    if ((this.x > C.PLAYER_RIGHT_BOUND) || (this.x < C.PLAYER_LEFT_BOUND))
    {
        this.facing *= -1;
        this.y += C.ENEMY_ADVANCE;
        this.score -= C.ENEMY_REDUCE_POINTS;
    }
}

These lines of code handle the movement of the alien. Line 24 moves the alien in the x axis by whatever value its facing variable is. Remember that earlier on we set it to C.ENEMY_SPEED, which is 5. The enemies start off moving in the positive x-direction, which is to the right.

If you took a sneak peek at the game already, you see that the aliens switch direction once they reach the sides of the game stage. That is handled by line 26, which checks for that. Line 28 multiplies the facing variable by -1. Since the facing variable was 5, it becomes -5 after the code is executed. And since we increase the alien's x value by facing, it starts moving to the left again during the next tick of the game loop (when line 24 is executed again).

Line 29 advances the enemy towards the player and the planet, and its score is reduced since it is now nearer to the player, and deserves a lower score.

So if we take a step back, we could have put all these codes into GameController.as. But remember the reason why we did it here is because we wanted to modularise our code further. Once our codes get longer, it makes little sense to cramp everything into GameController.as. Imagine you have to plow through a few thousand lines of codes just to find a bug. You may say that the code for this tutorial is too little to warrant that, but hey, better to show you how it's done when it's more manageable right? =)

Now, let's head back to the GameController.as again.

169
170
171
172
173
174
175
176
177
178
179
//Update bullets
for (var i=bullets.length - 1; i >= 0; i--)
{
    bullets[i].update();
    
    if (bullets[i].notInScreen())
    {
        mcGameStage.removeChild(bullets[i]);
        bullets.splice(i,1);
    }
}

After we are done updating the enemies, we update the bullets. I hope that things are getting a little more familiar by now. Similarly, we loop through the bullets array, and line 172 calls the update function we defined for each bullet inside Bullet.as. If you pop over to that file and take a quick look at what the update function does in Bullet.as, you'll see that it merely moves the bullet skywards by reducing its y value.

Lines 174 to 178 checks if the bullets have gone off the game stage, and hence should be removed. I probably could have placed these codes in the update function as well within Bullet.as, but that would involve a few other concepts which I think are better left for another tutorial. Regardless, the notInScreen function is defined in Bullet.as and checks if the y coordinate of the current bullet is less than 0. If so, it is considered off screen. Then we remove it from the mcGameStage with line 176, and remove it from the bullets array in line 177.

Step 6 - Checking for Collisions

With all the aliens moving and bullets flying, nothing is really happening unless they hit each other and kaboom. As usual, there's this checking for collision chunk of code that you see in the game loop.

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
//Check for collision
//---------------------
//Bullet and Enemy collisions
for (var i=bullets.length - 1; i >= 0; i--)
{
    for (var j=enemies.length - 1; j >= 0; j--)
    {
        if (bullets[i].hitTestObject(enemies[j]))
        {
            //Increase player score
            playerScore += enemies[j].getPointsWorth();
            
            //Remove bullet and enemy
            mcGameStage.removeChild(bullets[i]);
            mcGameStage.removeChild(enemies[j]);
            bullets.splice(i,1);
            enemies.splice(j,1);
            
            break;
        }
    }
}
 
//Player and Enemy collisions
for (var j=enemies.length - 1; j >= 0; j--)
{
    if (player.hitTestObject(enemies[j]))
    {
        mcGameStage.removeChild(player);
        mcGameStage.removeChild(enemies[j]);
        
        enemies.splice(j,1);

        
        gameOver();
        
        break;
    }
}

The codes above do the checking for the collisions that go on in the game. We check for both the collision of the bullets and the enemies, hence requiring a double for loop in lines 184 and 186.

In tutorial 1, I showed you how to use distance to check for collisions. I thought I probably should show you how the default function that Flash provided to do this. You can then choose whichever way you feel more comfortable with in future.

The hitTestObject is used to check for collisions between two movieclips. Take note of the bounding box concept for movieclips. Take a look at the diagram below.

hitTestObject

To demonstrate this idea, I deliberately made the alien a fat round alien (it's not inspired by the killer tomatoes). Although it is round, Flash adds a blue rectangle around it for positioning and collision testing purposes. All movieclips have such a bounding box, and you can see that the missile has one around it as well.

We can tell visually that both movieclips, the alien and the missile, have yet to touch each other yet. But by using the code above and having hitTestObject check for collision between the two of them, Flash will actually return true because the bounding box is what is used to check for collisions, not the actual pixels of the movieclip.

Personally, I seldom use hitTestObject when I code, but like I said, it's good to show you what the most basic function can do.

Next, the break is added in line 199 because each bullet can only collide once. So if it is able to reach line 199, it meant that the current bullet has hit an enemy, so we break out of the looping of the enemies array and move on to the next bullet.

The code for displaying the score is the same as previous tutorials.

Step 7 - Game Over

227
228
229
230
231
232
233
234
private function gameOver()
{
    player = null;
    
    mcGameStage.removeEventListener(Event.ENTER_FRAME,update);
    stage.removeEventListener(KeyboardEvent.KEY_DOWN,keyDownHandler);
    stage.removeEventListener(KeyboardEvent.KEY_UP,keyUpHandler);
}

Most games have a Game Over screen to tell the players that playtime's over. I'll demonstrate in later tutorials how to come up with the proper frames for a How To Play, Game Over, etc, but for now, I'll just use a simplified function called gameOver to stop gameplay. This happens when the player collides with an alien.

Remember that when you're done with the game, we need to dereference variables by setting them to null, and also remove listeners because these still take up memory and processing time if we don't. It's good practice that we should try to follow.

Here we set the player variable to null, and remove all the listeners we added previously. The Garbage Collector in Flash will kick into action when it feels like it (seriously we have no control over it), and clear up the memory usage.

The Game

And here you have it ... the working game! If you liked it ... share it!

Download the Game Files

The files you need to create this game can be downloaded from here.

How To Play

Objective: Hit as many aliens as you can.

Controls: Press the LEFT and RIGHT keys to move and SPACEBAR to fire.


Content on this page requires a newer version of Adobe Flash Player.

Get Adobe Flash player


Flash Resources
Preloader FPS Display Sounds & Music
Keycodes Name Generator
Game Development Resources
Sprite Sheets


Posted by Junkai Cher

on 2014-07-07 00:08:32

Hi there,
by any chance, do you know how to make the aliens fight back as in shoot missiles at you or something like that cause I was hoping to make a game like that


Posted by Joseph

on 2014-02-16 14:02:00

@Erwin
Can you check the properties of the text field. Choose Use Device Fonts so that the score adds up properly.


Posted by Erwin

on 2014-02-15 10:12:50

Hi if i tried to modify the enemy / background or the player or any of the movie file.
it runs but the score didnt appear. How would i fix that?


Posted by ItIsMe

on 2014-01-13 08:08:41

Do you know how to make classic Space Invaders movement?

I would like to move all enemies to right and if any of them hit right stage boundaries, then move all enemies to left side.

Can you show how to do that please?


Posted by Maldini

on 2013-12-10 16:36:14

okay so I made a new clearGame function similar to one in the frogger one, it works fine and it goes to the lose screen nicely, but the enemies keep spawning even after it goes to the main menu, it stopped spawning if i restart the game but even then the leftover enemies won't clear out,is there a way I can email or contact you?that'd be really helpful,thx


Posted by Joseph

on 2013-12-09 22:08:33

You can do it in a few ways … but putting it inside the GameOver function should work.

Just jump over to another frame when that happens, but you will need to remove the enter frame listener, etc.

For a peek on how to do that, check out the later tutorials like Frogger.


Posted by Maldini

on 2013-12-09 08:08:14

Thanks a lot for that it works perfectly now,also I have one more question,if I wanted to put a GameOverScreen to pop up when the player loses,should I put it inside the GameOver function or remove the GameOver function altogether and put the event inside the if(player.hittestobject)?


Posted by Joseph

on 2013-12-08 14:26:09

Hey,

@Maldini: Can you check the properties of the text field. Choose Use Device Fonts so that the score adds up properly.

@Luke: Sure!


Posted by Maldini

on 2013-12-07 08:05:19

thanks for the wonderfun tutorial,but I'm having trouble making the score appear,it wont add


Posted by Luke C

on 2013-11-25 17:37:01

Am I allowed to use your templates and character designs for my ICT A level unit?


Posted by toms retailers

on 2013-10-06 06:34:44

You write very well!


Posted by toms outlet

on 2013-09-09 02:01:03

These tips are so true


Posted by Joseph

on 2013-06-19 16:09:32

Hey, C.as is nothing more than a file which contains constants. You can take a look at tutorial 1 where I introduced it.


Posted by Julie

on 2013-06-03 22:04:54

Hi, i'm just a bit confused on what to link the C.as file with. I originaly thought it had to be linked with player but realised that didn't make sense. I'd appreciate a quick reply. Thanks.


Posted by Joseph

on 2012-12-19 23:52:19

@DesmondTuTu

Terribly sorry for the long reply.

To increase the spawn rate should be easier. Instead of using a constant C.SPAWN_ENEMY_CHANCE in "if (Math.random() < C.SPAWN_ENEMY_CHANCE)", you can change it to a variable that will keep increasing whenever a new enemy dies.

To increase the speed, you can always introduce a new variable to modify the speed of the enemy. Basically, the enemy move based on this code in the update function:
this.x += this.facing;

So, you can do something like this.x += this.facing * this.speedFactor

I'm introducing a speedFactor variable here which you can initialize to 1. Every time an enemy dies, you can increase a variable in your main GameController.as file. Using this variable, new enemies that are created can have a speedFactor that is increased.


Posted by mouseyyyyyyy

on 2012-03-16 22:29:34

Superb Game, was a fantastic experience playing this game, i would like to thank everyone out there who helped make this game.


Posted by Richard Ofee

on 2012-03-09 21:59:30

Good game.


Posted by DesmondTuTu

on 2011-12-07 03:47:40

Hi,

Thank you for your tutorials, they're helping me get the hang of AS3 and flash game development.

I do need some help at the moment. I'm looking at making the game get progressively harder as you play, for example if I start the enemy speed at 2 or three how would I increase the speed by 1% after each enemy hit. That or increase the spawn rate of each enemy.

Any help would be really appreciated. Thanks!


Posted by dHDJidRyyLuYRJ

on 2011-04-21 13:27:25

That's really thiknnig out of the box. Thanks!


Posted by Joseph

on 2010-11-15 22:33:50

You do not need a Player.as file in this case because we're not coding complex logic for the Player class. The default one will work fine. Just make sure the Linkage is set as Player, NOT Game.Player.


Posted by Dude

on 2010-11-11 18:24:01

Hi teacher! ^^

I am missing player in the download files...
I have Bullet, C and Enemy, but no Player file?
can you please check the files?


Posted by --xPolliTo-loco-x---

on 2010-08-26 11:10:47

Love Shoot Games! Im going to try this, it seems like Wonderfull! Thanks to shre your Tutorials Teacher! :]


Flash Tutorial Links:
Play Games: HTML5 Tutorials:
gaming tools download on app store now!
Home | About Us | Contact Us
Powered by Make Flash Games. All Rights Reserved.
By Joseph Tan