Foundation Game Design with ActionScript 3.0, Second Edition (44 page)

BOOK: Foundation Game Design with ActionScript 3.0, Second Edition
13.01Mb size Format: txt, pdf, ePub

When you use plus signs to concatenate strings, they don't have any mathematical meaning—they're just like stitches that are used to sew all the bits of text together into one long piece. In the program, the final result of all this stitching is copied into the
gameStatus
variable so you just need to use the
gameStatus
variable whenever you need to display this text. And that's exactly what the next bit of code does.

A small technical detail that you should be aware of is that the following directive actually mixes String and uint variables:

gameStatus = "Guess: " + guessesMade + ", Remaining: " + guessesRemaining;

In the program, you declared the
gameStatus
variable to be a String type. That means it can't contain numbers, except in the form of numeric characters (which are interpreted like letters or words). However, you declared both the
guessesRemaining
and
guessesMade
variables as uint variables (which are interpreted as numbers). Both of
them are joined together with ordinary text and copied into the
gameStatus
string variable. Isn't the purpose of assigning variable types to prevent this sort of mixing and matching between strings and numbers? How is this possible?

In fact, you can use number variables with strings by joining them together with plus signs, but when you do this, AS3.0 converts the values of the number variables into strings. The data type in the
guessesRemaining
and
guessesMade
variables remains unchanged as uint, but the values they contain are converted into a string when they're assigned to the
gameStatus
string variable. This is very useful for exactly the purpose you've put it to: to display text with numbers that are updated by the program. It's such a common requirement in programs that AS3.0 does this type conversion automatically.

Now that you have the
gameStatus
variable packed up and ready to go, you can get lot of mileage out of it in the if/else statement. The new bits of code are highlighted in bold:

if (currentGuess > mysteryNumber)
{
  output.text = "That's too high."
+ "\n" + gameStatus;
}
else if (currentGuess < mysteryNumber)
{
  output.text = "That's too low."
+ "\n" + gameStatus;
}
else
{
  output.text = "You got it!";
}

You're using string concatenation to add the contents of the
gameStatus
variable to the output text field. But there's something here that you haven't seen before.

"\n"

A backslash followed by the letter n is known as a
newline character
. The newline character forces whatever text that comes after it onto a new line. That's why the game displays the game status information just below the first bit of text.

You can use the newline character in the middle of any string to break the text onto two lines or more. Here's an example:

"This text\nis broken in the middle."

It displays as follows:

This text
is broken in the middle.

In the program you added the newline character by joining it to the rest of the text using string concatenation. Here's how it looks using the example text:

"This text" + "\n" + "is broken in the middle."

The result is exactly the same, but the code is a little easier to read because it's visually very clear where the line break falls.

Hey, why use the gameStatus variable, anyway?

There's one last thing you should quickly look at, and a question that you might have had about how you've written the code in the if/else statement. You could have written the first two directives in the if/else statement without the
gameStatus
variable, like this:

if (currentGuess > mysteryNumber)
{
  output.text
    = "That's too high." + "\n" + "Guess: "
    + guessesMade + ", Remaining: " + guessesRemaining;
}
else if (currentGuess < mysteryNumber)
{
  output.text
    = "That's too low." + "\n" + "Guess: "
    + guessesMade + ", Remaining: " + guessesRemaining;
}
else
{
  output.text = "You got it!";
}

Why then did you go to all the trouble of creating a special
gameStatus
variable if you could easily have done without it? Obviously, it's a lot of code, it makes the if/else statement more difficult to read, and you'd have to write it all out twice.

The other reason might be less obvious: if you have that text neatly stored in the
gameStatus
variable and you need to make any changes to it, you have to change it only once. Any place you use the
gameStatus
variable in the program is automatically updated with the new text. This might not be such a big issue in a small program like this number guessing game, but if it were used 10 or 20 times in different places in a bigger program, it would be a lot of work to update.

Whenever you find yourself using a lot of the same text over and over again in any of your programs, try storing it in a variable. You'll save yourself a lot of typing and a lot of trouble in the long run.

Using uint vs. int variables

Did you try making more than the ten guesses the game said you had remaining? If you did, you would have noticed that the output text field displayed something like this:

Remaining: 4294967295

