Memory Match Tutorial

Let’s let you have a little fun playing around with the game and then I will get into how to make it.

Play Hex Match
Play the Game Here

Now that you have an idea of what we are making, let’s take a look under the hood.

I made this using the Eclipse IDE and the AXDT plugin for Flex Development. I won’t go into� detail on how to set this up. It is pretty simple. If you use something else for Flex development you should still be able to use the code below.

With this game, I have a total of 2 .as files. The first is the main class MemoryMatch.as The second is the card class card.as

The basic structure of the MemoryMatch.as is as follows:

package MemoryMatch 
{
	import flash.display.*;
 
	public class MemoryMatch extends Sprite
	{
 
		public function MemoryMatch() :void
		{
                }
        }
}

On the first line we have the Package declaration. All you AS3 classes will be part of a Package. We are naming the package of our game after the game itself . Every thing inside the Package is enclosed in {}.

Next we have the import statement. This imports the flash.display package. We do this so we can use the Sprite class in the next line.

The Next Line is the class definition of our class. The first thing on the line is the word public. This defines the scope of the class. Public means that classes and AS files from outside have access to this. All class definitions need to be public if you actually want to use them. Next we define what we are writing here. In this instance we are creating a class so we use the class keyword. Then we have the name of our class. This is “MemoryMatch.” Finally we have the “extends Sprite” phrase. This means that we are basing this new class off of Flash’s built in Sprite Class. When we extend a class, the new class gains access to all properties and methods in the extended class and adds new properties and methods for use with this new class. Everything in the class definition is enclosed in {}

Finally we have the constructor of our class. This is a public function. It has to be public or no one would be able to use the class. The function keyword defines what we are writing. Next is the name of the function. Since this is a constructor, it must have the same name as the class. So in this instance it is called “MemoryMatch” It is followed by (). This is where you would put any parameters you would need to execute the function. We don’t need any for this constructor so we leave them empty. Finally the line ends with “:void” In AS3 we need to define the type of the returned value for the function. In this case, we are not returning any values so we declare it as void. If we were returning an integer, for example, we would put “:int” at the end of the function definition. Everything inside a function is enclosed in {}.

Now, let’s add some functionality to the constructor. First thing we need to do is define our stage instance. The stage is where everything in your game happens. So our new constructor will look like this:

public function MemoryMatch() :void
		{
			stage.stageHeight = 528;//264
			stage.stageWidth = 512;//256
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.frameRate = 12; 
		}

Here we set several values of our stage. The first is the width and height of the stage as defined by stageHeight and stageWidth. Next we want to set the scaleMode to NO_SCALE. If we don’t set this, Flash will attempt to scale the game to fit the display area. It can make your games not look right. So I set it to not scale here. Finally we set the frameRate. A memory match game does not need much in frame rates so I set it to 12. You can increase this if you want to.

Next we will create a function to show the title screen and play button.

private function showTitle():void
		{
			var loader:Loader = new Loader();
			addChild(loader);
			loader.load(new URLRequest('http://divineknightgaming.com/games/hexmatch/images/title.png'));
			loader.x = 10;  
            		loader.y = 10;
 
			var playAgain:TextField = new TextField();
	    		playAgain.text = "Play Game";
		    	playAgain.x = 230;
		    	playAgain.y = 260;
		    	playAgain.autoSize = TextFieldAutoSize.LEFT;
		    	playAgain.background = true;
		    	playAgain.backgroundColor = 0X0000CC;
		    	playAgain.textColor = 0Xffffff;
		    	playAgain.border = true;
		    	playAgain.borderColor = 0X000000;
		    	addChild(playAgain);
	    		playAgain.addEventListener(MouseEvent.CLICK, restartGame); 
		}

First thing you might notice is that this function has the keyword “private” in front of it. This means that this function cannot be accessed anywhere outside this class definition.

Next we need to do one thing before we can use this and before I explain what is happening here. We need to add a call to this function in the constructor of our class. So after we set the frame rate of the stage, we need to add the following line:

showTitle();

We also need to add the following import statements to our package. So put the following line below the line where we import flash.display.*

import flash.events.*;
import flash.text.*;
import flash.net.*;
import flash.utils.*;

We need to add this so that we can handle events in this class.

So first we are creating Title Screen Image. We do this by first creating a new Loader object. This Flash class allows us to load external resources into our game. Then we add this loader object as a child to the class. We need to do this before we try to manipulate it. Next we load in an image using the loader’s .load function. We pass in a new URLRequest object with the url to the image. I am putting the full http path to the image here so that this game can be linked to from other websites without losing any data. After loading the image, I shift it a bit to the right and bottom. This is not important if you have your game designed differently. my image is not the same size as the stage area, so I shift it slightly.

Next we are going to create a button that will allow the user to start playing the game. You can doa variety of things to handle this, but I decided to use a textField object. After creating the textField we do the following, assign the text to display, set the x and y position, tell it to autosize the field if the text is larger than the default size, tell it we want a background and what color, the color of the text, and tell it we want a border and what color. After all that, we add this as a child to the object.

