Project 2. DiceOut!

Over the last several chapters, you have learned the basics of working with classes and object-oriented programming with ActionScript. Now it is time to put your skills to the test with a little game called DiceOut.

What is different about this project, compared to the first, is that you’ll have a design file to start from, which will introduce a common workflow for teams. Often a designer might create a noninteractive version of the project and pass it along to the interactive designer to add the logic and controls to make everything work.

Part of this project will use some elements of the clock that you created in Project 1. It will be helpful to familiarize yourself with the previous project, or if you skipped it, go back and complete it as part of building Project 2. Let’s get started!

Project Specification: DiceOut

DiceOut is a game of chance based on rolling three six-sided dice. The game begins with a display of three dice. The user starts the game with a button on the screen.

After starting the game, the user then has 12 seconds, displayed on an analog clock, to get the highest roll possible for the game.

With each roll, the game scores the dice based on the following rules:

• 50 points for any doubles

• 100 points for triple 1s

• 200 points for triple 2s

• 300 points for triple 3s

• 400 points for triple 4s

• 500 points for triple 5s

• 600 points for triple 6s

• 0 points for other combinations

After the 12-second timer runs out, the game displays the final score and ends.

Visual Design Review: DiceOut

A Flash designer has already created the design of the project and has provided it to you at the following location: www.peachpit.com/actionscript3dd.com.

You ask the designer for a review of the project. He agrees to sit with you and provides an overview of the project (Figure P2.1).

Figure P2.1. DiceOut overview—start of project

image

The timeline (Figure P2.2) is organized into folders indicating the areas of the application. These folder are called endGame assets, game assets, instructions assets, splash assets, and general assets. The project has two main sections, labeled in a labels timeline row. The first is named “game.”

• There is a text field at the top of the Stage called feedbackText used to display prompts to the user, and to show what type of roll they scored after rolling the dice.

• The three dice are named die1, die2, and die3; each is an instance of a MovieClip that contains six frames, each frame showing a unique face of the die.

• The button to start the game is named rollButton and is an instance of a generic Game Button Library object. Within this Game Button Library object is a text field called buttonLabel.

• The points are displayed in a text field called scoreText.

• The clock is a variation of the clock you created earlier for a previous client and is being reused here.

Figure P2.2. DiceOut overview—end of game

image

The second section of the project is labeled “endgame.”

• In this section is some static text and a dynamic text field named finalScore to display the final score.

Kick-Off Meeting Notes: DiceOut

Before getting started, as part of the kick-off process a number of people from the team including designers, developers, and architects hold a quick meeting called the “kick off” to discuss the project, get ideas from each other on how to approach the design and development, and to answer any open questions that might not be addressed in the project specification. Below are the notes from this meeting.

To work efficiently with the dice, you should add them into an array so you can loop through them.

Testing for the face of the dice will require that you have a way to store the value of the roll somehow in each die, otherwise you won’t have a way to know what the score is.

After talking with another developer, you learn a new way to work with events that might be helpful. Apparently, you can create your own custom events that you can broadcast from any MovieClip. To do this, you use the dispatchEvent method, and then create a new Event, adding a string that would be used to identify the event.

She gave me this code as an example:

dispatchEvent(new Event("endGame"));

This line of code is in the class that broadcasts the event. You need to create a listener attached to that object to capture the event like this:

clock.addEventListener("endGame", endGame);

Instead of working with a built-in event like MouseEvent.CLICK, you should enter the string that matches the string used to create the event. It might come in handy for the clock to tell the game when it runs out of time.

With the kick-off finished, it is time to get started. Try to create the project on your own, and when you are finished, read on and I’ll explain how I created the project and why I chose the methods I did.

Solution and Walkthrough: DiceOut

Whew! Working with another person’s project adds an interesting twist to everything, doesn’t it?

In addition to using the skills you have learned so far, through working with others on the team you also learned some new things about ActionScript; specifically, how to create your own custom events that you can broadcast from a MovieClip.

