Return to Kroll Design home page

Flash Tutorials (with .FLA files included)

 
« Return

ActionScript 3

Game: remember the location of playing cards

This Flash game has you remember the location of playing cards, in order to locate matching pairs.

Download the FLA file

Download the AS file

Code for external class file As3_match_cards.as:
// THIS IS AN ACTIONSCRIPT FILE, NOT AN .FLA FILE

package {
	import flash.display.*;
	import flash.events.*;
	import flash.utils.*;
	import flash.media.Sound;
	import flash.media.SoundChannel;

	public class As3_match_cards extends MovieClip {

	var theFirstCardSound:FirstCardSound = new FirstCardSound();
	var theMissSound:MissSound = new MissSound();
	var theMatchSound:MatchSound = new MatchSound();

	private static const pointsForCorrect:int = 200;
	private static const pointsForIncorrect:int = -20;
	private static const pointsForGameOver:int = 1000;
	private var score:int = 0;

	private static const leftMargin:int = 50;
	private static const topMargin:int = 150;
	private static const padding:uint = 5;
	private static const cardColumns:uint = 8;
	private static const cardRows:uint = 4;
	private static const deckSize:uint = 54;
	var xx:uint;
	var yy:uint;
	var i:uint;
    var cardWidth:Number;
	var cardHeight:Number;

	var deckArray:Array = new Array();
	var deckArrayIndex:uint;

    var cardArray:Array = new Array();
	var cardArrayIndex:uint;

	var cardFace:uint;
	var cardToPick:uint; // value 1 through 54

	var cardsOnTable:uint = cardColumns * cardRows;
	var cardPairs:uint = cardsOnTable / 2;

	var firstCard:Card = null;
	var secondCard:Card = null;

	var pairsLeftToMatch:int = cardPairs;

	public function As3_match_cards():void {

	stop();

	MovieClip(root).score_txt.text = 0;

	// create an array of card numbers:
	    for (i=0; i<deckSize; i++) {
			deckArray[i] = i + 1; // adding 1 gives the Ace of clubs a correct
			                      // cardFace (frame number in Card movie clip
								  // timeline) of 1, instead of the incorrect
								  // cardFace of zero.
		}

	// pick 16 (or whatever "cardPairs" current value is) cards at random from deckArray:
	    for (i=0; i<cardPairs; i++) {
		   deckArrayIndex = Math.floor(Math.random() * deckArray.length);
		   cardToPick = deckArray[deckArrayIndex]; // pick a number from 1 to 54 that isn't taken yet
		   deckArray.splice(deckArrayIndex,1);
	       cardArray.push(cardToPick);
		   cardArray.push(cardToPick);
		}

	// arrange the chosen 16 pairs of cards randomly on the stage:
		for (xx=0; xx<cardColumns; xx++) {
			for (yy=0; yy<cardRows; yy++) {
				var currCard:Card = new Card(); // card is the playing card library item I created
				currCard.buttonMode = true; // make cursor same as for a button (pointing finger)
				currCard.scaleX = 0.5;
				currCard.scaleY = 0.5;
				cardWidth=currCard.width;
				cardHeight=currCard.height;
				cardArrayIndex = Math.floor(Math.random()*cardArray.length); // cardArray.length keeps getting shorter
				cardFace = cardArray[cardArrayIndex];
				currCard.cardFace = cardFace;
				currCard.cardColumn = xx;
				currCard.cardRow = yy;
				currCard.gotoAndStop("cardBack");
				cardArray.splice(cardArrayIndex,1);
				currCard.x = (xx * (cardWidth + padding)) + leftMargin;
				currCard.y = (yy * (cardHeight + padding)) + topMargin;
				currCard.addEventListener(MouseEvent.CLICK, clickCard);
				currCard.addEventListener(MouseEvent.MOUSE_OVER, overCard);
				currCard.addEventListener(MouseEvent.MOUSE_OUT, outCard);
				addChild(currCard);
			} // end of inner j loop
		} // end of outer i loop

	} // end of constructor


	function overCard(myEvent:MouseEvent) {
	    var currentCard:Card = (myEvent.currentTarget as Card);
		currentCard.alpha = .85;
	}

	function outCard(myEvent:MouseEvent) {
	    var currentCard:Card = (myEvent.currentTarget as Card);
		currentCard.alpha = 1;
	}

	function clickCard(myEvent:MouseEvent) {
		var clickedCard:Card = (myEvent.currentTarget as Card);

		if ((firstCard == null) && (secondCard == null)) // first card in a pair was just clicked
		{
		   playSound(theFirstCardSound);
		   firstCard = clickedCard;
		   firstCard.gotoAndStop(firstCard.cardFace);
		}
		else if ((firstCard != null) && (secondCard == null)) // second card in a pair was just clicked
		{
		   secondCard = clickedCard;

		   if ((firstCard.cardColumn == secondCard.cardColumn) && (firstCard.cardRow == secondCard.cardRow))
		   { //trace ("same card was clicked");
		     playSound(theMissSound);
			 clickedCard.gotoAndStop("cardBack");
			 firstCard = null;
			 secondCard = null;
		   }
		   else
		   { trace ("a different card was clicked");
		     trace("first card face: " + firstCard.cardFace);
			 trace("second card face: " + secondCard.cardFace);
			 secondCard.gotoAndStop(secondCard.cardFace);
			 // at present the game is "easy", considering it a match
			 // even if suit is different, as long as value is the same.
			 // adding 13 to a cardFace gives you the same card in the next suit.
			 // The 2 Jokers don't act the same as the other cards, which is why I
			 // say that easy mode is only for cards with a cardFace < 53:
			 if ((firstCard.cardFace == secondCard.cardFace) ||
                ((firstCard.cardFace < 53) && (secondCard.cardFace < 53) && (firstCard.cardFace - secondCard.cardFace) % 13 == 0))
			 {  trace("match");
			   playSound(theMatchSound);
			   score += pointsForCorrect;
			   MovieClip(root).score_txt.text = score;
			   var myTimer:Timer = new Timer(100,1); // the "1" ensures that the timer runs just once
			                                          // and doesn't keep looping.
	           myTimer.addEventListener(TimerEvent.TIMER, removeMatchingPair);
			   myTimer.start();
			 }
			 else
			 { //trace("no match");
			   playSound(theMissSound);
			   score += pointsForIncorrect; // yes, you want to ADD a negative number,
			                                // not subtract a negative number!
			   MovieClip(root).score_txt.text = score;
			   var myTimer2:Timer = new Timer(1000,1); // the "1" ensures that the timer runs just once
			                                          // and doesn't keep looping.
	           myTimer2.addEventListener(TimerEvent.TIMER, hideCardPair);
			   myTimer2.start();
			 }
		   }
		}
		else if ((firstCard != null) && (secondCard != null)) // user wants to move on quickly, before
		                                                      // timer kicks in and the program
															  // hides the two chosen cards.
		{
		   playSound(theFirstCardSound);
		   firstCard.gotoAndStop("cardBack");
	       secondCard.gotoAndStop("cardBack");
	       firstCard = clickedCard;
	       secondCard = null;
		   firstCard.gotoAndStop(firstCard.cardFace);
		}
		else
		{ trace("this branch of if-else hopefully never takes place");
		}
	}

	function hideCardPair(myEvent:TimerEvent) {
	   if ((firstCard != null) && (secondCard != null))
	   {
	   firstCard.gotoAndStop("cardBack");
	   secondCard.gotoAndStop("cardBack");
	   firstCard = null;
	   secondCard = null;
	   }
	}

	function removeMatchingPair(myEvent:TimerEvent) {
	   removeChild(firstCard); // setting visible to false wasn't working correctly on
	                           // one tester's pc, the cards were still clickable and visible,
							   // so hopefully removeChild will work better.
	   removeChild(secondCard);
	   firstCard = null;
	   secondCard = null;
	   pairsLeftToMatch--;
	   trace("pairsLeftToMatch: " + pairsLeftToMatch);
	   if (pairsLeftToMatch <= 0)
	   {
	     trace("game over");
		 score += pointsForGameOver;
	/* instead of just saying root.gotoAndPlay("game_over"), the Flash compiler now
	   requires you to strict type it to "MovieClip(root)", after all, "root" doesn't
	   necesssarily have to be a movie clip -- it can also be a sprite:
	*/
		 MovieClip(root).gotoAndPlay("game_over");

	   }
	}

	public function playSound(soundObject:Object) {
		var channel:SoundChannel = soundObject.play();
	}


	} // end of class As3_match_cards

} // end of package
Code for frame 1 of main timeline:
trace("now in frame 1 of main timeline...");

