Richard Parnaby-King

Web Developer – PHP, Zend Framework and Actionscript 3

Posted on | | 10 Comments

In this tutorial, you’ll learn how to create a simple point and click game. The objective is simple: Do not let any balloons go over the top of the screen!

Preview

The Plan

As always, plan how the game is going to behave before you start any coding!

  • First of all, we want a start button.
  • We want a new balloon every 5 seconds.
  • Each balloon should start at the bottom of the page and move to the top of the page.
  • If the balloon goes over the top of the page, then it’s game over; remove all balloons from the stage and offer a restart button.

Step 1: Buttons

We know we are having a start and restart button, and we want a balloon, so let’s create those. I am using the pixlr.com editor.

Starting with a freshly generated Main.as file in FlashDevelop, we embed our images:

[Embed(source="../lib/start.jpg")]
private var StartButton:Class;
private var startButton:Sprite = new Sprite();

[Embed(source="../lib/restart.jpg")]
private var RestartButton:Class;
private var restartButton:Sprite = new Sprite();

We create one instance of the start and restart buttons as Sprites. We have not embedded our balloon image as we want to do that in a separate class.

We have created and embedded our buttons. Now to make them do something. In the init function, add the following code:

//add start button
startButton.addChild(new StartButton());
startButton.addEventListener(MouseEvent.CLICK, startGame);
startButton.buttonMode = true;
startButton.x = (stage.stageWidth / 2) - (startButton.width / 2);
startButton.y = (stage.stageHeight / 2) - (startButton.height / 2);
addChild(startButton);

This code will add the StartButton image to the sprite, and make it so that when the user clicks on it it calls the function ‘startGame’. We also make it change the user’s cursor when they hover over it. We then add our start button to the centre of the stage!

We now need a function called startGame.

/**
 * Create some balloons and get them moving!
 * @param MouseEvent e
 */
private function startGame(e:MouseEvent):void {
  startButton.removeEventListener(MouseEvent.CLICK, startGame);
  removeChild(startButton);
}

First, some garbage collection. This is just some basic optimisation. Instead of waiting for FlashPlayer’s garbage collection to kick in and remove the event listener for us, we’ll remove it now and free up some CPU cycles.

We don’t want to show the start button any more, so we remove that from the stage.

Step 2: Balloons

Now we get to create some balloons.

First, planning. What do we want our balloons to do?

It would be nice if the balloons were not pure white. Let’s colour our balloons.
They need to move.
When a user clicks on the balloon, we want to recycle it. That is, make it move to the bottom of the screen again and begin it’s tween to the top of the page. Sounds like a reset function to me.

Here is our skeleton balloon class:

/**
 * Balloon.as
 * Balloon Class.
 */
package
{
  import flash.filters.DropShadowFilter;
  import flash.display.MovieClip;
  import com.greensock.*;

  public class Balloon extends MovieClip
  {
    [Embed(source = "../lib/balloon.png")]
    private var BalloonImage:Class;
    
    private var myTween:TweenLite;
    private var colours:Array = [0xFF0000, 0x00FF00, 0x0000FF, 0x006633, 0xFFFCD6, 0x16A5DF];
    private var dropShadowEffect:DropShadowFilter;
    
    public function Balloon():void
    {
      addChild(new BalloonImage());
      myTween = new TweenLite(this, 7, {y:-this.height, ease:"Linear.easeNone"});
      changeColour();
    }
    
    public function reset():void
    {
      changeColour();
      myTween.restart();
    }

    public function die():void
    {
      myTween.pause();
    }
        
    public function changeColour():void{
      dropShadowEffect = new DropShadowFilter(0,45,colours[Math.floor(Math.random() * colours.length)],1,width,height,1,1,true,false,false);
      filters = [dropShadowEffect];
    }
  }
}

As you can see we have embedded our balloon image in this class, and picked some bright colours to show it in. For the moving of the balloon I have chosen to use Greensock’s TweenLite as it offers a smoother tweening action than anything I can come up with.

