Advertisement

Create a "Frenzic" Inspired Puzzle Game in Flash

by

Take a look at this Premium Tutorial to create an entertaining puzzle game, inspired by Frenzic, using Flash and ActionScript 3.

In the demo above, fill the outer boxes with colored squares. You get more points for filling a box with squares that are all the same color.


Step 1: Brief Overview

Using the Flash drawing tools we'll create a good looking graphic interface that will be powered by several ActionScript 3 classes.

The player will be able to click on four different locations to sort the color blocks on the squares, more points are earned if you fill a square with a single block color.


Step 2: Flash Document Settings

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



Step 3: Interface


A colorful nice looking interface will be displayed, this involves multiple shapes, buttons, sounds and more.

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


Step 4: Background


Select the Rectangle Tool (R) to create a 320x480px #0D6191, #001217 rectangle and center it in the stage. Use the same tool to crate a 2x480px black line with 20% alpha, press CMD+D to duplicate it multiple times, and spread the lines out to get the effect in the image above.


Step 5: Title View


Select the Text Tool (T), select a good looking font and write your game title. I used this format: Orbitron Bold, 60pt, #A3FF24. You can add a simple glow filter to make it look better.

Use the same technique to create two buttons, align them to the center and name them startB and creditsB. Convert all to a Movie Clip and set its name to TitleView; mark the Export for ActionScript box and delete the clip from the stage.


Step 6: Score and Lives


This will be the GameView. Add the background MC to the stage and create two Dynamic Text Fields and place them as shown in the image. Name the Text Fields livesTF and scoreTF.


Step 7: Containers


Use the Rectangle Tool (R) to create a 70x70px square and fill it using the background gradient, convert it to MC and press CMD+D to duplicate it so that you have five in total. Use the Align Panel to place them as shown in the image.

The instance names should match their positions -- that is: up, down, left, right and the center will be mainHolder.


Step 8: Blocks


Use the same technique used in the last step to create three 30x30px blocks, convert them to MC and name them according to its color: OrangeBlock, PurpleBlock and GreenBlock. Don't forget to mark the Export for ActionScript box.


Step 9: Alert


An alert will be shown when you lose all your lives, and it will show the final score you reached. Use the Rectangle Primitive Tool to create it and fill it with this Linear gradient: #000000 to #333333. Set its instance name to AlertView and mark the Export for ActionScript box.


Step 10: Credits


This screen will be easy to make as we already have all the graphics. Set its instance name to CreditsView and mark the Export for ActionScript box.


Step 11: Tween Nano


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

You can download Tween Nano from its official website.


Step 12: Soungle


We'll use Sound Effects to enhance the feeling of the game, you can find the sounds used in this example in Soungle.com using the keywords bell and buzz. Add them to your Library, with class names of Bell, Bell4, and Buzz, respectively.


Step 13: 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 14: 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 15: 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.Sprite; 
import flash.events.MouseEvent; 
import com.greensock.TweenNano; 
import com.greensock.easing.Bounce; 
import flash.utils.Timer; 
import flash.events.TimerEvent; 
import flash.net.navigateToURL; 
import flash.net.URLRequest;

Step 16: 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 blockColor:Vector.<String> = new Vector.<String>(); //Stores the available colors, used to create new block instances 
private var blocks:Vector.<Sprite> = new Vector.<Sprite>();//Will store all the blocks in screen to access them anytime 
private var positions:Vector.<int> = new Vector.<int>();//Holds the possible blocks positions 
private var currentXPosition:int; 
private var currentYPosition:int; 
private var eventTarget:Object;//Used to access the event target of the place function 
private var timer:Timer = new Timer(3000);//You'll have 3 seconds to place the block in the center 
private var lives:int = 5; 
private var score:int = 0; 
private var bell:Bell = new Bell(); 
private var bell4:Bell4 = new Bell4(); 
private var buzz:Buzz = new Buzz();