Finally, we create an event listener. we do this by calling the textField’s addEventListener method. We pass in the type of event we are listening for, in this case we want a Mouse Click event. For the second parameter, we tell it the name of the function we want called when the event happens. This is restartGame.

private function restartGame(e:MouseEvent):void
	    {
	    	while(numChildren > 0)
	    	{
	    		removeChildAt(0);
	    	}
	    	setUpGame();
	    }

I call this function restartGame because it is used not just at the title screen of the game, but also the end game screen. It just made sense in my head.You will notice that this function has a parameter in it. This parameter is an event object. e is the name of the variable and MouseEvent is the type of parameter. While this function does not use the parameter, all functions that are called as the result of an event must have said event in the parameter list.

This function is pretty simple. First we clear out all the children of the object. We loop through all the children and each iteration we remove the one at index 0. Everytime one is removed the next one falls to fill in index 0. Once all the children are removed, or numchildren return 0, we call the function setUpGame.

setUpGame is the function we will use to set up all the cards for our memory match game. I will show an abreviated version of it here:

private function setUpGame():void
		{
			click = 1;
	    		turns = 0;
	    		lock = false;
	    		matches = 0;
 
	    		tokens = new Array();
 
	    		tokens.push(new card('http://divineknightgaming.com/games/hexmatch/images/token_back.png','http://divineknightgaming.com/games/hexmatch/images/token_blue.png','http://divineknightgaming.com/games/hexmatch/images/bat.png','bat'));
	    		/*Repeat for all cards anc change image and name as needed*/
 
			tokens = randomizeArray(tokens);
 
			addChild(tokens[0]);
			tokens[0].x = 70;
			tokens[0].y = 10;
			tokens[0].addEventListener(MouseEvent.CLICK, tokenClickListener); 
			/*Repeate for all cards and adjust position as needed*/
		}

