Making a simple game in flash

Many people get into programming in order to make games. In this post I’ll talk about how I followed a tutorial to make a simple spaceship game in Flash, then adapted the resulting product into a two-player competitive game.

The tutorial I used was asgamer’s AS3 Flash Games For Beginners series. Due to time constraints I omitted some features of the tutorial, such as the scrolling star background and the HUD.

The finished game can be downloaded here, and the .fla and accompanying files can be downloaded here. Play it and you’ll see that it’s a simple enough affair in which the player controls a spaceship and shoots enemy ships. There is no way for the player to die. In order to talk about the process of following this tutorial, let’s break the game down to its most important components and the key functions they fulfill:

  • The player controlled spaceship
    • Movement
    • Shooting
    • Animation
  • Enemy spaceships
    • AI
    • Shooting
  • Lasers!
    • Creation and removal
    • Hit detection
  • Engine

The engine is the key component here, as it handles the appearance of the other components onto the stage (the name given to the movie or game area in Flash). Without the engine, none of those components will come together into something that works.

Rather than confuse everyone with the full code of the Engine, here are some lines that show how the player-controlled spaceship, which is a MovieClip object made from a Ship class, comes into play:

  1.  public class Engine extends MovieClip
  2.     {
  3. public var ourShip:Ship;  
  4. public function Engine() : void
  5.         {
  6.             ourShip = new Ship(stage);   
  7.             stage.addChild(ourShip);  
  8.             ourShip.x = stage.stageWidth / 2;  
  9.             ourShip.y = stage.stageHeight / 2;  

In the highlighted code you can see that the player’s ship, called ourShip, is a class variable of the Engine. There’s a reason for this we’ll get to later.

Inside the Engine class constructor the ourShip variable is assigned to a new instance of the Ship class. As we’ll see in a moment, the Ship class is passed a reference to the stage, because some of the code in the class needs to reference the stage in order to function.

Once the ship is added to the stage, its starting position is set in the middle of the stage by assigning its x and y co-ordinates to half the width and height of the stage.

Before going any further with the Engine, let’s take a look at the Ship class. The player-controlled spaceship needs to move when the players presses the appropriate arrow keys, as well as fire a laser when the space key is pressed. This is achieved with a loop function that’s called whenever a key press event is recorded.

  1. public function loop(e:Event) : void
  2.              {
  3. if(key.isDown(Keyboard.LEFT)){
  4.                    vx -= speed;
  5.             }
  6. else if(key.isDown(Keyboard.RIGHT)){
  7.                 vx += speed;
  8.             }
  9. else{
  10.                 vx *= friction;
  11.             }

Rather than simply change the ship’s x and y co-ordinates, friction and velocity were added to give it a floaty feel:

  1. if(vx > maxspeed){
  2.                 vx = maxspeed;
  3.             }
  4. else if(vx < -maxspeed){
  5.                 vx = -maxspeed;
  6.             }
  7. if(vy > maxspeed){
  8.                 vy = maxspeed;
  9.             }
  10. else if(vy < -maxspeed){
  11.                 vy = -maxspeed;
  12.             }
  13. x += vx;
    y += vy;

In order to detect key-press events and launch the code inside the loop function, an EventListener is used. EventListeners watch for a specific kind of event and call a user-defined function in response; in this case the EventListener is watching for any time a new frame is entered, eg any time the animation of the game advances. When this happens our loop function will be called, the upshot of which is that key-presses will result in smooth movement as the function is continually called in response to the preceding animations. Here’s the code, which goes in the Ship constructor:

addEventListener(Event.ENTER_FRAME, loop);

In plain English, what this code says is “when the game enters a new frame, call the loop function”. Other EventListeners are used throughout the game, for example in order to make new enemies spawn continuously.

You may have noticed that the ship seems to tilt in quite a nifty way when it moves. This is handled entirely through code, specifically:

scaleX = (maxspeed – Math.abs(vx))/(maxspeed * 0.5) + 0.75;

scaleX scales the size of the ship when it moves along the x-axis (horizontally). The maths on the right returns a value between 0 and 0.25, which is then used a percentage to scale the ship’s size when travelling at max speed. The default values given in the tutorial had to be tweaked here, as due to my ship’s thinner size they rendered it completely invisible when moving quickly.

Finally, our ship has to shoot. The code to make this happen isn’t complicated- we just need to add a laser object to the stage in the right position, then have it travel upward to the top of the stage and dissapear. However, the code of the actual Laser class is much more complex as it ties into how the game recognizes the impact between the laser and an enemy ship.

The Laser also uses an Enter_Frame event listener and a loop function:

  1. private function loop(e:Event) : void
  2.         {
  3.             y -= bulletSpeed;
  4. if(y < 0)
  5.             {
  6.                 removeSelf();
  7.             }
  8. for(var i:int = 0; i < Engine.enemyList.length; i++)
  9.             {
  10. if(hitTestObject(Engine.enemyList[i].hit))
  11.                 {
  12.                     Engine.enemyList[i].takeHit();
  13.                     removeSelf();
  14.                 }
  15.             }
  16.         }

Up to line 10 isn’t too complicated- the y co-ordinate of the laser is set to y-bulletSpeed, which will make the laser move up at a rate corresponding to bulletSpeed, which is a class variable set in the class definition. If the y value of the laser goes to less than 0 a function called removeSelf will be called, which removes the laser from the stage.

Take a look at line 10. hitTestObject is a built-in function that tests to see if two objects are touching and returns a boolean value of true or false. In this case we’re testing the collision between our laser (this is implicit and doesn’t need to be declared) and the “hit” property of a particular element of an array called enemyList. What does that mean?

In our Engine class an array was made that stores a reference to every enemy currently on-screen. Each enemy instance has an invisible box drawn over it, which is called “hit”, so we cycle through that array with a for loop and test to see if the hit box and the laser are in contact. If they are, two things happen: the laser removes itself from the stage, and a function called takeHit() is called on the enemy in question. takeHit essentially just removes the enemy from the stage as well, so the laser and enemy are both gone.

Our enemy ships also fires a laser, which in many ways is very similar to our ship’s laser except that it moves horizontally.

Now the only thing we need are enemies to shoot at. The code for the Enemy class itself isn’t too interesting and is quite similar to the Ship class, except simpler and with no requirement for player movement. An Enter_Frame event listener in the Engine class is used to spawn enemies at random locations off the top of the stage, simultaneously adding them to the enemyList array.

The only complicated aspect of the Enemy class (and one of the more challenging aspects of following the tutorial) is making the enemy ships fire their lasers when in proximity to the player. In order to do this we make a class variable of type Ship and incorporate it into the Enemy constructor:

  1. public class Enemy extends MovieClip
  2.     {
  3. private var stageRef:Stage;
  4. private var vy:Number = 3;
  5. private var ay:Number = 0.4;
  6. private var target:Ship;
  7. public function Enemy(stageRef:Stage, target:Ship) : void
  8.         {
  9. this.stageRef = stageRef;
  10. this.target = target;  

Then in the Engine class, when new Enemy instances are created we set this target variable to ourShip, which is the player’s ship.

var enemy:Enemy = new Enemy(stage, ourShip);

In the Enemy class’s loop function there’s a line of code setting how close the enemy has to be before it will fire:

if (y – 15 < target.y && y + 15 > target.y){
fireWeapon();
}

Needless to say, fireWeapon is a function that creates instances of the EnemyLaser class (not discussed because it’s very similar to the Laser class that the player’s ship uses).

Once the tutorial game was done I decided to adapt it into a two-player game, where two spaceships fire at each other competitively. You can download the game here and the associated files here. The controls are:

Yellow Ship

Up: up arrow

Down: down arrow

Left: left arrow

Right: right arrow

Shoot: shift

Red Ship

Up: W

Down S

Left: A

Right: D

Shoot: space

Creating the second ship was a simple enough matter of flipping the previously made ship and making it a new class, called Ship2, which is identical to Ship1 except for its controls. Any subsequent additions or alterations to the Ship class from the tutorial game were reflected in both classes.

The introduction of two spaceships immediately presented two problem. The first was spawning the two ships in the engine class- I obviously couldn’t have them both appear in the middle of the screen. I wanted the ships instead to start facing each other in the middle of the top and bottom halves of the stage, on either side. I did this with the following code in the engine code:

public var halfStageWidth:int = stage.stageWidth / 2;
public var halfStageHeight:int = stage.stageHeight / 4;

This creates variables corresponding to the middle of the stage along the x-axis and a point about one quarter from the top of the stage along the y-axis. These values were used as-is for the positioning of the red ship, but I had to get slightly creative to put the yellow ship where I wanted:

player1.x = halfStageWidth;
player1.y = halfStageHeight + (halfStageHeight * 2);

The bottom line puts the red ship 50% closer to the bottom of the stage than the yellow ship, or in other words a quarter away from the bottom of the stage, putting the two ships equidistant from each other.

The second problem with two ships is that they could only shoot in one direction (minor adjustments were made so that the yellow ship’s laser moves down instead of up). I brainstormed several solutions to this, including having the ships rotate so they could fire in all directions, however this proved to be too complicated to achieve in the time-frame of the project. Instead I hit on the idea of dividing the stage in half and prohibiting either ship from moving into the other’s sector. Happily, there was already code in the tutorial game that made the player ship bounce off of the sides of the stage, and this was easily adapted:

if(y < stageRef.stageHeight/2){
y = stageRef.stageHeight/2;
vy = -vy;
}

In other words, if the ship’s y value corresponds to the middle of the stage, stop its motion and reverse its velocity along the y-axis.

A much bigger problem in terms of gameplay is that the tutorial game didn’t actually do anything when the player ship is hit with a laser; obviously if my two-player game was to have any sort of challenge, this wouldn’t do.

My solution was ti simply make each of the ships reset to their starting position when hit with each other’s lasers; that was simple enough, but it led to some unexpected difficulties as in the tutorial game only the enemy ship and its laser had a target; in this game both ships targeted each other, and adapting the somewhat complex sequence in which the target variable is passed from the ship class to the laser class proved tricky.

After some debugging I eventually discovered that the following code in the Engine, which should have set the two ship’s targets as each other, wasn’t working:

player1 = new Ship1(stage, player2);
player2 = new Ship2(stage, player1);

(ship1 constructor, for reference)

public function Ship1(stageRef:Stage, target:Ship2) : void
{

this.target = target;

The value of target remained “null” instead of taking on its proper value. I’ll admit I’m still not entirely sure why this was the case, but the solution was as simple as making a dedicated setter function in the two Ship classes and using it in the Engine to designate each ship’s target as the opposite ship. Here’s an example:

public function setTarget(target:Ship2)
{

this.target = target;

}

.

.

.

player1.setTarget(player2);

Tackling a Flash project of this complexity was challenging, but it taught me several important lessons. Firstly, it reinforced a lot of what I had already learned about the concepts of object-oriented programming in Java- learning the ideas in a lab setting is one thing, actually applying them to make a functional program is another.

Second, it demonstrated the true versatility of what can be done with a programming language. For this project I only used the basic drawing tools of the Flash CS6 client in order to make the ship and laser sprites; everything else, including animation work, was handled with coding. This goes to show just how much can be achieved even as a solo programmer.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s