Video icon 64
Learning to code? Skill up faster with our practical video courses. Start your free trial today.
Advertisement

Create a Balloon Popping Game in Flash

by

One of the most popular Flash games ever is Bloons, in which you play a monkey throwing darts to pop balloons. It's spawned numerous sequels, even branching out into other genres like tower defense. This tutorial will show you how to create your own balloon popping game, using the QuickBox2D engine.


Final Result Preview

Let's take a look at the final result we will be working towards:

Click and hold to determine the angle of the shot. Try to pop all the balloons!


Step 1: Brief Overview

In this tutorial we'll use a series of ActionScript classes to create a Bloons Inspired game. The objective of the game is to shoot at the balloons to pop them all.


Step 2: Flash Document Settings

Open Flash and create a 480 pixels wide, 320 pixels tall document. Set the Frame rate to 24fps.


Step 3: Interface

A colorful and simple interface will be used, featuring several shapes, buttons and MovieClips. Over the next few steps we will build this GUI. The squirrel and acorn graphics are from openclipart.org.


Step 4: Background

This background was created in Flash using simple rectangle and oval shapes. The brown bar at the bottom will serve as an information bar.


Step 5: Title and Balloons

To create the Title, select the Text Tool (T) and change the color to #EEEEEE; write your title text (I've used the font GoodDog) and add a simple drop shadow. For the balloon, select the Oval Tool (O) and create a 20x30 px #FFCE47 oval. Use the Poly Star Tool for the little triangle below it.


Step 6: Buttons

Use again the Text Tool to create two buttons as shown in the image above. Convert them to buttons and give them descriptive instance names so we can easily use them later in the code. Convert the graphics on the stage to a single MovieClip and name it TitleView - remember to check the Export for ActionScript box.


Step 7: Game Screen

This is the Game Screen, which contains all the dynamic and interactive elements of the game. More of them will be generated at runtime using ActionScript. You can read the instance names in the image above.


Step 8: Credits Screen

The Credits screen will appear in front of the Title screen; use the graphics and fonts from before to create it. Name it CreditsView and remember to check the Export for ActionScript box.


Step 9: Alert

An alert will be shown when all the balloons have been popped; it will display a game over message and the score. Use the Rectangle Tool to create it and set its instance name to AlertView. Again, mark the Export for ActionScript box.


Step 10: Sounds

We'll use sound effects to enhance the feeling of the game; you can find the sound used in this example in Soungle.com using the keyword pop.


Step 11: TweenNano

We'll use a different tween engine from the default included in Flash, this will increase performace as well as being easier to use.

You can download TweenNano from its official website.


Step 12: QuickBox 2D

We'll use the useful QuickBox2D physics library to create this game. If you are unfamiliar with it, you can follow the Introduction Series from Activetuts+.

You can download QuickBox2D from its official website.


Step 13: Set Document Class


We'll make our application interactive by using an external class. Add its name to the Class field in the Publish section of the Properties panel to associate the FLA with the Main document class.


Step 14: Create a New ActionScript Class


Create a new (Cmd + N) ActionScript 3.0 Class and save it as Main.as in your class folder.


Step 15: Class Structure

Create your basic class structure to begin writing your code.

 
package  
{ 
	import flash.display.Sprite; 
	 
	public class Main extends Sprite 
	{ 
		public function Main():void 
		{ 
			// constructor code 
		} 
	} 
}

Step 16: Required Classes

These are the classes we'll need to import for our class to work; the import directive makes externally defined classes and packages available to your code.

 
import flash.display.MovieClip; 
import com.actionsnippet.qbox.*; 
import com.greensock.TweenNano; 
import com.greensock.easing.Expo; 
import flash.events.MouseEvent; 
 
import Box2D.Common.Math.*; 
import flash.events.Event; 
import flash.net.navigateToURL; 
import flash.net.URLRequest;

Step 17: Variables