(You may need to scroll down the output text field to see it if the number doesn't quite fit.)

At the moment, you haven't programmed the game to end when the player has run out of guesses, so the game keeps on subtracting 1 from the
guessesRemaining
variable even after the 10 guesses are used up. After it passes 0, it suddenly jumps to this crazy long number: 4294967295. No, your program isn't about to join a secret botnet of computers plotting to overthrow the human race; there is actually very interesting logic behind it.

You declared the
guessesRemaining
variable as a uint type, which store whole numbers that are only positive. They can never be negative. When a variable that's declared as a uint type does try to become less than zero, exactly the opposite thing happens: it flips to the maximum possible number, which happens to be 4294967295.

This is very important to know because sometimes you need or want to know whether a number has run into negative territory. In those cases, make sure that you declare the variable as an int type. (As mentioned before, int stands for
integer,
which is a whole number that can be positive or negative.)

To see the effect that changing the
guessesRemaining
variable to an int type has on your program, try it and see what happens!

  1. Change the line of code in the class definition that declares the
    guessesRemaining
    variable so that its type is set to int:
    public var guessesRemaining:
    int;
  2. Compile the program.
  3. Press the Enter key more than ten times. You should see the Remaining value become negative, like this:
Remaining: -3

Keep this in mind whenever you decide what type to declare your variables.

Winning and losing

The game now has enough information about what the player is doing to figure out whether the game has been won or lost. All you need to do now is to find a way to say, “Hey, the game is over!” and tell players how well they did.

To do this, add the following to the program:

  • A Boolean (true/false) variable called
    gameWon
    that is set to true if the game has been won and false if it hasn't.
  • A method called
    checkGameOver
    that checks to see whether the player has enough guesses remaining to continue playing.
  • A method called
    endGame
    that tells players whether they've won or lost.

An important aspect of this next bit of code is that it shows you an example of how you can use methods to modularize your code. As discussed in the beginning of this chapter,
modular programming
is a way of breaking down complex bits of code into smaller manageable pieces, or
modules
. Modules can really be any pieces of code, such as classes or methods, that perform one specific helpful function. Have a look at the two new methods added in the following code and see if you can figure out how they're used to modularize the program.

  1. Add the new
    gameWon
    variable to the class definition.
    public class NumberGuessingGame extends Sprite
    {
      //Create the text objects
      public var format:TextFormat = new TextFormat();
      public var output:TextField = new TextField();
      public var input:TextField = new TextField();
      //Game variables
      public var startMessage:String;
      public var mysteryNumber:uint;
      public var currentGuess:uint;
      public var guessesRemaining:int;
      public var guessesMade:uint;
      public var gameStatus:String;
      public var gameWon:Boolean;
  2. Give it an initial value of false in the
    startGame
    method.
    public function startGame():void
    {
      //Initialize variables
      startMessage = "I am thinking of a number between 0 and 99";
      mysteryNumber = 50;
      //Initialize text fields
      output.text = startMessage
      input.text = "";
      guessesRemaining = 10;
      guessesMade = 0;
      gameStatus = "";
      
    gameWon = false;
      //Add an event listener for key presses
      stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressHandler);
    }
  3. Add the following code in bold to the
    startGame
    method. Add two new methods,
    checkGameOver
    and
    endGame
    , just below it.
    public function playGame():void
    {
      guessesRemaining--;
      guessesMade++;
      gameStatus = "Guess: " + guessesMade + ", Remaining: " + guessesRemaining;
      currentGuess = uint(input.text);
      if (currentGuess > mysteryNumber)
      {
        output.text = "That's too high." + "\n" + gameStatus;
        checkGameOver();
      }
      else if (currentGuess < mysteryNumber)
      {
        output.text = "That's too low." + "\n" + gameStatus;
        checkGameOver();
      }
      else
      {
        output.text = "You got it!";
        gameWon = true;
        endGame();
      }
    }
    public function checkGameOver():void
    {
      if (guessesRemaining < 1)
      {
        endGame();
      }
    }
    public function endGame():void
    {
      if (gameWon)
      {
        output.text
          = "Yes, it's " + mysteryNumber + "!" + "\n"
          + "It only took you " + guessesMade + " guesses.";
      }
      else
      {
        output.text
          = "No more guesses left!" + "\n"
          + "The number was: " + mysteryNumber + ".";
      }
    }
  4. Delete the following directive from the if statement in the
    startGame method
    . This text will be replaced by the new text from the
    endGame
    method. There's actually no harm in leaving it in, but it's redundant.
    output.text =  "You got it!";
  5. Compile the program and play the game. It now prevents you from guessing more than ten times and tells you whether you've won or lost.
    Figure 4-19
    shows what your game might now look like if you guess correctly.

Figure 4-19.
The game can now be won or lost.

The game needed to figure out whether the player used up all the guesses. Before you added the new code, you could count the guesses, but the program didn't know what to do with that information. The new code solves that.

The new methods have helped modularize the program by breaking the steps down into manageable pieces. Let's go on a little tour of how all this new code fits together.

First, you need to help the game figure out whether the player can still continue playing. You add the same
checkGameOver
method call to the first two blocks of the if/else statement in the
startGame
method, highlighted in bold:

public function playGame():void
{
  guessesRemaining--;
  guessesMade++;
  gameStatus = "Guess: " + guessesMade + ", Remaining: " + guessesRemaining;
  currentGuess = uint(input.text);
  if (currentGuess > mysteryNumber)
  {
    output.text = "That's too high." + "\n" + gameStatus;
    
checkGameOver();
  }
  else if (currentGuess < mysteryNumber)
  {
    output.text = "That's too low." + "\n" + gameStatus;
    
checkGameOver();
  }
  else
  {
    output.text = "You got it!";
    gameWon = true;
    endGame();
  }
}

The two new directives are method calls to the
checkGameOver
method. So as soon as the program reads one of these directives, it immediately jumps ahead to the
checkGameOver
method's function definition and runs whatever directives it contains.

Other books

Honest by Ava Bloomfield
That Summer in Sicily by Marlena de Blasi
Vanquished by Hope Tarr
White Dolphin by Lewis, Gill
Night Game by Christine Feehan
A Curious Courting by Laura Matthews
Exile's Song by Marion Zimmer Bradley