Back in our Main class, create a property called timer

private var timer:Timer = new Timer(5000, -1);

and add the following to the startGame function:

timer.addEventListener(TimerEvent.TIMER_COMPLETE, createBalloon);
timer.start();
createBalloon();
score = 0;

This will create a new balloon every 5 seconds. And to get the ball rolling, we call createBalloon immediately:

private function createBalloon(e:TimerEvent = null):void {
  var balloon:Balloon = new Balloon();
  balloon.addEventListener(MouseEvent.CLICK, popBalloon);
  balloon.y = stage.stageHeight;
  balloon.x = Math.floor(Math.random() * (stage.stageWidth - balloon.width));
  balloons.push(balloon);
  addChild(balloon);
  timer.reset();
  timer.start();
}

This function creates a new balloon, positions it randomly along the bottom of the screen, and tells the application to run popBalloon when a user clicks our newly created balloon.

private function popBalloon(e:MouseEvent):void {
  e.target.x = Math.floor(Math.random() * (stage.stageWidth - e.target.width));
  e.target.reset();
}

This function simply moves the balloon back to the bottom of the screen and tells it to begin moving to the top of the screen again.

If you test your game at this point you will have the beginning of your game!

Step 3: Game Over and Restart

You may have noticed that the game doesn’t actually end. Let’s fix that. When a balloon passes the top of the screen we shall remove all the balloons on the screen and show a game over message. And, because games like to keep track of their l33t skilz, we’ll even tell them how many balloons they have clicked.

In the Main class, add another property:

private var score:int;

This will keep track of how many balloons have been clicked.

Update startGame so that score equals 0:

score = 0;

Finally, update popBalloon so that the score goes up:

score++;

With score tracking in place, let’s put an end to this game. Update startGame:

addEventListener(Event.ENTER_FRAME, balloonCheck);

What this is doing is calling a function on every frame checking if any of our balloons are above the screen.

private function balloonCheck(e:Event):void {
  if (balloons.length)
  {
    for (var i:int = 0; i < balloons.length; i++)
    {
      if (balloons[i].y == 0 - balloons[i].height)
      {
        //game over.
        removeEventListener(Event.ENTER_FRAME, balloonCheck);
        for (var i:int = 0; i < balloons.length; i++)
        {
          balloons[i].die();
          removeChild(balloons[i]);
        }
        timer.stop();
        return;
      }
    }
  }
}

If any of the balloons ARE above the top of the screen, then stop them moving, remove them from the stage, and stop the timer otherwise we'll end up with more balloons being generated.

Now that we have stopped the game, we need to show the user their score and the restart button. First, showing of the score.

Create a new property in the Main class:

private var textBox:TextField = new TextField;
private var textFormat:TextFormat = new TextFormat(null, 30);

All textFormat is doing is specifying the font-size to 30 pixels. I'm going to apply textFormat to textBox in the init function:

textBox.defaultTextFormat = textFormat;

And now, we add the textBox to the stage. Update the game over section of balloonCheck:

textBox.text = "You popped " + score + " balloons!nWell Done!";
textBox.width = textBox.textWidth;
textBox.x = (stage.stageWidth / 2) - (textBox.width / 2);
textBox.y = (stage.stageHeight / 4);
addChild(textBox);

We add the restart button. Add the following code to the init function:

//instantiate the restart button
restartButton.addChild(new RestartButton());
restartButton.buttonMode = true;
restartButton.x = (stage.stageWidth / 2) - (restartButton.width / 2);
restartButton.y = (stage.stageHeight / 2) - (restartButton.height);

And finally, we tweak startGame by removing a few lines of code into a new function, and create restartGame, which removes all balloons from the array and removes the button and score.

private function restartGame(e:MouseEvent):void {
  balloons = [];
  restartButton.removeEventListener(MouseEvent.CLICK, restartGame);
  removeChild(restartButton);
  removeChild(textBox);
  game();
}