This function sets all the flags, variables and such we need to keep track of the game as we play. First thing we have is four variables and an array being set to the default values. You will notice that the type and the keyword “var” are not on these lines. The reason for this is that these variables are created at the top of the class so that they are accessible by all functions in this class. So we need to add the following lines between the opening { of the class definition and the class constructor:

private var turns:int;
private var matches:int;
private var click:int;
private var lock:Boolean;
private var tokens:Array;

Back to the function, the first variable we set is “click” this is used to track which click the player is on each turn. In a memory match game, the player can select 2 cards each turn. The second variable is “turns”. We want to keep track of how many turns it took the player to match all cards. “lock” is used to prevent the player from selecting more than 2 cards while the game processes the results. Its use will become more clear as we move through the code. Next we have “matches.” Every time the player successfully matches two cards, we will track it with this variable so that we can determine when the player has won. Finally we create an array to hold all of the cards. I call it “tokens” only because I am using a six sided card rather than a typical four sided card.

After we set all those variables to their defaults we will fill the array with all the cards. We do this by first adding each card using the tokens array’s .push method. We pass in a new card object. This is a custom class made for this game and we will look at its code in a moment. After we have added all the cards to the array, we shuffle them using the randomizeArray method. This is a custom method and its code is as follows. Add this function to your MemoryMatch class.

private function randomizeArray(array:Array):Array 
	    {
	        var newArray:Array = new Array();
	        while(array.length > 0)
	        {
	            var obj:Array = array.splice(Math.floor(Math.random()*array.length), 1);
	            newArray.push(obj[0]);
	        }
	        return newArray;
    	    }

Now you may notice that this is the first method we have created that has a return type. This is shown as :Array rather than the :void we have been using. In this function we just loop through the passed in array and put random elements from it in a new array and then return the new array.

So back to our setUpGame method. After we shuffle the cards we need to display them on the game screen. We take each one, add it as a child to the class and position it in the row or column it needs to be in. Then we add a new event to each one to listen for the player clicking on the card. The method called when clicking on the card is tokenClickListener. Code is as follows:

private function tokenClickListener (e:MouseEvent):void 
	    {
	    	if(lock == false)
	    	{
		    	if(click == 1)
		    	{
		    		match1 = (e.currentTarget as card);
		    		match1.flip_card();
		    		click = 2;
		    	}
		    	else if(click == 2)
		    	{
		    		match2 = (e.currentTarget as card);
		    		if(match1 != match2)
		    		{
		    			lock = true;
			    		match2.flip_card();
			    		click = 1;
			    		turns++;
			    		setTimeout(checkMatch, 1000);
		    		}
		    	}
	    	}
	    }

Before we get too into this function, we can see we have two new variables, match1 and match2. We need to create these up above the constructor just as we did the other variables.

private var match1:card;
private var match2:card;

Now first thing we do in this method is check if we are currently locked. If we are not locked, then we can proceed. Next we check to see which click we are on. If we are on click one, we take the event target and assign it to match1, we flip the card to show the picture and we change the value of click to 2.

If click as a value of 2, meaning the player is now selecting the second card, we assign the event target to match2. Next we check to see if match1 and match2 are the same card, after all we don’t want to penalise the player for accidentally clicking the same card twice. If they are different we set lock to true. This will prevent the player from selecting more than 2 cards each turn. Then we flip the second card. We set click back to 1, increment turns by 1 and finally we call the function checkMatch. We do this by using the flash function setTimeout. This function delays the call to what ever function is in the first parameter by the number of milliseconds in the second parameter. In this instance we are delaying it by 1 second. We do this sso that if the player selects 2 cards that are not equal they have time to see which card they picked.

So what happens in checkMatch?

private function checkMatch():void
	    {
	    	if(match1.get_name() == match2.get_name())
    		{
    			match1.set_matched();
    			match2.set_matched();
    			matches++;
 
    			if(matches == tokens.length/2)
    			{
    				createWinMessage();
    			}
    		}
    		else
    		{
    			match1.flip_card();
    			match2.flip_card();
    		}
			lock = false;
	    }

In this function we check if both cards are the same by comparing the names of both cards. If they are the same we set their matched values, increment matches by one and check for the win condition. This is determined by checking to see if the number of matches is equal to half the total number of tokens. If the cards are not the same, we flip both cards back over.

If the player had successfully matched all the cards we show the win message by calling createWinMessage.

private function createWinMessage():void
	    {
	    	var rect:Shape = new Shape();
	    	rect.graphics.lineStyle(1);
	    	rect.graphics.beginFill(0Xffffff,1);
	    	rect.graphics.drawRect(180,150,180,60);
	    	addChild(rect);
 
	    	var message:TextField = new TextField();
	    	message.text = "You win. It took you "+turns+" turns.";
	    	message.x = 190;
	    	message.y = 160;
	    	message.autoSize = TextFieldAutoSize.LEFT;
	    	addChild(message);
 
	    	var playAgain:TextField = new TextField();
	    	playAgain.text = "Play Again";
	    	playAgain.x = 230;
	    	playAgain.y = 180;
	    	playAgain.autoSize = TextFieldAutoSize.LEFT;
	    	playAgain.background = true;
	    	playAgain.backgroundColor = 0X0000CC;
	    	playAgain.textColor = 0Xffffff;
	    	playAgain.border = true;
	    	playAgain.borderColor = 0X000000;
	    	addChild(playAgain);
    		playAgain.addEventListener(MouseEvent.CLICK, restartGame); 
	    }

I won’t go into too much detail on this as we have covered most of it already. But the first thing done above is create a big rectangle to hold the win message. Then we display a message telling the player how many turns it took to win the game and then give them an option to play it again.

Now that we have looked at the MemoryMatch class in depth we need to look at the card class. Before we do this we need to add the following line in the same area where our other import statements are:

import MemoryMatch.classes.card;

This imports the class file card to our main game class. What the above message means is that we are importing a class from the MemoryMatch package contained in the classes directory and called card.

So here is that class file.

package MemoryMatch.classes
{
	import flash.display.*;
	import flash.net.*;
 
	public class card extends Sprite
	{
		private var loader:Loader;
		private var loader2:Loader;
		private var loader3:Loader;
		private var card_name:String;
 
		private var dir:int;
		private var matched:Boolean;
 
		private var backImage:String;
		private var frontImage:String;
		private var faceImage:String;
 
		public function card(tokenBack:String, tokenFront:String, tokenImage:String, card_value:String) :void
		{
			card_name = card_value;
			dir = 2;
			matched = false;
 
			loader = new Loader();
			loader2 = new Loader();
			loader3 = new Loader();
 
			backImage = tokenBack;
			frontImage = tokenFront;
			faceImage = tokenImage;
 
			addChild(loader2);
			loader2.load(new URLRequest(frontImage));
 
			addChild(loader3);
			loader3.load(new URLRequest(faceImage));
			loader3.x = 32;
 			loader3.y = 32;
 
			addChild(loader);
			loader.load(new URLRequest(tokenBack));
		}
 
		public function flip_card():void
		{
			if(!matched)
			{
				switch(dir)
				{
					case 1:
						dir = 2;
						setChildIndex(loader,numChildren-1);
						break;
					case 2:
						dir = 1;
						setChildIndex(loader,0);
						break;
				}
			}
		}
 
		public function get_name() :String
		{
			return card_name;
		}
 
		public function set_matched() :void
		{
			matched = true;
		}
	}
 
}

I think at this point, you should be familiar enough with the functionality in this game and with the AS3 calls we have covered to understand most of what is going on in this class. The only new functionality is in the flip_card method.

In flip_card, I am first checking to make sure the card is not already matched. After all we don’t want to flip a card that no longer needs flipping. If it is not already matched we check its direction using the dir variable. If dir is 1 the card is face up and we take the back face of the card and move it to the front of the display order using the Flash method setChildIndex. The first parameter is the child we want to move and the second parameter is the position. So we move it to numChildren-1 which will make it the last child to be displayed on the screen. Then we set dir = 2. If dir is = to 2 when this method is called, the card is face down. We then move the back face of the card to the 0 position in the display order using setChildIndex and set dir = 1.

So there you have it, everything you need to make a memory match game. There are a lot of other things you could do to improve upon and expand this simple game concept. Hopefully, you will find what is here useful.

MemoryMatch Source Download