Invaders with Scoring, Game Over, and Restart

Click in the window above to set focus. Hit 6 invaders to finish the game. Why not play again?

As initmated, adding a Game Over screen and a Restart button involves considerable addition to, and modification of, the base code. Now that the deadline is upon us, we'll discuss one approach to this task; not by any means the most elegant.

I. Assumptions

First, we assume you've implemented some scoring mechanism, following our advice to place the score variable within the shooter object. See our posting on scoreboard hints.

Second, we assume you'll want to make your Game Over screen a keyframe in the main movie timeline, rather than trying to load an external SWF file. (That's another possible approach, but loading subsidiary movies has gotten considerably more difficult in ActionScript 3 than it was in earlier versions.)

II. Trouble

As soon as you add a keyframe to your main movie, you will find yourself with a large screenful of error messages, most of them talking about a "null object reference," or complaining that "Parameter hitTestObject must be non-null."

The problem is both simple and vexing: unless you add frames for the layers containing your invaders -- you'll send the Flash Player into fits. This is because the Event Listeners you create with each instance of invader continue to operate even in frames that do not contain the object. And when they can't find themselves, they throw fits, or errors, which are worse.

To avoid this problem, you'll need to add frames for all your invader layers. To be safe, add a frame for every layer. Script a stop() action on some layer in frame 1, and likewise for your Game Over frame (which for us is frame 10). This is progress, but you've still got some problems to solve.

III. Modifications to shooterClass

So now we can jump safely to that Game Over frame, but the screen is still covered with marching invaders. In fact, the game isn't over at all; and come to think of it, we haven't explained exactly how we can jump to the Game Over screen...

To handle these problems, we need to make some changes to shooterClass.as.

First, we declare a variable called gameOver of type Boolean, giving it the value false. (The variable name is arbitrary, but probably hard to improve upon.)

Next, we set up a mechanism for determining when the game is over. In our version, we have an ENTER_FRAME callback called showScore(), that updates the scoreboard on every frame entry. We do our game-over check there:

  public function showScore(event:Event):void
  {
    MovieClip(root).scoreField.text = String(score);
    if(score > 5)
    {
      gameOver = true;
      MovieClip(root).gotoAndStop(10);
      MovieClip(root).scoreField.text = "Game Over";
    }
  }

We don't actually need to use gotoAndStop() here, since there's a stop() action on frame 10, but the overkill is harmless. Note that we put our "Game Over" message into the same field that holds the score. That's efficiency for you.

Most crucially, we set the value of the gameOver Boolean to true. This raises a flag for other objects to see, particularly all our instances of invaderClass.

IV. Modifications to invaderClass

In the animate() callback of invaderClass, which operates on every frame entry, we add this line:

  if(MovieClip(root).shooter.gameOver == true) reSet();

So our invaders all run up to the top of the screen when the game is over; but the animate() method should put them right back into motion, right? Not in this case: remember, animate() checks the value of gameOver several times a second. If it comes up true, animate() calls reset(). which randomly positions the invader at some point above the top of the visible screen. This continues until the value of gameOver returns to false.

In effect, our invaders just shuffle around offscreen until we're ready for them.

However, we've done nothing to disable the firing and scoring mechanism. We could add code to shooterClass to prevent firing while gameOver is true. Or we could add a condition to the hit test in invaderClass, like so:

  if(hitTestObject(MovieClip(root).theBullet) && !gameOver)

Remember, the symbol ! means logical inverse, or not, which is a shorter way of saying gameOver == false. This line prevents contact with the bullet (up there in the offscreen stratosphere) from having any effect.

Yes, this arrangement still lets the player fire away while in the Game Over state, which is not an especially keen design decision. We're trying to keep things simple.

V. Restart button (Movie Clip)

Finally, we need to explain how to start the game over. We'll assume you've added a Movie-Clip-as-button in a new layer, at frame 10, so there's something to click on the Game Over screen. We'll further assume that you've written a class called restartBtnClass for this new object. The class might look something like this:

package
{
  import flash.display.MovieClip;
  import flash.events.MouseEvent;

  public class restartBtnClass extends MovieClip
  {
    function restartBtnClass():void
    {
      buttonMode = true;
      addEventListener(MouseEvent.CLICK, reStart);
    }
		
    function reStart(event:MouseEvent):void
    {
      MovieClip(root).shooter.gameOver = false;
      MovieClip(root).shooter.score = 0;
      MovieClip(root).gotoAndPlay(1);
    }
  }
}

The main business of this class, contained in the callback for the CLICK event, resets the gameOver variable to false, the score variable to zero, and sends the playback head to frame 1, where it encounters a stop() instruction.

It's important to reset score. Remember, you have code in shooterClass that checks to be sure it's less than 6. If you don't set it back, you'll end up stuck on the Game Over screen for all eternity.

As for the invaders, resetting gameOver to false frees them to threaten the Earth with destruction, or whatever they do. It also makes them vulnerable to bullets once again.

VI. Document class, anyone?

Finally, a note about the architecture of this solution. We've avoided using a document class by placing variables that must be unique (score, gameOver) on the unique shooter object. There's nothing wrong with this approach, though it may be easier for others to understand your work if you use a document class to host variables used by more than one class in the system.



University of Baltimore Logo

Last updated: 03/23/08 18:26:08
Copyright © 2008 School of Information Arts and Technologies