private function startGame(e:MouseEvent):void {
  startButton.removeEventListener(MouseEvent.CLICK, startGame);
  removeChild(startButton);
  game();
}

private function game():void {
  addEventListener(Event.ENTER_FRAME, balloonCheck);
  timer.addEventListener(TimerEvent.TIMER_COMPLETE, createBalloon);
  timer.start();
  createBalloon();
  score = 0;
}

Final Classes

Main.as

package 
{
  import flash.display.MovieClip;
  import flash.display.Sprite;
  import flash.events.Event;
  import flash.events.MouseEvent;
  import flash.events.TimerEvent;
  import flash.text.TextField;
  import flash.text.TextFormat;
  import flash.utils.Timer;
  
  [SWF(width='800',height='600',backgroundColor='#FFFFFF',frameRate='25')]
  /**
   * Pop the balloons game. Main Class
   * @author Richard Parnaby-King
   */
  public class Main extends MovieClip 
  {
    [Embed(source="../lib/start.jpg")]
    private var StartButton:Class;
    private var startButton:Sprite = new Sprite();
    
    [Embed(source="../lib/restart.jpg")]
    private var RestartButton:Class;
    private var restartButton:Sprite = new Sprite();
    
    private var balloons:Array = [];
    private var timer:Timer = new Timer(5000, -1);
    private var score:int;
    private var textBox:TextField = new TextField;
    private var textFormat:TextFormat = new TextFormat(null, 30);
    
    public function Main():void 
    {
      if (stage) init();
      else addEventListener(Event.ADDED_TO_STAGE, init);
    }
    
    private function init(e:Event = null):void 
    {
      removeEventListener(Event.ADDED_TO_STAGE, init);
      // entry point
      
      //add start button
      startButton.addChild(new StartButton());
      startButton.addEventListener(MouseEvent.CLICK, startGame);
      startButton.buttonMode = true;
      startButton.x = (stage.stageWidth / 2) - (startButton.width / 2);
      startButton.y = (stage.stageHeight / 2) - (startButton.height / 2);
      addChild(startButton);
      
      //instantiate the restart button
      restartButton.addChild(new RestartButton());
      restartButton.buttonMode = true;
      restartButton.x = (stage.stageWidth / 2) - (restartButton.width / 2);
      restartButton.y = (stage.stageHeight / 2) - (restartButton.height / 2);
      
      textBox.defaultTextFormat = textFormat;
      
    }
    
    private function balloonCheck(e:Event):void {
      if (balloons.length)
      {
        for (var i:int = 0; i < balloons.length; i++)
        {
          if (balloons[i].y == 0 - balloons[i].height)
          {
            removeEventListener(Event.ENTER_FRAME, balloonCheck);
            for (var j:int = 0; j < balloons.length; j++)
            {
              balloons[j].die();
              removeChild(balloons[j]);
            }
            timer.stop();
            textBox.text = "You popped " + score + " balloons!nWell Done!";
            textBox.width = textBox.textWidth;
            textBox.x = (stage.stageWidth / 2) - (textBox.width / 2);
            textBox.y = (stage.stageHeight / 4) - (textBox.height / 2);
            addChild(textBox);
            
            restartButton.addEventListener(MouseEvent.CLICK, restartGame);
            addChild(restartButton);
            return;
          }
        }
      }
    }
    
    private function restartGame(e:MouseEvent):void {
      balloons = [];
      restartButton.removeEventListener(MouseEvent.CLICK, restartGame);
      removeChild(restartButton);
      removeChild(textBox);
      game();
    }

    private function startGame(e:MouseEvent):void {
      startButton.removeEventListener(MouseEvent.CLICK, startGame);
      removeChild(startButton);
      game();
    }
    
    private function game():void {
      addEventListener(Event.ENTER_FRAME, balloonCheck);
      timer.addEventListener(TimerEvent.TIMER_COMPLETE, createBalloon);
      timer.start();
      createBalloon();
      score = 0;
    }
    
    private function createBalloon(e:TimerEvent = null):void {
      var balloon:Balloon = new Balloon();
      balloon.addEventListener(MouseEvent.CLICK, popBalloon);
      balloon.y = stage.stageHeight;
      balloon.x = Math.floor(Math.random() * (stage.stageWidth - balloon.width));
      balloons.push(balloon);
      addChild(balloon);
      timer.reset();
      timer.start();
    }
    
    private function popBalloon(e:MouseEvent):void {
      e.target.x = Math.floor(Math.random() * (stage.stageWidth - e.target.width));
      e.target.reset();
      score++;
    }
  }
}