stop();

// sound defaults to on:
soundOnOff_mc.soundOff_mc.visible = false;
soundOnOff_mc.soundOn_mc.visible = true;
soundOnOff_mc.mouseEnabled = true;
soundOnOff_mc.buttonMode = true;

// add event listener for sound on/off button being clicked on:
soundOnOff_mc.addEventListener(MouseEvent.CLICK, toggleSound);

// set the sound to the opposite setting:
function toggleSound(myEvent:MouseEvent) {
	trace("now in toggleSound");

	var sTransform:SoundTransform = new SoundTransform(1,0);

	// if sound is on, turn it off:
	if (soundOnOff_mc.soundOn_mc.visible == true)
	{  soundOnOff_mc.soundOn_mc.visible = false;
	   soundOnOff_mc.soundOff_mc.visible = true;
	   sTransform.volume = 0;
       SoundMixer.soundTransform = sTransform;
	}
	// if sound is off, turn it on:
	else
	{  soundOnOff_mc.soundOn_mc.visible = true;
	   soundOnOff_mc.soundOff_mc.visible = false;
	   sTransform.volume = 1;
       SoundMixer.soundTransform = sTransform;
	}
} // end of toggleSound function



score_txt.visible = false;

start_btn.visible = true;
playAgain_btn.visible = false;

start_btn.addEventListener(MouseEvent.CLICK, startGame);

function startGame(myEvent:MouseEvent) {
	trace("now in startGame");
	MovieClip(root).gotoAndStop("game_play");
}

Code for frame 10 of main timeline:
trace("now in frame 10 of main timeline");

score_txt.visible = true;

start_btn.visible = false;
playAgain_btn.visible = false;

stop();

Code for frame 20 of main timeline:
start_btn.visible = false;
playAgain_btn.visible = true;

Code for frame 30 of main timeline:
stop();

playAgain_btn.addEventListener(MouseEvent.CLICK, playAgainFunction);

function playAgainFunction(myEvent:MouseEvent) {
	trace("now in playAgainFunction");
	removeEventListener(MouseEvent.CLICK, playAgainFunction);
	MovieClip(root).gotoAndStop("game_play");
}


 
« Return


©2012 Kroll Design    info@KrollDesign.net    781.910.3694
Last modified: 12/31/1969 7:00 PM