These are the variables we'll use. Read the comments in the code to know more about them; some of their names are self explanatory so there will be no comment there.

 
private var titleView:TitleView = new TitleView(); 
private var credits:CreditsView; 
private var world:QuickBox2D; 
private var acorn:QuickObject; 
private var acorns:Array = [];//stores the acorns thrown 
private var contacts:QuickContacts; //used to handle collisions in quickbox2d 
private var balloons:Array = []; //stores the balloons in stage 
private var yImpulse:Number = 0; //vertical strength to shoot the acorn 
private var xImpulse:int = 3; //default horizontal strength the acorn is thrown 
private var pop:Pop = new Pop(); //the sound in the library

Step 18: Constructor

The constructor is a function that runs when an object is created from a class, this code is the first to execute when you make an instance of an object. The constructor of the document class is a special case: it runs at the start of the game.

We use this to call the necessary functions to start the game. Check those functions in the next steps.

 
public final function Main():void 
{ 
	//Code 
}

Step 19: Add Title View

We start by adding the TitleView from the Library to the stage.

 
addChild(titleView); 
startButtonListeners();

Step 20: Start Buttons Listeners

This will add the mouse listeners to the buttons in the title view, which will take us to the game or credits screen.

 
private final function startButtonListeners(action:String = 'add'):void 
{ 
	if(action == 'add') 
	{ 
		titleView.creditsBtn.addEventListener(MouseEvent.MOUSE_UP, showCredits); 
		titleView.playBtn.addEventListener(MouseEvent.MOUSE_UP, showGameView); 
	} 
	else 
	{ 
		titleView.creditsBtn.removeEventListener(MouseEvent.MOUSE_UP, showCredits); 
		titleView.playBtn.removeEventListener(MouseEvent.MOUSE_UP, showGameView); 
	} 
}

Step 21: Show Credits

The Credits screen is shown when the user clicks the Credits button. A mouse listener is added to the full MovieClip to remove it.

 
private final function showCredits(e:MouseEvent):void 
{ 
	titleView.creditsBtn.visible = false; 
	titleView.playBtn.visible = false; 
	credits = new CreditsView(); 
	addChild(credits); 
	TweenNano.from(credits, 0.3, {x:-credits.width, onComplete:function():void{credits.addEventListener(MouseEvent.MOUSE_UP, hideCredits);}}); 
}

Step 22: Hide Credits

When the Credits screen is clicked it will be tweened back and removed from the stage.

 
private final function hideCredits(e:MouseEvent):void 
{ 
    TweenNano.to(credits, 0.3, { 
        x: -credits.width, 
        onComplete: function (): void { 
            titleView.creditsBtn.visible = true; 
            titleView.playBtn.visible = true; 
            credits.removeEventListener(MouseEvent.MOUSE_UP, hideCredits); 
            removeChild(credits); 
            credits = null; 
        } 
    }); 
}

Step 23: Show Game View

The following lines remove the Title screen and leave the Game Screen visible. Here we also call the necessary functions to start the game; those functions are explained in the next steps.

 
private final function showGameView(e:MouseEvent):void 
{ 
    TweenNano.to(titleView, 0.3, { 
        y: -titleView.height, 
        onComplete: function (): void { 
            startButtonListeners('rmv'); 
            removeChild(titleView); 
            titleView = null; 
            startGame(); 
        } 
    }); 
}

Let's stop here to make a quick test and make sure that our game code is working:

Keep in mind that some lines have been commented out, as some functions haven't been created yet.

Remember that the Milestones are included in the source files, so if for some reason your file doesn't mimic this one take a look at the source to see what's causing that.


Step 24: Game Listeners

This function adds the mouse listeners required to perform the acorn shooting.

 
private final function gameListeners(action:String = 'add'):void 
{ 
	if(action == 'add') 
	{ 
		bg.addEventListener(MouseEvent.MOUSE_DOWN, startCharge); 
		bg.addEventListener(MouseEvent.MOUSE_UP, shot); 
		restartBtn.addEventListener(MouseEvent.MOUSE_UP, restartLvl); 
		stage.addEventListener(Event.ENTER_FRAME, update); 
	} 
	else 
	{ 
		bg.removeEventListener(MouseEvent.MOUSE_DOWN, startCharge); 
		bg.removeEventListener(MouseEvent.MOUSE_UP, shot); 
		restartBtn.removeEventListener(MouseEvent.MOUSE_UP, restartLvl); 
		stage.removeEventListener(Event.ENTER_FRAME, update); 
	} 
}

