Hostingheaderbarlogoj
Join InMotion Hosting for $3.49/mo & get a year on Tuts+ FREE (worth $180). Start today.
Advertisement

Design and Develop a Fantastic Flash Shooting Gallery Game

by
Gift

Want a free year on Tuts+ (worth $180)? Start an InMotion Hosting plan for $3.49/mo.

In this Premium Tutorial, we'll learn how to combine several ActionScript 3 classes and skills to create a fantastic shooting gallery game.


Step 1: Brief Overview

Using the Flash Tools we'll create good looking graphics that will be powered by several ActionScript 3 classes like MouseCursor, Tween Nano, Sprite, Timers and other Events.

The user will be able to input a player's name and destroy a predefined number of dartboards before the game ends.


Step 2: Document Settings

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



Step 3: Interface


A colorful nice looking interface will power our code, this involves multiple shapes, buttons, custom cursors and more.

Continue to the next steps to learn how to create this GUI.


Step 4: Sky


A blue radial gradient will be the sky.

Select the Rectangle Tool (R) and create a 720x335 px rectangle, use the Color Panel to apply a #EFFDFE, #7FD7FF radial background.


Step 5: Clouds

Three main shapes will be used for the clouds, the rest will be duplicated MovieClips.


Use the Oval Tool (O) to create circles and ovals of different sizes, after you got the cloud shape you like, color them using this gradient fill #F1FBFF, #C3ECFF. Use the Gradient Transform Tool (F) to rotate the gradient.




Step 6: Mountains

Let's add some mountains to the scene.

Use the Rectangle Tool to create two rectangles accross the scene, use this gradient on them #8DB400, #CFF500.


With the Selection Tool (V), grab the corners of the rectangle and give them a less squared form.


Use the same technique only this time dragging from the sides of the rectangles, (you'll se a curve in the mouse cursor), use the Gradient Transform tool to rotate the gradient.



Step 7: Grass

This is the grass graphic we'll be creating. It is made from three or four different shapes in different colors.


Use the Rectangle Tool to create a rectangle, and use the mountains technique to start modifiying the shape. You can see how the grass was created looking at the next image:


Once you have the first grass shape you just now have to modify the colors and sizes, then put them together and you're done.



Step 8: Ground

The ground graphic is pretty simple, a #5F4123 colored background, with some #3A2814 rocks.


Your background should look like this now:



Step 9: Info Panel

The Info Panel will show the player's name as well as the current score. Let's start by creating the background.

Use the Rectangle Primitive Tool to create a 230x40 px, #CCCCCC, alpha 60% rectangle and place it as seen in the image.


Duplicate the shape and change it to 225x30px, #000000, alpha 70%. Center the new shape in the gray background.


Convert the new shape to MovieClip and name it infoBg.

Use the Text Tool (T) to create two dynamic textfields and place them in the background.


This is the format used for the player name: Walway Rounded, 28pt, #6CA8E6, instance name: playerName.

The textfield on the side is: Walkway rounded, 32pt, #FFFFFF, instance name: score.


Step 10: Cursor

The custom cursor is composed by a series of rounded rectangles and a circle.


A look at the next image will give you a better understandig of how it was made.



Step 11: Dartboard

The Dartboard is one of the main elements in the game, it is the target to destroy.

Use the Oval tool to create a 80x80 px circle with this linear gradient #697368, #060604.


Duplicate the shape, resize it to 64x64 px, and change the gradient to #F6F6F6, #DDDDDD.


Use the Oval Primitive Tool to create a 46x46 px circle and modify the inner radius to 75.00. Use again the black gradient.


Duplicate the white circle, resize it to 18x18 px, and fill it with #AF4F50.


Convert the Shapes to MovieClip and name it Dartboard, be sure to check the Export for ActionScript box.


Step 12: Hits

A hit counter will be on the top-left corner of the stage.


Use the same format of the playerName Textfield, just change the color to #FEE75C. The dynamic textfield is called hits.


Step 13: Name Panel


This is the name panel, nothing difficult about it.

This will be first thing shown to the player. It contains an Input TextField named nameField and dartboard used as a button named beginButton.


Step 14: Sound

We'll play a sound when a dartboard is hit. There are many sites where you can download sound effects and music online, you can get the effect used in the tutorial here.


Step 15: Export Sound for ActionScript

To use the sound we first need to import it to the library. Press Cmd+R, browse to the sound you downloaded and click Open.


Open the library and right click the sound icon, select Properties and mark the Export for ActionScript box.


This ends the graphic phase, let the ActionScripting begin!


Step 16: New ActionScript Class

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



Step 17: Tween Nano


We'll use a different tween engine from the default included in flash, this will increase performance (it's also easier to use). You can download Tween Nano from its official website.


