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.

WRITE YOUR FUNCTIONS

Select your "actions" layer and put this code in:

stop();
// declare and initialise variables
bombNum = 0;
lives = 3;
score = 0;
speed = 10;
            

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:

//	---------	INITIALISE ALIENS	-------------	//
 
_global.initAliens = function(mc)
{
	depth = 0;
	for (var i = 0; i<3; i++)
	{
		for (var j = 0; j<10; j++)
		{
			attachMovie(mc, mc+i+"_"+j, 100+depth);
			_root[mc+i+"_"+j]._x = j*40;
			_root[mc+i+"_"+j]._y = i*40-80;
			depth++;
		}
	}
}
            

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.

(continues on page 2)


     
 
 
Name: Steve Happ
Location: Newcastle, Australia
Age: 51
Flash experience: 2-3 years
Job: Computer trainer
Website: http://www.video-animation.com/
 
 
| Homepage | News | Games | Articles | Multiplayer Central | Reviews | Spotlight | Forums | Info | Links | Contact us | Advertise | Credits |

| www.smartfoxserver.com | www.gotoandplay.biz | www.openspace-engine.com |

gotoAndPlay() v 3.0.0 -- (c)2003-2008 gotoAndPlay() Team -- P.IVA 03121770048