Conclusion

In this tutorial you have learned how to make a simple pop-the-balloons game in ActionScript3.

Extra Credit

Even I will admit the graphics are a bit underwhelming. What about adding a background image? Perhaps a few floating clouds to add a little distraction? Could even increase the difficulty by having the balloons get a little smaller every time they are clicked on. And putting the score on the game page (in the top left corner, perhaps).

Posted By:

Comments

  • BJ Griffin

    Hey There,

    This is a great tutorial, but then how do we get this to run? I tried to modify this and then run it in Flash CS6 and I get an error saying the package cannot be nested.

    Any ideas?

    Thanks!

    • http://richard.parnaby-king.co.uk/ Richard

      I need more information. How have you tried to run this code in CS6?

  • Rm

    Hello,

    I tried to run the downloaded source code but its fails to build.
    That’s the error code :
    “\com\greensock\TweenLite.as: Error: A file found in a source-path must have the same package structure ”, as the definition’s package, ‘com.greensock’.”

    • http://richard.parnaby-king.co.uk/ Richard Parnaby-King

      Hi Rm,

      When including additional packages, you need to map the file structure to the same as the package name. In this case, ‘com.greensock’ becomes a folder structure ‘/com/greensock’. I hope that answers your question :)

  • Rm

    Hey Richard,

    I commented everything that got a Tween in it in the ballon.as file and the project builds fine ,it launches and the balloons are just sitting down .So this indicates the problem is when your passing arguments to the constructor in the greensock package class.However,maybe I am doing something wrong when I am adding the “com” package in flashdevelop. That’s how I did it right click my Package file -Properties-class path-Add Classpaths -and selecting the greensock file under the “com” folder.

    Thanks!!! Great Tutorial I have been looking over the internet for one …Anyways I will be adding more levels to the game

  • Joe Tran

    Hi Richard, thanks for very detail tutorial. I have dowloaded the source and run the swf file. However, I wonder how could you execute the .as file with any link to .fla file? Thank for replying.

    • http://richard.parnaby-king.co.uk/ Richard Parnaby-King

      Hi Joe,

      For this project I did not use Flash, therefore there was no .fla file. I used FlashDevelop – http://www.flashdevelop.org/ – which allows you to compile the code using either Flash CS3 (and above) or the Flex compiler (which is what I use) or a bunch of other options. This way I can code and compile swf files without having to pay the hefty cost for Flash CS.

  • Richard Parnaby-King

    Hi Rm,

    When including additional packages, you need to map the file structure to the same as the package name. In this case, ‘com.greensock’ becomes a folder structure ‘/com/greensock’. I hope that answers your question :)

  • Ween Solis

    sir can i download your game for free..?

    • http://richard.parnaby-king.co.uk/ Richard Parnaby-King

      The source code is available at the top of the page for anyone to download freely.

  • ABOUT

    Having five years of programming experience in PHP, Zend Framework and ActionScript3, I have a very strong working knowledge of object orientated programming.

    I am a PC Gamer! Playing FPS, RTS, RPG and the occasional MMO since 1996 I have a huge number of a variety of fast-paced games.

  • Recent Posts

  • Categories

  • RSS SUBSCRIBE TO OUR FEED

  •