Read Foundation Game Design with ActionScript 3.0, Second Edition Online
Authors: Rex van der Spuy
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 thegameStatus
variable so you just need to use thegameStatus
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 thegameStatus
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 theguessesRemaining
andguessesMade
variables as uint variables (which are interpreted as numbers). Both of
them are joined together with ordinary text and copied into thegameStatus
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 theguessesRemaining
andguessesMade
variables remains unchanged as uint, but the values they contain are converted into a string when they're assigned to thegameStatus
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 thegameStatus
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 thegameStatus
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.
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 thegameStatus
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 specialgameStatus
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 thegameStatus
variable and you need to make any changes to it, you have to change it only once. Any place you use thegameStatus
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.
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 theguessesRemaining
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 theguessesRemaining
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 theguessesRemaining
variable to an int type has on your program, try it and see what happens!
guessesRemaining
variable so that its type is set to int:public var guessesRemaining:
int;
Remaining: -3
Keep this in mind whenever you decide what type to declare your variables.
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:
gameWon
that is set to true if the game has been won and false if it hasn't.checkGameOver
that checks to see whether the player has enough guesses remaining to continue playing.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.
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;
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);
}
startGame
method. Add two new methods,checkGameOver
andendGame
, 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 + ".";
}
}
startGame method
. This text will be replaced by the new text from theendGame
method. There's actually no harm in leaving it in, but it's redundant.output.text = "You got it!";
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 samecheckGameOver
method call to the first two blocks of the if/else statement in thestartGame
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 thecheckGameOver
method. So as soon as the program reads one of these directives, it immediately jumps ahead to thecheckGameOver
method's function definition and runs whatever directives it contains.