Search code examples
arraysactionscript-3flashcs4

Select pairs from an array (matching game) And add sound to that selection AS3 Flash CS4


I'm using a tutorial I found on Google - which works well. However, I have a few issues to make it work how I would like. This code uses a MovieClip for the card faces with the back of the card on frame1 and 2-17 different pictures or movieclips.

The questions are - Is there a way to get the ActionScript to choose from the whole array? But still produce pairs to choose from. As it stands now - If I select the game to be 4 across by 2 down (8 cards in total) It has the back of card (frame1) and will then randomly select, but only from frames 2-5 . If I modify these lines...

    public function MatchingGameObject10():void {
        // make a list of card numbers
        var cardlist:Array = new Array();
        for(var i:uint=0;i<boardWidth*boardHeight/2;i++) {
            cardlist.push(i);
            cardlist.push(i);
    }

to

    public function MatchingGameObject10():void {
        // make a list of card numbers
        var cardlist:Array = new Array(0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,16,16,17,17);
    }

I get random cards - but no pairs...

If I can ask another question here - it is - how to add a seperate sound to each card..So if it shows a Bee - the Bee.mp3 is played.. Here's the whole code..

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

public class MatchingGameObject10 extends MovieClip {
    // game constants
    private static const boardWidth:uint = 4;
    private static const boardHeight:uint = 2;
    private static const cardHorizontalSpacing:Number = 500;
    private static const cardVerticalSpacing:Number = 700;
    private static const boardOffsetX:Number = 50;
    private static const boardOffsetY:Number = 70;
    private static const pointsForMatch:int = 10;
    private static const pointsForMiss:int = -1;

    // variables
    private var firstCard:Card10;
    private var secondCard:Card10;
    private var cardsLeft:uint;
    private var gameScore:int;
    private var gameStartTime:uint;
    private var gameTime:uint;

    // text fields
    private var gameScoreField:TextField;
    private var gameTimeField:TextField;

    // timer to return cards to face-down
    private var flipBackTimer:Timer;

    // set up sounds
    var theFirstCardSound:FirstCardSound = new FirstCardSound();
    var theMissSound:MissSound = new MissSound();
    var theMatchSound:MatchSound = new MatchSound();

    // initialization function
    public function MatchingGameObject10():void {
        // make a list of card numbers
        var cardlist:Array = new Array();
        for(var i:uint=0;i<boardWidth*boardHeight/2;i++) {
            cardlist.push(i);
            cardlist.push(i);
        }

        // create all the cards, position them, and assign a randomcard face to each
        cardsLeft = 0;
        for (var x:uint=0; x<boardWidth; x++) {// horizontal
            for (var y:uint=0; y<boardHeight; y++) {// vertical
                var c:Card10 = new Card10();// copy the movie clip
                c.stop();// stop on first frame
                c.x = x*cardHorizontalSpacing+boardOffsetX;// set position
                c.y = y*cardVerticalSpacing+boardOffsetY;
                var r:uint = Math.floor(Math.random()*cardlist.length);// get a random face
                c.cardface = cardlist[r];// assign face to card
                cardlist.splice(r,1);// remove face from list
                c.addEventListener(MouseEvent.CLICK,clickCard);// have it listen for clicks
                c.buttonMode = true;
                addChild(c);// show the card
                cardsLeft++;
            }
        }

        // set up the score
        gameScoreField = new TextField();
        addChild(gameScoreField);
        gameScore = 0;
        showGameScore();

        // set up the clock
        gameTimeField = new TextField();
        gameTimeField.x = 450;
        addChild(gameTimeField);
        gameStartTime = getTimer();
        gameTime = 0;
        addEventListener(Event.ENTER_FRAME,showTime);
    }

    // player clicked on a card
    public function clickCard(event:MouseEvent) {
        var thisCard:Card10 = (event.target as Card10); // what card?

        if (firstCard == null) { // first card in a pair
            firstCard = thisCard; // note it
            thisCard.startFlip(thisCard.cardface+2);
            playSound(theFirstCardSound);

        } else if (firstCard == thisCard) { // clicked first card again
            firstCard.startFlip(1);
            firstCard = null;
            playSound(theMissSound);

        } else if (secondCard == null) { // second card in a pair
            secondCard = thisCard; // note it
            thisCard.startFlip(thisCard.cardface+2);

            // compare two cards
            if (firstCard.cardface == secondCard.cardface) {
                // remove a match
                removeChild(firstCard);
                removeChild(secondCard);
                // reset selection
                firstCard = null;
                secondCard = null;
                // add points
                gameScore += pointsForMatch;
                showGameScore();
                playSound(theMatchSound);
                // check for game over
                cardsLeft -= 2; // 2 less cards
                if (cardsLeft == 0) {
                    MovieClip(root).gameScore = gameScore;
                    MovieClip(root).gameTime = clockTime(gameTime);
                    MovieClip(root).gotoAndStop("gameover");
                }
            } else {
                gameScore += pointsForMiss;
                showGameScore();
                playSound(theMissSound);
                flipBackTimer = new Timer(2000,1);
                flipBackTimer.addEventListener(TimerEvent.TIMER_COMPLETE,returnCards);
                flipBackTimer.start();
            }

        } else { // starting to pick another pair
            returnCards(null);
            playSound(theFirstCardSound);
            // select first card in next pair
            firstCard = thisCard;
            firstCard.startFlip(thisCard.cardface+2);
        }
    }

    // return cards to face-down
    public function returnCards(event:TimerEvent) {
        firstCard.startFlip(1);
        secondCard.startFlip(1);
        firstCard = null;
        secondCard = null;
        flipBackTimer.removeEventListener(TimerEvent.TIMER_COMPLETE,returnCards);
    }

    public function showGameScore() {
        gameScoreField.text = "Score: "+String(gameScore);
    }

    public function showTime(event:Event) {
        gameTime = getTimer()-gameStartTime;
        gameTimeField.text = "Time: "+clockTime(gameTime);
    }

    public function clockTime(ms:int) {
        var seconds:int = Math.floor(ms/1000);
        var minutes:int = Math.floor(seconds/60);
        seconds -= minutes*60;
        var timeString:String = minutes+":"+String(seconds+100).substr(1,2);
        return timeString;
    }

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

Here's Card10 class

package {
import flash.display.*;
import flash.events.*;

public dynamic class Card extends MovieClip {
    private var flipStep:uint;
    private var isFlipping:Boolean = false;
    private var flipToFrame:uint;

    // begin the flip, remember which frame to jump to
    public function startFlip(flipToWhichFrame:uint) {
        isFlipping = true;
        flipStep = 10;
        flipToFrame = flipToWhichFrame;
        this.addEventListener(Event.ENTER_FRAME, flip);
    }

    // take 10 steps to flip
    public function flip(event:Event) {
        flipStep--; // next step

        if (flipStep > 5) { // first half of flip
            this.scaleX = .20*(flipStep-6);
        } else { // second half of flip
            this.scaleX = .20*(5-flipStep);
        }

        // when it is the middle of the flip, go to new frame
        if (flipStep == 5) {
            gotoAndStop(flipToFrame);
        }

        // at the end of the flip, stop the animation
        if (flipStep == 0) {
            this.removeEventListener(Event.ENTER_FRAME, flip);
        }
    }
}
}

Solution

  • So without completely re-factoring how this game works, the best way to make it dynamic based off the amount of frames (card faces) in your Card10 Clip, is change this code:

        var cardlist:Array = new Array();
        for(var i:uint=0;i<boardWidth*boardHeight/2;i++) {
            cardlist.push(i);
            cardlist.push(i);
        }
    

    To the following:

            var allCards:Array = new Array(); //an array of all available frame numbers
            var cardlist:Array = new Array(); //an array of just those cards to show
    
            var tmpCard:Card10 = new Card10(); //create a temporary card for the sole purpose of counting how many frames it has
    
            var i:int;
            //populate the array with all the frames from the Card MC 
            for (i = 0; i < tmpCard.totalFrames;i++) {
                allCards.push(i);//add card frame to allCards array
            }
    
            //now create the list of cards to show (since the amount of cards may be more than the amount you want to show
            for (i = 0; i < (boardWidth * boardHeight) / 2; i++) {
                var cardIndex:int = Math.floor(Math.random() * allCards.length);// get a random card from the all card list
    
                //add the card twice (so there is a pair) in the list of cards to show
                cardlist.push(cardIndex);
                cardlist.push(cardIndex);
    
                //remove it from the all cards array so it doesn't come up again in the random bit above
                allCards.splice(cardIndex,1);
            }