Space Devourers: a Space Invaders clone [ September 01, 2003 ] by Steve Happ
A complete tutorial showing the development of a Space Invaders clone.
This will be a tutorial for Flash MX to make a game that is inspired by, rather than clone, the original Space Invaders. You can create your sprites to look exactly like the original or do what I have done and make them in your style. We are going to create just 3 levels, but you can go on and create as many as you like. I will use the mouse to move the defender and fire bullets.
First off, Make the movie 700 x 400 and set the frame rate at 25 frames/per/second. Then make 3 layers and call them: actions, text, defender.
FRAME 1 - INTRO
In frame 1, layer "text", put some text describing your gameplay ("use the mouse"), a title and a start button. You can put some graphics, etc. as well in here
Select your button, and open the code window (F9) and put this code in:
on(release)
{
_root.gotoAndStop(2);
}
This is very basic. All it does, of course, is take us to frame 2.
MAKE YOUR SPRITES
Create 3 alien sprites. Make them 30x30. I made them as bitmaps and saved them as transparent png's. Also make a defender about 40X25. Call the mc "Defender". Call the Alien mc's "Alien", "Bug" and "Skull". Go to the Library window(F11) and right click on Alien. Select "Linkage" and then tick "Export for Actionscript" and "Export in first frame". In the identifier box , name it "alien". Do the same for Bug and Skull. Call them "bug" and "skull" in the identifier box. That will be their actionscript mc name.
Make a bomb mc and a Bullet mc. Name them "Bomb" and "Bullet". In their linkage windows call them "bomb" and "bullet".
So that is it for the sprites. We have a: Alien, Bug, Skull, Bomb, Bullet, and a Defender.
This code stops the playhead going to frame 2 until the user has pressed the start button, and initialises our variables that we will use later.
INITIALISE THE ALIENS
We will write a global function which will allow use to initialise the various types of baddies and to call it in one line of code. We can reuse it by simply passing the name of the baddie to the function. Like so: initAliens("bug") or initAliens("skull"). Notice that we pass the linkage name and not the MC name.
Here it is. Copy this after the speed = 10 line, in the actions layer, frame 1:
It is pretty self-explanatory. I use a 2 Dimensional Array, 3 by 10, and use 2 for loops to go through and name and attach the aliens according to their rows and columns. Then their x and y positions are determined by their row and column numbers. I have given them depths of 100+. That is because the bullets will be given number from 0+. It is good to give each sprite and their duplicates the same hundreds number. I will be using 200+ for the bombs. So if I had more ranges of duplicated or attached clips i would use 300+, 400+, etc... Each mc must be on its own depth, otherwise it will be overwritten.
MOVE ALIENS FUNCTION
We will now write the global function that will allow us to move the aliens and allows us to test for any collisions with the defender's bullets. We have jammed a lot in here because I want to have as few loops as possible so that the game runs as fast as can be. 3 arguments will be passed to the function: the mc name(alien, bug, or skull), the next frame number, and the baddies' speed. Write it on frame 1, actions layer after the above code. Here it is:
// ------- MOVE ALIENS ----------------- //
_global.moveAliens = function(mc, frame,alspeed)
{
// count the dead baddies
_root.deadcount = 0;
// loop through baddies
for (var i = 0; i < 3; i++)
{
for (var j = 0; j < 10; j++)
{
// move horizontal
_root[mc+i+"_"+j]._x += speed;
// check if aliens hit defender
if(_root[mc+i+"_"+j].hitTest(_root.defender))
{
cleanup(mc);
_root.gotoAndStop(1);
}
// check if any aliens left alive
if (_root[mc+i+"_"+j] != null)
{
++_root.deadcount;
}
// -------test bullet hit
bulleti = 6;
while (--bulleti > 0)
{
if (_root[mc+i+"_"+j].hittest(eval("_root.bullet"+bulleti)))
{
_root[mc+i+"_"+j].removeMovieClip();
eval("_root.bullet"+bulleti).removeMovieClip();
_root.score += 1;
}
}
// hits left wall
if (_root[mc+i+"_"+j]._x < 0)
{
// set direction to right
speed = alspeed;
// drop down
dropdown = true;
break;
}
// hit right wall
if (_root[mc+i+"_"+j]._x > Stage.width)
{
// set direction to left
speed = -alspeed;
// drop down
dropdown = true;
break;
}
}
}
// drop down all the rows
if (dropdown)
{
for (var i = 0; i < 3; i++)
{
for (var j = 0; j < 10; j++)
{
_root[mc+i+"_"+j]._y += 20;
}
}
}
// reset flag
dropdown = false;
// if all aliens are dead
if (_root.deadcount == 0) {
// go to next level
_root.bombspeed = 0.0;
_root.gotoAndStop(frame);
}
}
So what does this do. We set up 2 loops to go through each alien. We:
Move them horizontally by amount speed
If a baddie collides with defender, go to frame 1
Counts how many baddies left alive
Collision Detection for bullets, ++score
Checks if baddies hit left or right sides
Sets the flag to drop rows
If flag is true, drops down all baddies
If 0 baddies are left, goto next frame/level
Initialise the Bombs Function
This function will randomly drop bombs at a random time set by bombspeed, the argument passed to this function. I have used the deprecated random() function as well as the newer Math.random() which returns a random number between 0 and 1. I have also set the bombs to have a random starting x and y position. If the bombNumber is greater than 10, it simply starts again at 0. Add this code in frame 1, actions layer, after the above moveAliens function:
// ----------- INIT BOMBS --------------- //
_global.initBombs = function(bombspeed)
{
// drop bombs
if (Math.random() < bombspeed)
{
// duplicate the bomb mc
attachMovie("bomb", "bomb"+bombNum, 200+bombNum);
// set the coords to a random position
eval("_root.bomb"+bombNum)._x = random(700);
eval("_root.bomb"+bombNum)._y = 300*Math.random();
// increment the bomb number
bombNum++;
// if more than 10 bombs , start again at 0
if (bombNum > 10)
{
bombNum = 0;
}
}
}
MOVE BOMBS FUNCTION
This function will move the bombs and do collision detection on the defender. If the bomb hits a defender, it will be removed and lives will be decremented. If all the lives are gone, then the user will be returned to frame 1, the mouse will be shown, the bombspeed set to 0 so that the bombs will stop falling in frame 1, and all the baddies will be set to invisible.
If any bombs go offscreen, they are removed. Notice the use of a break statement after the collision detection. There is no need to continue with testing if it goes offscreen. Use a break when you dont need to continue in a loop and save time and speed. I have also used break statements in the moveAliens function after a baddie has hit the wall.
// -------------- MOVE BOMBS ---------------- //
_global.moveBombs = function(mc)
{
var bombi = 0;
while (bombi < 11)
{
_root["bomb"+bombi]._y += 5;
// hitest defender
if (_root["bomb"+bombi].hittest(_root.defender))
{
_root["bomb"+bombi].removeMovieClip();
_root.lives -= 1;
// lives are all gone
if (_root.lives < =0)
{
// go to start
Mouse.show();
_root.bombspeed = 0.0;
_root.gotoAndStop(1);
for (var i = 0; i < 3; i++)
{
for (var j = 0; j < 10; j++)
{
_root[mc+i+"_"+j]._visible = false;
}
}
break;
}
}
// test if bomb goes offscreen
if (_root["bomb"+bombi]._y > Stage.height)
{
_root["bomb"+bombi].removeMovieClip();
}
bombi++;
}
}
CLEAN UP FUNCTION
This function cleans up before the user is returned to frame 1. It sets the bombspeed to 0, and makes all the baddies invisible. If not done the baddies continue in the foreground when a user is taken back to frame 1.
Put this code in frame 1, actions layer, after the moveBombs function:
// ---------- CLEAN UP -------- //
_global.cleanup = function(mc)
{
_root.bombspeed = 0.0;
for (var i = 0; i < 3; i++)
{
for (var j = 0; j < 10; j++)
{
// move horizontal
_root[mc+i+"_"+j]._visible = false;
}
}
}
That finishes off frame 1. To recap:
we have made all our sprites;
put introductory Text and a start button on the frame;
initialised our variables;
wrote a global function to initialise the baddies;
wrote a global function to move the baddies, as well as do collision detection on them;
wrote a global function to initialise the bombs;
wrote a global function to move the bombs, and do collision detection on defender;
wrote a global function to clean up our baddies and bombs from the screen.