Step 18: Package

The package keyword allows you to organize your code into groups that can be imported by other scripts. It's recommended to name them starting with a lowercase letter and use intercaps for subsequent words for example: myClasses. It's also common to name them using your company's website: com.mycompany.classesType.myClass.

In this example, we're using a single class, so there isn't really a need to create a classes folder.

 
package 
{

Step 19: Import Directive

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.Sprite; 
import flash.ui.Mouse; 
import com.greensock.TweenNano; 
import flash.events.MouseEvent; 
import flash.events.Event; 
import flash.utils.Timer; 
import flash.events.TimerEvent;

Step 20: Declaring and Extending

Here we declare the class using the class definition keyword followed by the name that we want for the class, remember that you have to save the file using this name.

The extends keyword defines a class that is a subclass of another class. The subclass inherits all the methods, properties and functions, that way we can use them in our class.

 
public class Main extends Sprite 
{

Step 21: Variables

These are the variables we'll use, read the comments in the code to find out more about each one.

 
private var gridY:Array = new Array(); //Stores the y coordinate in which a dartboard can be positioned 
private var gridX:Array = new Array();//Stores the x coordinate in which a dartboard can be positioned 
private var xPos:int = 0; //The latest x position used by a dartboard 
private var yPos:int = 0;//The latest y position used by a dartboard 
private var dartboards:Array = new Array(); //Stores the dartboards sprites 
private var smack:SmackSound = new SmackSound(); //The sound that will play when a dartboard is destroyed 
private var timer:Timer = new Timer(3000); //The amount of time to wait before change the dartboards in screen 
private var currentDartboards:int = 0; //The dartboards already shown in stage, checks for level completion 
private var levelComplete:int = 30; //The dartboards to show to complete the level 
private var scorePanel:ScorePanel = new ScorePanel(); //A score panel instance

Step 22: 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 or runs using the Document Class.

It calls the necessary functions to start the game. Check those functions in the next steps.

 
public function Main():void 
{ 
	startCustomCursor(); 
	namePanelHandler(); 
	updateScore(); 
	bg.addEventListener(MouseEvent.MOUSE_DOWN, addHits); 
}

Step 23: Name Panel Handler

This function animates the Name Panel to stage and adds a listener to the button to set the name in the Textfield when activated.

 
private function namePanelHandler():void 
{ 
	namePanel.beginButton.stop(); 
	namePanel.beginButton.addEventListener(MouseEvent.MOUSE_UP, setPlayerName); 
	TweenNano.from(namePanel, 0.5, {y: -namePanel.height/2}); 
}

Step 24: Set Player Name

Sets the name written in the Name Panel textfield to the playerName field in the Info panel.

 
private function setPlayerName(e:MouseEvent):void 
{ 
	smack.play(); 
	namePanel.beginButton.gotoAndPlay(3); 
	playerName.text = namePanel.nameField.text; 
	TweenNano.to(namePanel, 0.5, {y: stage.stageHeight + namePanel.height/2, onComplete: beginGame}); 
}

Step 25: Add Custom Cursor

The following function makes the custom cursor draggable, it also hides the default mouse cursor.

 
private function startCustomCursor():void 
{ 
	Mouse.hide(); 
	cursor.startDrag(true); 
}

Step 26: Dartboards Grid

This is an important function, it calculates the stage area and creates a grid based on the size of the Dartboard (80px).

We'll use the resulting arrays later to prevent the dartboards from appearing in front of each other.

 
private function calculateGrid():void 
{ 
	gridX = []; 
	gridY = []; 
 
	for (var h:int = 1; h <= (stage.stageHeight - 160) / 80; h++) //The - reduces invisible/used area 
	{ 
		gridY.push(80 * h); 
	} 
 
	for (var v:int = 1; v <= (stage.stageWidth - 160) / 80; v++) 
	{ 
		gridX.push(80 * v); 
	} 
}

Step 27: Add Random Dartboards

The next function will create and add the dartboards established by the amount parameter.

It follows this logic:

  • Calculate the grid (it only does this one time)
  • Create a new Dartboard instance and prevent to play it
  • Use a random position from the positions arrays
  • Remove the last position used to avoid adding dartboards in the same place
  • Add the destroy listener to the dartboard
  • Add dartboard to stage and animate it
  • Add dartboard to the dartboards array
  • Get next highest depth (frequently asked in AS3, take note) for the custom cursor
  • Add one to the dartboards shown list
 
private function addRandomDartboards(amount:int):void 
{ 
	calculateGrid(); 
 
	for (var i:int = 0; i < amount; i++) 
	{ 
		var dartboard:Dartboard = new Dartboard(); 
 
		dartboard.stop(); 
 
		xPos = gridX[Math.floor(Math.random() * gridX.length)]; 
		yPos = gridY[Math.floor(Math.random() * gridY.length)]; 
 
		dartboard.x = xPos + 40; 
		dartboard.y = yPos + 40; 
 
		gridX.splice(gridX.indexOf(xPos), 1); 
		gridY.splice(gridY.indexOf(yPos), 1); 
 
		dartboard.addEventListener(MouseEvent.MOUSE_DOWN, destroyDartboard); 
 
		addChild(dartboard); 
 
		TweenNano.from(dartboard, 0.6, {rotationY: 180}); 
		TweenNano.from(dartboard, 0.6, {scaleX: 0.4}); 
		TweenNano.from(dartboard, 0.6, {scaleY: 0.4}); 
 
		dartboards.push(dartboard); 
 
		setChildIndex(cursor, (numChildren - 1)); 
 
		currentDartboards++; 
	} 
}

Step 28: Destroy Dartboard

This function handles the animation for a darboard that has been hit, it also removes the dartboard from the dartboards array and adds new ones if there are no more clips in stage.

Scores and scores animations are handled here too.

 
private function destroyDartboard(e:MouseEvent):void 
{ 
	smack.play(); //The hit sound 
	e.target.removeEventListener(MouseEvent.MOUSE_DOWN, destroyDartboard); 
	e.target.gotoAndPlay(3); 
	e.target.addEventListener(Event.ENTER_FRAME, removeDartboard); 
 
	dartboards.splice(dartboards.indexOf(e.target), 1); //Remove from array 
 
	if (dartboards.length == 0) //Add new darboards if all have been destroyed 
	{ 
		timer.stop(); 
		addRandomDartboards(5); 
		timer.start(); 
	} 
 
	/*Update scores, hits and play hit animation*/ 
 
	updateScore(1); 
	updateHits(1); 
 
	var plusOne:ScorePlus = new ScorePlus(); 
 
	plusOne.x = e.target.x; 
	plusOne.y = e.target.y + plusOne.height; 
 
	addChild(plusOne); 
 
	TweenNano.from(plusOne, 0.5, {scaleX: 0.5}); 
	TweenNano.from(plusOne, 0.5, {scaleY: 0.5, onComplete:removeScoreGFX, onCompleteParams: [plusOne]}); 
}

Step 29: Remove Score Graphics

Removes the Score "+1" movieclip.

 
private function removeScoreGFX(target:Sprite):void 
{ 
	removeChild(target); 
}

Step 30: Remove Dartboard

Checks if the darboard animation has ended and removes it if true.

 
private function removeDartboard(e:Event):void 
{ 
	if (e.target.currentFrame == 8) 
	{ 
		e.target.removeEventListener(Event.ENTER_FRAME, removeDartboard); 
		removeChild(e.target as Sprite); 
	} 
}

Step 31: Update Score

Adds the indicated score to the score TextField.

 
private function updateScore(addToScore:int = 0):void 
{ 
	score.text = String(int(score.text) + addToScore); 
}

Step 32: Update Hits

Adds 1 to the hits score, this is called when a dartboard is destroyed.

 
private function updateHits(addToHits:int = 0):void 
{ 
	hits.text = String(int(hits.text) + addToHits); 
	TweenNano.from(hits, 0.3, {y: -5}); 
}

Step 33: Add Hits

Adds the total hit score to the score TextField.

 
private function addHits(e:MouseEvent):void 
{ 
	score.text = String(int(score.text) + int(hits.text)); 
	hits.text = "0"; 
}

Step 34: Begin Game

Initiates the game.

Creates the dartboards, removes the players name panel and starts the timer.

 
private function beginGame(restarting:Boolean = false):void 
{ 
	if (! restarting) 
	{ 
		removeChild(namePanel); 
	} 
 
	addRandomDartboards(5); 
	timer.addEventListener(TimerEvent.TIMER, removeRemainingListeners); 
	timer.start(); 
}

Step 35: Remove Remaining

Removes the dartboards that weren't hit and adds new ones if the level isn't complete.

 
private function removeRemaining():void 
{ 
	for (var i:int = dartboards.length-1; i >= 0; i--) 
	{ 
		removeChild(dartboards[i]); 
		dartboards.length = i; 
 
		if (dartboards.length == 0 && currentDartboards < levelComplete) 
		{ 
			addRandomDartboards(5); 
			timer.start(); 
		} 
		else if (dartboards.length == 0 && currentDartboards >= levelComplete) //If level complete 
		{ 
			levelCompleted(); 
		} 
	} 
}

Step 36: Level Complete

If all the allowed dartboards have been displayed in stage, this function will execute.

It calculates the final score, hides the info panel, and shows the ScorePanel.

 
private function levelCompleted():void 
{ 
	score.text = String(int(score.text) + int(hits.text)); 
	hits.text = "0"; 
 
	score.visible = false; 
	playerName.visible = false; 
 
	TweenNano.to(infoBg, 0.5, {x: -infoBg.width/2}); 
 
	scorePanel.x = stage.stageWidth + scorePanel.width / 2; 
	scorePanel.y = stage.stageHeight / 2; 
 
	scorePanel.myScore.text = score.text; 
	scorePanel.playAgain.addEventListener(MouseEvent.MOUSE_UP, restart); 
 
	addChild(scorePanel); 
 
	setChildIndex(cursor, (numChildren - 1)); 
 
	TweenNano.to(scorePanel, 0.5, {x: stage.stageWidth/2}); 
}

Step 37: Restart

The next lines make the restart possible. You'll find everything explained in the comments.

 
private function restart(e:MouseEvent):void 
{ 
	score.visible = true; //hides the score 
	score.text = "0"; //Sets the score to 0 
	playerName.visible = true; //Shows again the player name 
 
	scorePanel.playAgain.removeEventListener(MouseEvent.MOUSE_UP, restart); //Removes the listener from the button in the score panel 
 
	TweenNano.to(infoBg, 0.5, {x: infoBg.width/2}); //Animates the info panel and the score panel 
	TweenNano.to(scorePanel, 0.5, {x: stage.stageWidth + scorePanel.width/2, onComplete: removeScorePanel}); 
 
	currentDartboards = 0; //Resets the current dartboards list 
	beginGame(true); //starts the game 
}

Step 38: Remove Score Panel

Removes the score panel from the stage when the animation is complete.

 
private function removeScorePanel():void 
{ 
	removeChild(scorePanel); 
}

Step 39: Document Class


We'll make use of the Document Class in this tutorial, if you don't know how to use it or are a bit confused please read this QuickTip.


Step 40: Test Movie


You're now ready to test your game!, go to Flash and press Cmd+Return, check that everything works as expected and have fun!


Conclusion

The final result is a colorful and entertaining game, try customizing it, what about a port to Android?

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

Advertisement