Step 17: 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 (when in the Document Class) the first to run when the project loads.

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

 
public final function Main():void 
{ 
	//code... 
}

Step 18: Add Title View

We'll start by adding the TitleView to the stage; if we don't do this the first screen shown will be the GameView.

 
addChild(titleView);

Step 19: Add Vectors Values

The blockColor vector is used to create a new instance of the selected block; the parameters are the blocks that we created in the previous steps.

The positions vector stores the possible x and y positions that a block can have; mixing this will give us the final position relative to the mainHolder MC.

 
blockColor.push('orange', 'green', 'purple'); 
positions.push(5, 35); 
startButtonListeners();

Step 20: Button Listeners

In this function we add the mouse listeners to the buttons in the title view. These will take us to the game screen or the credits screen.

 
private final function startButtonListeners(action = 'add'):void 
{ 
	if(action == 'add') 
	{ 
		titleView.creditsB.addEventListener(MouseEvent.MOUSE_UP, showCredits); 
		titleView.startB.addEventListener(MouseEvent.MOUSE_UP, showGameView); 
	} 
	else 
	{ 
		titleView.creditsB.removeEventListener(MouseEvent.MOUSE_UP, showCredits); 
		titleView.startB.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 MC to remove it.

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

Step 22: Hide Credits

When the credits screen is clicked, it'll be tweened out of the stage and removed.

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

Step 23: Game View

When the Start button is pressed, the title view is tweened and removed revealing the game view.

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

Let's stop here to make a quick test and make sure that our screen switcher code is working (test Credits first so you can go back). Set the document class of your FLA to Main.

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 can be causing that.


Step 24: Game Listeners

Get back to the code and add the following function. It will add a Mouse Listener to the squares so you can click them to place the current block.

 
private final function addListeners():void 
{ 
	up.addEventListener(MouseEvent.MOUSE_UP, placeBlock); 
	right.addEventListener(MouseEvent.MOUSE_UP, placeBlock); 
	down.addEventListener(MouseEvent.MOUSE_UP, placeBlock); 
	left.addEventListener(MouseEvent.MOUSE_UP, placeBlock);

Step 25: Container Arrays

These arrays are created inside the square MovieClips, they are used to register the blocks, colors, and positions inside every square.

The letters represent the following positions:

  • a: top-left
  • b: top-right
  • c: bottom-left
  • d: bottom-right

Continue the addListeners() function:

 
	/* Create an array for every container to determine when full and the blocks color */ 
 
	up.blocks = []; 
	right.blocks = []; 
	down.blocks = []; 
	left.blocks = []; 
 
	/* Create an boolean for every container to avoid placing blocks in the same position */ 
 
	up.a = false; 
	right.a = false; 
	down.a = false; 
	left.a = false;  
 
	up.b = false; 
	right.b = false; 
	down.b = false; 
	left.b = false;  
 
	up.c = false; 
	right.c = false; 
	down.c = false; 
	left.c = false;  
 
	up.d = false; 
	right.d = false; 
	down.d = false; 
	left.d = false;  
 
	newBlock(true); 
}

Step 26: Generate Random Block Color

This code picks a random block color from the Vector, this will be used to instantiate the actual block. A parameter is used to determine whether the Timer to start counting will be activated.

 
private final function newBlock(firstTime:Boolean = false):void 
{ 
	/* New Block */ 
	 
	var randomBlock:int = Math.floor(Math.random() * 3); 
	var block:Sprite; 
	 
	switch(blockColor[randomBlock]) 
	{ 
		case 'orange': 
			block = new OrangeBlock(); 
			break; 
		case 'green': 
			block = new GreenBlock(); 
			break; 
		case 'purple': 
			block = new PurpleBlock(); 
			break; 
		default: 
			trace('BlockColor Error'); 
			break; 
	}

Step 27: Add New Block

After selecting the block color, the position where it will be placed is calculated using the positions Vector and then added to the blocks vector and the stage. Continue the newBlock() function:

 
	currentXPosition = positions[Math.floor(Math.random() * 2)]; 
	currentYPosition = positions[Math.floor(Math.random() * 2)]; 
 
	block.x = mainHolder.x + currentXPosition; 
	block.y = mainHolder.y + currentYPosition; 
	blocks.push(block); 
	addChild(block);

Step 28: Check For an Available Space

Before continuing with the game, we must check that the newly created block can actually be placed in a square container. The following code checks every container array to make sure that there is an empty position available in one of the boxes where the block can be placed; if there isn't, the block is destroyed and the function is called again to generate another one.

 
	/* Check for an available space to move the block */ 
 
	var position:Array = [currentXPosition, currentYPosition]; 
 
	if(String(position) == '5,5' && up.a && right.a && down.a && left.a) 
	{ 
		removeChild(block); 
		block = null; 
		newBlock(); 
		 
	} 
	else if(String(position) == '35,5' && up.b && right.b && down.b && left.b) 
	{ 
		removeChild(block); 
		block = null; 
		newBlock(); 
	} 
	else if(String(position) == '5,35' && up.c && right.c && down.c && left.c) 
	{ 
		removeChild(block); 
		block = null; 
		newBlock(); 
	} 
	else if(String(position) == '35,35' && up.d && right.d && down.d && left.d) 
	{ 
		removeChild(block); 
		block = null; 
		newBlock(); 
	}

If you used a different layout for your game, make sure you change the value that you're checking (i.e. not '35,35', as your game's blocks won't necessarily appear at that point).


Step 29: Start Timer

The timer starts counting when the function is called for the first time.

 
	if(firstTime) 
	{ 
		/* Start Timer */ 
		 
		timer.addEventListener(TimerEvent.TIMER, timesUp); 
		timer.start(); 
		counter.play(); 
	} 
}		//end the newBlock() function

Step 30: Lives

Three seconds are given to place a block in a square container, if that time passes and the block is still in the center square, a life will be removed.

 
private final function timesUp(e:TimerEvent):void 
{ 
	/* Remove Live */ 
	 
	lives--; 
	livesTF.text = String(lives); 
	buzz.play();

Step 31: Unused Blocks

After removing the life, the block in the center square will be destroyed and a new block will be generated. This code also checks if the player is out of lives and calls a function that we'll write later.

 
	/* Remove Unused Block */ 
 
	var i:int = blocks.length - 1; 
 
	removeChild(blocks[i]); 
	blocks[i] = null; 
	blocks.splice(i, 1); 
 
	/* Check if out of lives */ 
 
	if(lives < 1) 
	{ 
		alert(); 
	} 
	else 
	{ 
		/* Next Block */ 
		newBlock(); 
	} 
}

Let's take another pause to see how our code works at this point:


Step 32: Place Blocks

This function runs when the player clicks any of the container squares. It basically checks whether the correct position is available to place the square and places it if true. The function in the next step is called when the block is placed.

 
private final function placeBlock(e:MouseEvent):void 
{ 
	var i:int = blocks.length - 1; 
	eventTarget = e.target; 
	 
	/* Check if position is available */ 
	 
	var position:Array = [currentXPosition, currentYPosition]; 
	 
	if(String(position) == '5,5' && !e.target.a) 
	{ 
		blocks[i].x = e.target.x + position[0]; 
		blocks[i].y = e.target.y + position[1]; 
		e.target.a = true; 
		blockPlaced(); 
	} 
	else if(String(position) == '35,5' && !e.target.b) 
	{ 
		blocks[i].x = e.target.x + position[0]; 
		blocks[i].y = e.target.y + position[1]; 
		e.target.b = true; 
		blockPlaced(); 
	} 
	else if(String(position) == '5,35' && !e.target.c) 
	{ 
		blocks[i].x = e.target.x + position[0]; 
		blocks[i].y = e.target.y + position[1]; 
		e.target.c = true; 
		blockPlaced(); 
	} 
	else if(String(position) == '35,35' && !e.target.d) 
	{ 
		blocks[i].x = e.target.x + position[0]; 
		blocks[i].y = e.target.y + position[1]; 
		e.target.d = true; 
		blockPlaced(); 
	} 
}

Again, you might need to change the values that are checked here, to match the position of your blocks.


Step 33: Add Block to Array

When the block is placed in the container, we add the block to the array that keeps record of the stored blocks in that container. This will help us determine when the container is full.

 
private final function blockPlaced():void 
{ 
	var i:int = blocks.length - 1; 
	 
	/* Push block to container's blocks array */ 
	 
	eventTarget.blocks.push(blocks[i]);

Step 34: Score

Every block placed increments the score by one. When the box is full the score will increase by 50 and if the box is completely filled by a single color the total score will increase by 200.

 
	score++;

Step 35: Sound

A short sound will indicate that the block was placed.

 
	bell.play();

Step 36: Complete Single Color Container

The next code checks whether the container was filled by a single color block using the container array. It increments the score by 200, plays the corresponding sound and bounces the container as a visual sign. It also clears the variables in the container.

 
	/* If container is full and every block is same color */ 
			 
	if(eventTarget.blocks.length == 4 &&  
		String(eventTarget.blocks[0]) == String(eventTarget.blocks[1]) &&  
		String(eventTarget.blocks[1]) == String(eventTarget.blocks[2]) &&  
		String(eventTarget.blocks[2]) == String(eventTarget.blocks[3]) 
	) 
	{ 
		score += 200; 
		bell4.play(); 
		TweenNano.from( 
			eventTarget,  
			0.4,  
			{ 
				x:eventTarget.x - 5,  
				ease:Bounce.easeOut,  
				onComplete:function():void 
				{ 
					for(var j:int = 0; j < 4; j++) { 
						removeChild(eventTarget.blocks[j]); 
					} 
				eventTarget.blocks = []; 
				} 
			} 
		); 
		eventTarget.a = false; 
		eventTarget.b = false; 
		eventTarget.c = false; 
		eventTarget.d = false; 
	}

Step 37: Complete Container

This code runs when the container is full but the blocks inside aren't the same color.

 
/* If container is full but blocks are different colors */ 
 
else if(eventTarget.blocks.length == 4) 
{ 
	bell4.play(500, 2); 
	score += 50; 
	TweenNano.from( 
		eventTarget,  
		0.4,  
		{ 
			x:eventTarget.x - 5,  
			ease:Bounce.easeOut,  
			onComplete:function():void{ 
				for(var j:int = 0; j < 4; j++){ 
					removeChild(eventTarget.blocks[j]); 
				} 
			eventTarget.blocks = []; 
			} 
		} 
	); 
	eventTarget.a = false; 
	eventTarget.b = false; 
	eventTarget.c = false; 
	eventTarget.d = false; 
}

Step 38: Restart Timer

After clearing the full containers the score is set to the Text Field on the stage, the timer is reset, and another block is called.

 
	scoreTF.text = String(score); 
	timer.stop(); 
	timer.start(); 
	counter.gotoAndPlay(1); 
	newBlock(); 
}

Step 39: Alert

The alert function runs when the player is out of lives; it displays the final score reached and adds a listener to go back to the title screen.

 
private final function alert():void 
{ 
	timer.stop(); 
	counter.gotoAndStop(1); 
	var alert:AlertView = new AlertView(); 
	alert.messageBox.msgTF.text = 'Score: ' + String(score); 
	alert.addEventListener(MouseEvent.MOUSE_UP, restart); 
	addChild(alert); 
	TweenNano.from( 
		alert.messageBox,  
		0.7,  
		{ 
			y:-alert.messageBox.height,  
			ease:Bounce.easeOut 
		} 
	); 
}

Step 40: Restart

The next function will reload the swf, restarting any variable, method and returning to the Title Screen.

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

Conclusion

You've crated a very entertaining game, try to add your own features and graphics.

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

Advertisement