Step 25: Start Game

Here we start the game by creating the Box2D world and calling the functions that will create the balloons and handle mouse events.

 
private final function startGame():void 
{ 
	/* Hide gCircle */ 
	 
	gCircle.visible = false; 
	 
	/* New B2D world */ 
	 
	world = new QuickBox2D(this, {debug:0}); 
	contacts = world.addContactListener(); 
	contacts.addEventListener(QuickContacts.ADD, onAdd); 
	 
	/* Create balloon function */ 
	 
	gameListeners(); 
	createBalloons(); 
}

Step 26: Create Balloons

Nested for loops are used to place the balloons on the stage. This function will use the QuickBox2D addBox method to create a new Box2D object that will be set as a Sensor - this means there will be no physics reaction to the collision (i.e. the acorn won't bounce off it), but a collision will still be detected. Using this method we can destroy the balloon but let the acorn continue on its way as if nothing happened.

The balloon is then added to an array; this will grant us access to all the balloons outside this function.

 
private final function createBalloons(h:int = 5, v:int = 3):void 
{ 
	for(var i:int = 0; i < h; i++) 
	{ 
		for(var j:int = 0; j < v; j++) 
		{ 
			var balloon:QuickObject = world.addBox({x:10 + (i * 0.66), y:4 + (j * 1), width: 0.66, height: 1, skin:Balloon, fixedRotation:true, draggable:false, density:0}); 
			balloon.shape.m_isSensor = true; 
			balloons.push(balloon); 
		} 
	} 
	 
	/* Set balloon counter */ 
	 
	targetTF.text = String(balloons.length); 
	 
	/* Start Physics */ 
	 
	world.start(); 
}

Of course, you don't have to use nested for loops to position the balloons; this is the easiest way to position them in a grid, but you can position them manually if you prefer.


Step 27: Collision Detection

This function handles the collision mentioned in Step 26. The first thing to do is go through the balloons array, checking each one to see whether it is colliding with the acorn.

 
private final function onAdd(e:Event):void 
{ 
	for(var i:int = 0; i < balloons.length; i++) 
	{ 
		if(contacts.isCurrentContact(balloons[i], acorn)) 
		{

Step 28: Destroy Balloon

If the collision is true, we call the destroy() method of the balloon QuickObject and remove the element from the array.

 
balloons[i].destroy(); 
balloons.splice(i, 1);

Step 29: Play Sound

Then we play a sound indicating the hit, enhancing the game feeling.

 
pop.play();

Step 30: Update Score and Target Counters

The score and target counters are updated according to the balloons popped and the balloons left.

 
scoreTF.text = String(int(scoreTF.text) + 50); 
targetTF.text = String(balloons.length);

Step 31: Check for Level Complete

An alert is called when all the balloons are popped; we'll see this function later in the tutorial.

 
if(targetTF.text == '0') 
{ 
	alert(); 
}

Step 32: Start Charge

This code will reveal the acorn's direction indicator, reset the acorn's y-impulse variable, and add an enterframe listener that will handle the aim.

 
private final function startCharge(e:MouseEvent):void 
{ 
	yImpulse = 0; 
	gCircle.visible = true; 
	gCircle.addEventListener(Event.ENTER_FRAME, charge); 
}

Step 33: Charge

The aim indicator rotates to show the direction in which the acorn will be fired, and adjusts the y-impulse variable accordingly. The direction of the shot is affected by two variables, xImpulse and yImpulse, which are combined to form an impulse vector later. xImpulse stays constant, and yImpulse is changed as the user holds down the mouse button.

 
private final function charge(e:Event):void 
{ 
	gCircle.rotation -= 3; 
	yImpulse -= 0.2; 
 
	/* Prevent over-rotation */ 
	if(gCircle.rotation < -80) 
	{ 
		yImpulse = -5.4; 
		gCircle.rotation = -80; 
	} 
}

Step 34: Shot

The following actions occur when the mouse button is up.

 
private final function shot(e:MouseEvent):void 
{ 
	/* Hide gCircle */ 
	 
	gCircle.removeEventListener(Event.ENTER_FRAME, charge); 
	gCircle.visible = false; 
	gCircle.rotation = 0; 
	 
	/* Create new Acorn */ 
	 
	acorn = world.addBox({x:2.76, y:7.33, width: 0.66, height: 0.53, skin:Acorn, fixedRotation:true, draggable:false, density:1}); 
	acorns.push(acorn); 
	 
	/* Shoot acorn */ 
	 
	var impulse:b2Vec2 = new b2Vec2(xImpulse, yImpulse); 
	acorn.body.ApplyImpulse(impulse, acorn.body.GetWorldCenter()); 
	 
	/* Update Acorn counter */ 
	 
	acornsTF.text = String(int(acornsTF.text) -1); 
}

Let's stop here to make a quick test and make sure that our game code is working:

Keep in mind that some lines have been commented out as those functions haven't been created yet.


Step 35: Update Function

The update function will perform a series of EnterFrame operations. Let's see those actions in the following steps.

 
private final function update(e:Event):void 
{

Step 36: Remove Offstage Acorns

The next lines will remove every acorn that goes off the stage.

 
/* Remove offstage acorns */ 
	 
	for(var i:int = 0; i < acorns.length; i++) 
	{ 
		if(acorns[i].y > 10.66) 
		{ 
			acorns[i].destroy(); 
			acorns.splice(i, 1);

Step 37: Check for Level Failed

The game is over when the player runs out of acorns (or destroys all the balloons as mentioned before).

 
/* Check for level failed */ 
	 
			if(int(acornsTF.text) &lt;= 0) 
			{ 
				alert('lose'); 
			} 
		} 
	} 
}

Step 38: Restart Level

This code runs when the Restart button is clicked. It will reset the necessary variables and listeners to restart the level.

 
private final function restartLvl(e:MouseEvent):void 
{ 
	/* Remove Listeners */ 
	 
	gameListeners('rmv'); 
	 
	/* Destroy World */ 
	 
	world = null; 
	 
	/* Destroy Balloons, reset score and acorns */ 
	 
	for(var i:int = 0; i < balloons.length; i++) 
	{ 
		balloons[i].destroy(); 
		scoreTF.text = '0'; 
		acornsTF.text = '5'; 
	} 
	 
	balloons = [];//clear balloons array 
	 
	startGame(); 
}

Step 39: Alert

This function will stop the game and show the Game Over message. It also adds a mouse listener to reset the game when clicked.

 
private final function alert(gameState:String = 'win'):void 
{ 
	gameListeners('rmv'); 
	world.stop(); 
	 
	var alert:AlertView = new AlertView(); 
	 
	alert.x = stage.stageWidth * 0.5; 
	alert.y = stage.stageHeight * 0.5; 
	alert.scoreTF.text = scoreTF.text; 
	alert.addEventListener(MouseEvent.MOUSE_UP, restart); 
	 
	if(gameState == 'lose') 
	{ 
		alert.titleTF.text = 'Level Failed!'; 
	} 
	 
	addChild(alert); 
	TweenNano.from(alert, 0.6, {scaleX: 0.2, scaleY: 0.2, ease:Expo.easeOut}); 
}

Step 40: Restart

This code will reload the SWF, restoring any values and returning to the initial screen.

 
private final function restart(e:MouseEvent):void 
{ 
	navigateToURL(new URLRequest(stage.loaderInfo.url), '_level0'); 
}

Conclusion

Make your own tweaks to the game and enjoy creating it. Perhaps you could change the layout of the balloons, or add new levels, or alter the graphics.

I hope you liked this tutorial, thank you for reading!

Advertisement