With that, here is one way to solve this challenge. Because there are so many open-ended ways to approach this project, this is just an example—but it may introduce some solutions that you hadn’t considered.

Overview of the Document Class

In this finished example, the DiceOut Document class contains most of the game functionality. The work to manage the countdown timer, the rolling of each die, and the button labels changes were offloaded into custom classes for those objects.

Let’s start with a review of how I created the Document class:

package
{
    import flash.display.MovieClip;
    import flash.events.MouseEvent;
    import flash.events.Event;
    public class DiceOut extends MovieClip
    {
        /*
        Objects on stage:
        - rollButton:GameButton;
        - die1:Die;
        - die2:Die;
        - die3:Die;
        - scoreText:TextField;
        - feedbackText:TextField;
        - clock:Clock;
        */
        private var gameDice:Array;
        private var score:uint = 0;
        public function DiceOut()
        {
            stop();
            setupDice();
            setupButtons();
            setupListeners();
        }
        private function setupDice():void
        {
            gameDice = new Array(die1,die2,die3);
        }
        private function setupButtons():void
        {
            rollButton.setLabel("Roll");
        }
        private function setupListeners():void
        {
            rollButton.addEventListener(MouseEvent.CLICK, rollDice);
            clock.addEventListener("endGame", endGame);
        }
        public function rollDice(e:MouseEvent):void
        {
            clock.startClock();
            var currentRoll:Array = [];
            for (var i:uint = 0; i < gameDice.length; i++)
            {
                currentRoll[i] = gameDice[i].rollDie();
            }
            scoreRoll(currentRoll);
        }
        public function scoreRoll(newRoll:Array):void
        {
            if (newRoll[0] == newRoll[1] && newRoll[1] == newRoll[2])
            {
               if (newRoll[0] == 1)
               {
                   score += 100;
                   scoreText.text = score + " points";
                   feedbackText.text = "Triple 1";
               } else if (newRoll[0] == 2)
               {
                   score += 200;
                   scoreText.text = score + " points";
                   feedbackText.text = "Triple 2";
               } else if (newRoll[0] == 3)
               {
                   score += 300;
                   scoreText.text = score + " points";
                   feedbackText.text = "Triple 3";
               } else if (newRoll[0] == 4)
               {
                   score += 400;
                   scoreText.text = score + " points";
                   feedbackText.text = "Triple 4";
               } else if (newRoll[0] == 5)
               {
                   score += 500;
                   scoreText.text = score + " points";
                   feedbackText.text = "Triple 5";
               } else if (newRoll[0] == 6)
               {
                   score += 600;
                   scoreText.text = score + " points";
                   feedbackText.text = "Triple 6";
               }
            }
            else if (newRoll[0] == newRoll[1] || newRoll[1] == newRoll[2] || newRoll[0] == newRoll[2])
            {
                score += 50;
                scoreText.text = score + " points";
                feedbackText.text = "Doubles!";
            }
            else
            {
               feedbackText.text = "";
            }
        }
        public function endGame(e:Event):void
        {
            gotoAndStop("endgame");
            finalScore.text = score + " points";
        }
    }
}

Walkthrough of the Document Class

Let’s start with the contents before the constructor:

/*
Objects on stage:
- rollButton:GameButton;
- die1:Die;
- die2:Die;
- die3:Die;
- scoreText:TextField;
- feedbackText:TextField;
- clock:Clock;
*/
private var gameDice:Array;
private var score:uint = 0;

First, the class has an opening comment that lists the objects that are on the Stage. This is helpful when working with a visually laid out project and prevents the need to flip back and forth to find out the name of an object on the Stage.

Next are two private variables that are created; the first is an array to hold the dice, and the second to hold the player’s score.

Let’s jump to the constructor next:

public function DiceOut()
{
   stop();
   setupDice();
   setupButtons();
   setupListeners();
}

To prevent the project from playing the main timeline, I added a stop action when the object is constructed, then three helper functions to get everything up and running. The first is the setupDice method:

private function setupDice():void
{
    gameDice = new Array(die1,die2,die3);
}

This method uses the gameDice array and populates it with the MovieClips that are on the Stage. By having these in the array, I felt it would be easier to loop through them to roll each die and get its score.

You then configure the rollButton instance on the Stage:

private function setupButtons():void
{
    rollButton.setLabel("Roll");
}

This is running a public method that is part of a GameButton custom class you created and is shown below:

package  {
    import flash.display.Sprite;
    public class GameButton extends Sprite {
        /*
        Objects on stage:
        - buttonLabel:MovieClip
        */
        public function GameButton() {
            // constructor code
        }
        public function setLabel(newLabel:String):void
        {
            buttonLabel.text = newLabel;
        }
    }
}

The method is accepting a label and is assigning it to the text property of the buttonLabel text field that is in the MovieClip.

Ok, back to the Document class, the next step is to set up the event listeners:

private function setupListeners():void
{
    rollButton.addEventListener(MouseEvent.CLICK, rollDice);
    clock.addEventListener("endGame", endGame);
}

Here, there is an event listener for when rollButton is clicked, which then executes a callback function called rollDice. An event listener is then added for a custom event broadcasted from the clock called endGame, which executes the endGame callback function.

Let’s take a look at the Clock class that is linked to the countdown clock on the Stage:

package  {

    import flash.display.MovieClip;
    import flash.utils.Timer;
    import flash.events.TimerEvent;
    import flash.events.Event;
    public class Clock extends MovieClip {
        /*
        Objects on stage:
        - second:MovieClip
        */
        private var clockTimer:Timer;
        public function Clock() {
            setupTimer();
        }
        private function setupTimer():void
        {
            clockTimer = new Timer(1000,12);
            clockTimer.addEventListener(TimerEvent.TIMER, tickClock);
            clockTimer.addEventListener(TimerEvent.TIMER_COMPLETE, endClock);
        }
        public function startClock():void
        {
            clockTimer.start();
        }
        public function tickClock(e:TimerEvent):void
        {
            second.rotation += 30;
        }

        public function endClock(e:TimerEvent):void
        {
            dispatchEvent(new Event("endGame"));
        }
    }
}

In this custom class, there is a single private variable, the timer itself, named clockTimer.

The constructor executes the setupTimer method, which configures the timer and adds the TimerEvent.TIMER and TimerEvent.TIMER_COMPELTE event listeners.

I created a public function called startClock to gets everything up and running. It starts the clock, which will then start broadcasting events.

The first event is the TimerEvent.TIMER, which has a callback function named tickClock. This changes the angle of the hand of the clock by adding 30 degrees.

The second event is the TimerEvent.TIMER_COMPELTE which has a corresponding callback function named endClock. To create a custom event from scratch, you need to use the dispatchEvent statement. Within this, create a new instance of the Event class, and provide it with a string that you want to use to identify the event. Remember, this string is what the event listener is going to “hear” when the custom event is dispatched. The endgame event is what the Document class is listening to.

Cool! Back to the Document class.

When the user clicks the rollButton object, the rollDice callback function begins:

public function rollDice(e:MouseEvent):void
{
    clock.startClock();
    var currentRoll:Array = [];
    for (var i:uint = 0; i < gameDice.length; i++)
    {
        currentRoll[i] = gameDice[i].rollDie();
    }
        scoreRoll(currentRoll);
}

Here, the clock is started and an array is created within the method that will hold the roll of the dice. There is a for loop that moves through all the items in the gameDice array and executes a rollDie method for each.

The rollDie method is a public method of the Die class that is attached to each instance of the dice on the Stage:

package  {
    import flash.display.MovieClip;
    public class Die extends MovieClip {
        /*
        Objects on stage:
        - none
        */
        public function Die() {
            stop();
        }
        public function rollDie():uint
        {
            var dieRoll:uint;
            dieRoll = Math.random()*6+1;
            this.gotoAndStop(dieRoll);
            return dieRoll;
        }
    }
}

To prevent the die from playing the main timeline a stop action is added to the Die class when it is created. In the public rollDie method, a variable is created to hold the die value. It receives a random number from 1 to 6, and the die then displays the matching die face corresponding to the random number.

The method then returns the value of the die back to the caller, which is back in the rollDie method in the Document class.

Back in the Document class, the returned value is added to the currentRoll array. When all three dice have been rolled, that currentRoll array is sent to the scoreRoll method to evaluate the results and award points to the player:

public function scoreRoll(newRoll:Array):void
{
    if (newRoll[0] == newRoll[1] && newRoll[1] == newRoll[2])
    {
        if (newRoll[0] == 1)
        {
            score += 100;
            scoreText.text = score + " points";
            feedbackText.text = "Triple 1";
        } else if (newRoll[0] == 2)
        {
            score += 200;
            scoreText.text = score + " points";
            feedbackText.text = "Triple 2";
        } else if (newRoll[0] == 3)
        {
            score += 300;
            scoreText.text = score + " points";
            feedbackText.text = "Triple 3";
        } else if (newRoll[0] == 4)
        {
            score += 400;
            scoreText.text = score + " points";
            feedbackText.text = "Triple 4";
        } else if (newRoll[0] == 5)
        {
            score += 500;
            scoreText.text = score + " points";
            feedbackText.text = "Triple 5";
        } else if (newRoll[0] == 6)
        {
            score += 600;
            scoreText.text = score + " points";
            feedbackText.text = "Triple 6";
        }
    }
    else if (newRoll[0] == newRoll[1] || newRoll[1] == newRoll[2] || newRoll[0] == newRoll[2])
    {
        score += 50;
        scoreText.text = score + " points";
        feedbackText.text = "Doubles!";
    }
    else
    {
        feedbackText.text = "";
    }
}

The newRoll array contains the values of the dice.

First, a test runs to determine if the three dice equal each other. Through the laws of association, if die1 equals die2, and die1 equals die3, then all three are the same. If that condition is true, then the value of die1 will determine what all three of the dice are, which can be either 1, 2, 3, 4, 5, or 6.

Based on the value of that die, the score is increased, the score display is updated, and feedback text is shown to the user.

If the three don’t equal each other, then the next step is to see if there are doubles. This is done by seeing if die1 equals die2, or if die2 equals die3, or if die1 equals die3. If any of these conditions are true, then the score is increased, the score display is updated and feedback text is shown to the user as shown in Figure P2.3.

Figure P2.3. Displaying a winning score

image

If none of these scoring conditions is met, then the feedback text is cleared, since the player didn’t have any winning combinations.

The final piece is to end the game. This happens when the clock broadcasts the custom endGame event, which the Document class is listening for. When it hears it, the Document class runs the endGame method:

public function endGame(e:Event):void
{
    gotoAndStop("endgame");
    finalScore.text = score + " points";
}

Here, the main timeline is moved to the “endgame” label, and the final score is displayed to the user (Figure P2.4).

Figure P2.4. The end of the game. Better luck next time!

image

Wrapping Up

With this project, there are several elements that were employed. The first was tying in the interaction of the user’s mouse to trigger the rolling of the dice using event listeners. Then, through random number generation, the numbers were “rolled” and based on the conditional logic added, the roll was tested against the scoring rules and then assigned points based on certain combinations.

Through using a timer, the clock is able to time the user’s play and end the game after a specific amount of time.

Good job! As you can see, even after learning just a small bit of ActionScript, you can create some pretty cool projects. In the next section of the book, you’ll learn more and your next project will challenge you to make a mobile application using Flash Professional CS5.5, ActionScript, and Adobe AIR.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.55.35