Preparing the
environment
1. Open a new Flash document and save it in a new folder in your Flash Gaming folder
— name the folder Quiz 2.
2. Download
the zip file that I prepared for you. Unzip it. You will find two
files inside it: guessword.txt
and words.xml.
Place both of them in
the folder where you saved your new Flash document. If you want, take a look at
them now, but really there is no need — I will discuss and explain them in
extensive detail later.
3. Back to your Flash document, select Modify
> Document to access the Document Properties panel. In the Dimensions section, enter 500 pixels for both width and height
fields. Click OK.
Of course, if
you want, you can pick any other dimensions for your Flash movie to suit your
needs, but for the sake of simplicity and easier work, make them as I suggested
above. These dimensions will make it easier for you to follow this tutorial and
place the graphic elements accordingly.
Creating the
hangman animation
4. Select the Pencil tool
(Y). In the Property
inspector, choose black
for the color, Solid as
line type and a line thickness of 5.
5. Draw a hangman, complete
with gallows. Its total dimensions (top to bottom, left to right) should be
about 130 pixels by 150 pixels.
Pay attention
to the following: the drawing should be composed of 9 separate lines, like
this:
It isn't
strictly necessary to do this, but if you follow my suggestion, you will find
the animation work that comes next much easier to follow. Also, if you want,
you can make more parts for the hangman: the one used in this lesson is made up
of nine parts, which allows the player to make nine errors before the game is
over. But I will leave that up to you — decide the level of difficulty that you
want to make for this game, and then draw the figure accordingly.
6. No matter how you drew
your hangman, do the following now: select
the whole drawing with the Selection tool (V).
7. Press F8 (or select Modify > Convert to Symbol) to
make a symbol out of this drawing. In the window that shows up, select Movie clip as type, call it hanging sequence and click OK.
8. Position your new
movie clip (using the arrow keys
or your mouse) in the upper right part of your document.
9. Double-click on the hanging sequence movie clip with the
Selection tool (V) to
enter inside it. To be sure that you are really inside the movie clip symbol, take a look above the stage, it is clearly written there:
10. Right-click on frame 2 of the only (so far) layer of
the movie clip and select Insert Keyframe. Your movie clip's timeline should
now look like this:
11. On the keyframe that you have just created, click once on an empty part of the stage to
unselect the drawing. Then, select a
leg of the figure by clicking on it with the Selection tool (V), and then hit Delete or Backspace to erase it.
12. Insert a new Keyframe
in frame 3 of the
current layer, just like you did in step
10.
13. Repeat the procedure you
did in step 11, this
time erasing the second leg of the character.
14. Repeat this procedure,
until you have 6 new keyframes, meaning 9 keyframes in total.
On each new keyframe you should erase a part of the
drawing. The image below shows how the drawing should look like in each of the
new keyframes.
15. Once you have finished
the previous step, select all the nine keyframes.
16. Now, right-click on any of the selected
(blackened) keyframes and select Reverse Frames from the menu that
shows up. Apparently, nothing has changed. But wait just a little more, you
will see why this was done.
17. With all the keyframes still selected, click on them and move
them forward by 1 frame, like the sequence of images below
shows:
Ok, let me
explain you now why all of this had to be done. When a player begins playing
the game, the drawing must not be visible at all, because no mistake has been
made yet. And when (if) the first mistake is going to happen,
the first part of the drawing — the vertical line of gallows — has to appear.
And that's why
you had to reverse the order of the keyframes — you
began by drawing the full image, on the first keyframe.
That was done because it is much, much easier to create the complete drawing
first and then just erase it part by part, until you arrived at a single line.
Imagine drawing the entire thing frame by frame: it is a waste of time. By
doing as I had laid the procedure out, you save time and just click and delete
as you go along.
18. Lock this layer (you are still inside
the movie clip, remember) and call it sequence.
Make a new layer above
it and call it actions.
19. Click on the first (and only) keyframe of the actions
layer to select it.
20. Select Window > Actions (shortcut key: F9) to open the Actions panel. Insert
the following line of code inside:
stop();
The stop(
)
action will prevent this movie clip
from going forward. As you know, all the animations in Flash loop endlessly by
default, unless you tell them otherwise via ActionScript.
And this movie clip should advance forward only if the player made a mistake.
You will make this possible later, when the main code is going to be written.
21. Click on the Scene 1 link above the layers to
return to the main scene.
22. The hanging sequence movie clip which you
just exited will be selected by default now. Go to the Property inspector and
give it the Instance name hangman_mc.
23. Call the current layer
(the only one so far) on the main scene hangman
and lock it.
You shouldn't
see anything inside your document right now, just the empty stage. This is
perfectly ok, since the first frame of the hanging
sequence movie clip is empty.
Creating the
dynamic text field
24. Make a new layer and
call it text field.
25. Select the Text tool (T). Pick the following options in the Property
inspector (see numbers on the image below):
1.
Choose Dynamic Text
on the panel's left side.
2.
Select the generic _sans
font type (you will find it at the top of the fonts list).
3.
Select a big font size, around 24.
4.
Pick black
as color or any other if you have a specific design for your game in mind.
5.
Select left alignment
for the text field.
6.
In the rendering options menu, select the Use device fonts
option.
7.
If you don't want the player to be able to select the text in
the field, leave the Selectable
option turned off.
8.
Your text field should be of the Single line type.
Most of these
options are self-explanatory. I just want to point out two options: the _sans generic font type and the Use device fonts rendering option.
The first one
is a wise thing to do, because it makes the user's operating system pick the
default sans serif font. Basically, this will allow for all users to see almost
the same thing. If you had chosen the Arial font for example, some Mac users
wouldn't see it. Likewise, if you are working on a Mac and you want to select
Helvetica, most Windows users won't see this font, because it doesn't come
pre-installed with the operating system. The _sans option automatically selects
the default sans serif font on any system.
The Second
option, for using the device fonts, means that your final SWF file intended for
the Web will be much smaller in size. Had you selected any other option, like
Anti-alias for animation or readability for example, you would have to select a
non-generic font family and after that, embed the characters in your SWF
document. Embedding makes the SWF file larger in size, because Flash must store
the vector shape data of the font's characters into itself.
Sure, if you
need a specific design with a specific font in mind, you may want to embed the
font data into your Flash movie. If you choose this method, every single user
will see the font you chose, regardless if it's installed on their system or
not.
26. Click and drag out a long text field
on the stage, somewhere along its vertical middle point. It should span the
whole stage width. When done, press Esc
on your keyboard to exit the text field.
Now, you
should be aware of a property here: the number of characters that can appear in
the text field. If you have made it as wide as I did, with the same
characteristics such as font type an size, it should
be able to display about 34 characters. Most of the words used in a hangman
game don't have such a high letter count, so you should be safe with the text
field that you just created.
On the other
hand, if you plan to make your game include some less commonly used words, like
latin animal species names, words used in science,
etc, you should either make your text field (and the size of your document)
wider, or pick a smaller font size. If you go for the second option, don't pick
a font size that is too small, because the word and the guessed letters must be
clearly visible.
27. With the dynamic text
field still selected, go again to the Property inspector and give it an Instance name: call it guessWord_txt.
That's it for
the text field. It's good and ready to be manipulated with via ActionScript.
Making the
movie clip with a dynamic text field, for runtime manipulation
The title of
this section mens the following: you will create a
movie clip which will be used at runtime. At runtime means while the SWF movie
is running. Instead of creating each letter button (for the player to press —
to guess a letter in the word) separately on stage, you will save lots of time
by making a single movie clip, and then writing some ActionScript
code that will create all the buttons for the entire alphabet.
28. Lock the current layer
and make a new one: call it start screen.
This layer
will in fact host the starting screen for the game. It is here that you will
create the movie clip with the text field, since it will be erased anyway. This
movie clip is going to be stored in the Library, so it really isn't necessary
to create a separate layer for it.
29. Select the Rectangle
tool (R) and draw a 31 by 31 pixel borderless square on the stage. If you prefer
buttons with borders, by all means do make a border. Pick any color you like.
30. Select the square and
press F8 to convert it
into a symbol. Pay attention to the following: select Movie clip as type and make sure to select the upper left corner for the Registration
point. Enter letter button
as name and click OK.
Selecting this
particular registration point will make the positioning of the many letter
buttons much easier later.
31. Double-click the newly made movie
clip on the stage to enter inside it.
32. Once inside it, call
the first layer background and lock it. Make a new layer and call it text field.
33. Choose the Text tool (T). In the Property inspector, all
the options should be the same as the ones in step
25 of this tutorial, except one: the font size. Make it smaller, change it to 18.
Click and drag
over the square and make a text field that covers almost all of it. Press Esc to exit the text field.
34. Go to the left side of
the Property inspector and assign an Instance
name to the text field: name it letter_txt.
35. Click on the Scene 1 link to go back to the main
scene and timeline.
36. Delete the movie clip that you have
just made from the stage. It is stored in the Library, so there is no need to
have it on the scene and/or assign it an Instance name. You will pull it out
dynamically, thanks to an identifier. You will see how to do just that in a
moment.
37. Open the Library if it
isn't open already (Window > Library). You will see your letter button movie clip nicely sitting
there, along with the hanging sequence
movie clip.
38. Right-click on the letter button movie clip
and select Linkage from
the menu.
39. The Linkage Properties window will
appear. Check the Export for ActionScript option. The Export in first frame option will
automatically follow. In the Identifier
field write letterButton
and click OK.
This movie
clip is now ready to be manipulated via ActionScript, thanks to the Identifier name you gave it and the Export
for ActionScript option.
The Export in
first frame option means (if checked, like in this case) that this movie clip
will begin to load before any other content in your SWF. This can cause
problems with large, graphics-intensive movie clips, because if you happen to
have a preloader in your SWF, it won't be visible
until that particular movie clip has completely loaded. But there is a simple
solution to that: make a SWF with just a preloader in
it, which in turn loads the main SWF with the movie clip in question inside it.
Here, you don't have to worry about that because the letter button movie clip's size is around
180 bytes :) !
Creating the
game start/game over screen
40. Still in the start screen layer, select the Rectangle
tool (R). Draw a big square on the stage, the
width and height of which should be about 430 pixels.
41. Convert this square into a Movie clip symbol, call it start screen and click OK. The registration point for this
one isn't important.
42. Double-click on the newly made movie
clip to enter inside it.
43. Inside the start screen movie clip, call the first
layer (containing the square) background
and lock it. Make a new
layer and call it play button.
44. In this layer, create a 160 by 50 pixel rectangle,
with round corners if you like, choosing any colors you like. Place it over the
lowest third of the background square and center it horizontally.
45. Use the Text tool (T) to write the message
"Play!" on top of it. This time, choose any font you like and make
sure that you have selected Static text
for your text field. This is a design element, not a dynamic one.
46. Using the Selection
tool (V), select both
the rectangle and the text field. Press F8 to convert it into a Movie clip — call it play it again sam or whatever you like
:) and click OK.
47. This movie clip will
need an Instance name,
so that you can tell it via ActionScript what to do
when a player presses it. So do just that: name it play_mc.
48. Lock the play button layer and make
a new one above it, with the name message.
49. Select the Text tool (T) again. Make sure that you have
selected Dynamic text.
Make the same choices for this tool as you did earlier in step
25, with one change: select the Multiline option, NOT the
Single line one.
50. Create a big text
field on the stage, that goes from the top of the background square, down to
the play button and spans the square from side to side. Hit Esc to exit the text field. You can
see the text field's blue border in the image below.
51. This text field will
display the welcome message, with a piece of dynamic data inside it, so it
needs an Instance name.
Call it message_txt.
52. Go back to the main
scene and give the start screen
movie clip the Instance name
startScreen_mc.
53. Lock the start screen layer.
Loading data
from a text file into Flash using the LoadVars object
54. Make a new layer and call it actions. Lock it, since a layer in Flash doesn
not need to be unlocked for you to enter ActionScript
code inside it. Click
on the layer's first (and only) keyframe to select it
for code inserting.
55. Select Window > Actions to open the
Actions panel. Insert the following ActionScript code
inside it:
guessWord_txt._visible = false;
var welcomePart1:String = "Welcome to the
hangman game! To, win you must try to guess the name of ";
var welcomePart2:String = ". Press the play
button below to start.";
var guessTopic:LoadVars =
new LoadVars();
guessTopic.onLoad = function(success:Boolean)
{
if (success) {
startScreen_mc.message_txt.text = welcomePart1+this.myTopic+welcomePart2;
} else {
startScreen_mc.message_txt.text = "The data failed to load. I am sorry!";
}
};
guessTopic.load("guessword.txt");
The first line
effectively hides the guessWord_txt
text field by setting its _visible
property to false
. It will be made visiblke once the player presses the play button, the
functionality of which will be defined later.
The second and
the third line define the welcomePart1
and welcomePart2
variables. Both are
defined as String
variables,
which means that they will hold text values. And these text values are
assigned to them immediately. They are, respectively:
§
"Welcome to the hangman game! To, win you must try to guess
the name of " and
§
". Press the play button below to start."
They may
appear a little strange. If you look at them closely, you will see that the first one ends with a space and
that the second one starts with a fullstop, followed by a space and another
sentence. This is because they will both be parts of the welcome message, once
the game loads. The third piece of information for the welcome message will be
loaded from an external text file.
The main
reason for doing so is that once you finish the SWF file, with all the ActionScript code that you are going to add, you will have a completely dynamic game at your
disposal. You won't have to edit the .fla file
anymore and re-export it as a .swf. If you ever want
to change the topic of the game (the type of word to be guessed) and the words,
all you will have to do is edit the text and XML files,
upload them to your website, and that's it! That's a much, much better solution
than cementing the values inside the Flash file and having to re-edit it every
time you want to have a different game.
Suppose that
you want the player to guess the name of an animal. The welcome message would
be as follows: "Welcome to the hangman game! To, win you must try to guess
the name of an animal. Press the play button below to
start."
The two bolded words, "an animal", are placed in the guessword.txt file that you have
downloaded at the beginning of this tutorial. Why both the article and the
noun, and not just "animal"?
Well, suppose
that you are going to change the game so that the player has to guess the name
of a city. If you had put the article "an" into the code of your .FLA
file, the resulting message would be "...guess the name of an city", which is bad English. So it is logical that
both the type of word to be guessed an its article
should be put in the external text file. Thanks to this, you can just change
"an animal" into "a city".
And now comes the chunk of code
that loads the text file and performs different actions,
depending on whether the external text file was loaded successfully or not. The
first line creates a new LoadVars
object, which is used to load external variables into Flash or export
variables to an external source:
var guessTopic:LoadVars = new LoadVars();
Like with the
majority of objects in Flash, you can't create them separately, like this: new LoadVars()
. This won't work at all. You must create a variable (guessTopic
in this case) and then
store an instance of the object that
you wish to use inside that variable, exactly like is shown in
the line of code above. Since you are creating a new LoadVars
object, the type of
the guessTopic
variable is set to LoadVars
, of course (guessTopic:LoadVars
). Once you do that, for all practical
purposes, you can say that the guessTopic
variable is in fact an
instance of the LoadVars
object.
Let me show
you now how to load variables from an external source (the guessword.txt file in this case) using
the LoadVars
object that you just
created. Before loading
the actual data, it is considered the best practice to tell Flash first what to do once the loading has finished,
and then order it to load the data.
To do this,
you must use the onLoad
event handler of the LoadVars
object.
guessTopic.onLoad = function(success:Boolean) {
if (success) {
startScreen_mc.message_txt.text = welcomePart1+this.myTopic+welcomePart2;
} else {
startScreen_mc.message_txt.text = "The data failed to load. I am sorry!";
}
};
guessTopic.load("guessword.txt");
REMEMBER In ActionScript,
an event handler is a function that is called and executed automatically when a
particular event occurs. An event is something that happens in your movie: the
user clicking a button, a sound finishing playing, the mouse being moved and so
on. By inserting event handlers into your code, you enable Flash to react when
an event has transpired — you tell it what to do.
So, the onLoad
event handler reacts
when external variables
(variables stored in guessword.txt
file in this particular case) have been
converted into object properties. To better understand this,
have a look at the guessword.txt
file. Open it and look at its contents. You will see this:
myTopic=an+animal
myTopic is the name of the
variable, and an+animal is its value. You have
certainly noticed the plus (+) sign between these two words. It is used to
denote spaces in a file that is going to be loaded via the LoadVars
object. You can't just
put a simple space between the value's words, you must separate them with a plus sign.
If you are
going to create a project where you will need multiple variables with different
values, your text file's contents would look like this:
myName=John&mySurname=Smith&myAddress=Flash+plaza&myCity=Flashville&myCountry=Flashia
As you can
see, the various variables with their respective values are separated by
ampersand signs (&). In programmer's jargon, these variables and their
values are called name/value pairs.
I mentioned above
that once loaded, these external variables will be converted into object
properties. What this means is that the myTopic
variable will become a
property of the guessTopic
LoadVars object.
Thanks to that, you can retrieve the value of this variable by referencing it
like this: guessTopic.myTopic
. And from that, Flash
would read the value, which "an animal" in this case.
Fine! Now that
you understand how the LoadVars object loads external
variables into Flash, let me show you how it will react once the data has been
loaded. As you can see, the first line calls the guessTopic
object's
onLoad
event handler, with a
parameter passed to it: success
. This parameter is of
the Boolean type,
meaning that its value can be either true
or false.
guessTopic.onLoad = function(success:Boolean) {
if (success) {
startScreen_mc.message_txt.text = welcomePart1+this.myTopic+welcomePart2;
} else {
startScreen_mc.message_txt.text = "The data failed to load. I am sorry!";
}
};
This parameter
is necessary, because you must check
if the variables have been loaded and converted into properties of the guessTopic
LoadVars
object. The contents of the event handler function do just that (they are
located between the function's curly braces: {
and }
). Here, the contents consist of an if/else
conditional statement.
If the value
of success
turns out to be true (meaning the data has been
loaded and converted successfully), the welcome message will be displayed. If
it turns out as false,
an error message will be displayed. In both cases, the message will be
displayed in the message_txt
text field, which is situated inside the startScreen_mc
movie clip. In the
first case (when success
equals true), the message will be composed
of three variables' values:
welcomePart1+this.myTopic+welcomePart2
You have
already defined and seen the values of the variables welcomePart1
and welcomePart2
. The middle one is reffered to as this.myTopic
. The keyword this
points to the guessTopic
object itself, because it is written
inside the object's onLoad
event handler function. And, just as I said
previously, the myTopic
property is the variable that has been loaded
from the external text file and converted into a property of the guessTopic
object. Its value:
"an animal". Without the quotation marks, of course — I have written
them here to better distinguisg the value from the
surrounding text. So the welcome message will inform the player what is the
topic of the game (an animal, a city, a car, etc).
And if the
loading fails, the "I'm so sorry" message is displayed :). If the
loading fails, it is basically beyond your control. The loading error could be
due to the problems the player may have with his Internet connection, his
firewall and so on. The best thing that you can do is to notify the player that
the loading has failed.
IMPORTANT The one thing that you must pay attention to is to place the
text file (guessword.txt) in
the same folder on your website where the final SWF file (the hangman game
Flash movie) is going to be. Also, make sure that the HTML file — the page
inside which the Flash SWF file will be embedded is also in this same folder.
The same goes for the XML file.
These files do
not necessarily have to be in the same folder — I did it like this for the sake
of simplicity. You can even put the files on different web servers if you want
to, but some additional steps must be made then for the game to function
properly. And I don't wish to discuss this subject here, because this tutorial
would span tens of pages. Instead, I will save that for another tutorial, where
the cross-domain file loading policy will be explained in more detail.
Finally comes the line that actually tells Flash to load data from
the external text file:
guessTopic.load("guessword.txt");
But... as you
may have noticed, there is no preloader here. Why?
Because the guessword.txt text
file has a size of 17 bytes!
Making a preloader for this tiny bit of data makes no
sense at all. This file will load instantly even on a prehistoric 14.4 K modem
connection!
Defining the
game variables
56. Place the following
code right after the one that you wrote previously:
var words:Array =
new Array();
var alphabet:String =
"abcdefghijklmnopqrstuvwxyz";
var chosenWord:String = new
String();
var displayedText:String =
new String();
var playAgain:Boolean =
false;
Here, you are
defining variables that will be used later. If possible, it is a fine practice
that you define as many variables as possible in one place. This makes your
code more clean and easy to edit later. Let's see what will
each variable be used for:
§
The words
variable is of the Array type, meaning it will store many values. Later, you will write
the code that will load the XML, find all the words for the hangman game and
put it inside this array.
§
The String (a String value is a text value, remember) variable alphabet
holds inside all the
letters of the English alphabet. This is necessary for checking if a letter the player has
pressed is inside the hidden word or
not.
§
The chosenWord
variable (a String, too) will hold inside
itself a randomly picked word from the words
array. This is a must, otherwise the same word would pop up each time, which
would render the game useless.
§
The displayedText
(again, a String) variable's value is the text that will be shown in the guessWord_txt
text field. This is a piece of
text that will consist of correctly guessed letters and dots (or question
marks) that fill in for the letters that haven't been guessed by the player
yet.
§
The variable playAgain
is of the Boolean type
and is set to false
. This variable will
serve for checking if the player has
pressed the play button after finishing the first game (whether
she succeeded in guessing the hidden word or not) and subsequently, resetting the guessWord_txt
text field to its inital state, with no text at all displayed inside it.
Using ActionScript to load XML data into Flash
57. Append this code after
the existing one:
var wordsLoader:XML
= new XML();
wordsLoader.ignoreWhite = true;
wordsLoader.onLoad = function(success) {
if (success) {
parseWords();
} else {
guessWord_txt.text = "Sorry dude, the data just didn't load.";
}
};
wordsLoader.load("words.xml");
As you can
see, this code is similar to the previous one. At first, a new XML object is
created (wordsLoader
). After that, the XML object's onLoad
event handler function
is invoked, to check if the loading succeeded or failed. Like before, this
function has inside it an if/else conditional statement. If success
turns out as true
, the parseWords
function is invoked
(more on that function later). If not, a "I am
sorry" message will be displayed for the user. And after that, the actual XML file gets loaded via the XML object's load
function.
Before I
explain you the workings of the XML file, there is one line of code that needs
to be explained: the second one, with the ignoreWhite
property. The ignoreWhite
property of an XML
object can be set to either true or false. By defining it as true
, you tell Flash to ignore all the white space found in
the XML file. Why is this necessary? Because white space in an XML file counts
as data! Fine. Now that the above piece of code is
clear, let me tell you more about XML.
A brief
explanation of XML data format and its rules
If you open
the file words.xml
(which you have downloaded at the start of this tutorial), you will see the
following:
<?xml version="1.0"?>
<gamedata>
<word>dog</word>
<word>elephant</word>
<word>cat</word>
<word>lion</word>
<word>giraffe</word>
<word>wolf</word>
<word>ostrich</word>
<word>penguin</word>
<word>whale</word>
<word>raccoon</word>
<word>tiger</word>
<word>camel</word>
<word>snake</word>
<word>lizard</word>
</gamedata>
Before
proceeding, you should know that XML
stands for EXtensible
Markup Language. It is a markup language
that describes data.
The great thing about the XML data format is that it is platform and operating system independent.
This means that an XML file looks exactly the same, whether it is made or read
on Linux, Mac, Windows or any other OS or platform. An XML file is basically a text file,
with the extension .xml.
When making an
XML file, you can use any basic text editor, like Notepad on Windows or
SimpleText on a Mac. The important thing to keep in mind is that you should
save this file with an .xml extension. Or, you can save it as a .txt file and
later change the extension to .xml in your File Explorer.
An XML file can not do anything by itself — it is
parsed (read, combed
through, looked at) by various programs, browsers, server-side scripts (PHP,
Java...) etc if they are enabled to do so. So, you can think of it as a very
simple database — stored information.
Unlike an HTML
file, where tags are predefined (<p>, <body>, <h1> etc), you are the one who defines the tags in an XML file.
This means that you can call your tags any way you like, for example:
<flash>, <mysuperbtag>, <anything>
etc. But, there are some rules
that must be followed. These are really simple, but very, very strict. You must abide by them. Here they
are:
§
Each XML file must begin with the XML declaration:
<?xml version="1.0"?>
This line
tells the parser that it's, well, an XML file. This is not a tag, but just a
declaration. So it appears only once, at the beginning of the XML file. Inside
it, the version of XML is stated. Also, the character encoding of the file can
be included, like this, for example:
<?xml version="1.0"
encoding="UTF-8"?>
Since the XML
file used in this tutorial is written in English, that additional parameter is
not necessary.
§
While being composed of different elements, all XML files
can contain only one root element. In this example, the root element is <gamedata>. Between the opening and closing tags of the
root element, every other element is included. Nothing can be placed outside
it:
<gamedata>
<word>dog</word>
<word>snake</word>
<word>lizard</word>
</gamedata>
Note: I have
named each tag within the root element as "word" on purpose (you will
see why later). For example, an XML file like this one would be perfectly valid
too:
<computer>
<operatingsystem>windows</operatingsystem>
<processor>intel</processor>
<price>expensive</price>
</computer>
§
Each element must have a closing tag (except the
declaration). So, the following example would result in an error and the XML
file couldn't be parsed:
<gamedata>
<word>dog</word>
<word>snake
<word>lizard</word>
</gamedata>
§
The XML tags are case-sensitive. The opening and closing
tags of a node must be exactly the same. Following this rule, this would be ok:
<word>dog</word>
...while this
would cause an error:
<Word>dog</word>
§
All the elements of an XML file must be nested correctly. This is an example of
proper nesting:
<diary>
<day>monday</day>
<entry>Another week, another monday</entry>
</diary>
...while this
one is wrong:
<diary>
<day>monday<entry>
</day>Another week, another monday</entry>
</diary>
Here's another
example. This would be fine:
<flowers><best>rose</best></flowers>
...and this
would result in an error:
<flowers><best>rose</flowers></best>
§
Any attribute values must be included within quotation
marks. A good example of this would be:
<logentry day="monday">Another day at work</logentry>
...while this
is incorrect:
<logentry day=monday>Another day at work</logentry>
Also, remember
that you can insert as many attributes as you need.
These were the
rules for writing proper XML. As you saw, they are really simple. You just have
to respect them.
One more thing:
as I said before, the white space in an
XML file counts as data. That's why you had to set the ignoreWhite
property to true
in your ActionScript
code previously. This can be circumvented with another method, namely, to leave
no spaces between your elements, like this:
<gamedata><word>dog</word><word>snake</word><word>lizard</word></gamedata>
But this is
really hard to read and edit. It is much better to put each element of your XML
file on its separate line and use the ignoreWhite
property.
How Flash parses
the XML data
58. Add this ActionScript code after all the existing one:
function parseWords():Void
{
if (wordsLoader.firstChild.nodeName
== "gamedata") {
var rootNode:XMLNode = wordsLoader.firstChild;
for (i=0; i<rootNode.childNodes.length; i++)
{
if (rootNode.childNodes[i].nodeName == "word")
{
var currentWord:String = rootNode.childNodes[i].firstChild.nodeValue.toString();
words.push(currentWord);
}
}
}
}
As I mentioned
before, the parseWords
function will be called upon once the XML
data has been successfully loaded. The first line inside this function is a
conditional if statement:
if (wordsLoader.firstChild.nodeName
== "gamedata") {
...which checks to see if the first
child of the wordsLoader
XML object is named (nodeName
) "gamedata".
The first child of the wordsLoader
XML object is indeed named "gamedata". On the previous page, I have shown you that
an XML file can contain only one root node. The root node is the first child
(the first element in the XML file's hierarchy) of the XML object. In this
case, the root node is <gamedata>
.
So, there is
no need for an if/else
conditional statement
— an if
condition will do, because Flash
will read it and see that it evaluates as true. So, it will perform all the code within the
conditional statement's curly brackets:
var rootNode:XMLNode = wordsLoader.firstChild;
for (i=0; i<rootNode.childNodes.length; i++)
{
if (rootNode.childNodes[i].nodeName == "word")
{
var currentWord:String = rootNode.childNodes[i].firstChild.nodeValue.toString();
words.push(currentWord);
}
}
The first line
creates the variable rootNode
, which is of the XMLNode
type. This variable is
created just so that you don't have to write wordsLoader.firstChild
each time (remember, firstChild
is the gamedata
root node in this
lesson's example). It is merely a shorthand name.
And then the for
loop begins, which is used to read all
the words that will be used in the game and store them in an array:
for (i=0; i<rootNode.childNodes.length; i++) {
if (rootNode.childNodes[i].nodeName == "word")
{
var currentWord:String = rootNode.childNodes[i].firstChild.nodeValue.toString();
words.push(currentWord);
}
}
This loop
starts with the variable i
set to 0 (zero). The
loop will make iterations (i.e. it will repeat itself) as long as its condition evaluates as true. And it will increase the value
of i
with each loop (i
++
). The condition is that i
must be lesser than
the number of the child nodes of the root node. The number of the
child nodes of root node is retrieved by calling upon childNodes'
length
property:
i < rootNode.childNodes.length
In this
particular example, this means that i
must be lesser than 14. Why? Because there
are 14 child nodes inside the gamedata node:
<?xml
version="1.0"?>
<gamedata>
<word>dog</word>
<word>elephant</word>
<word>cat</word>
<word>lion</word>
<word>giraffe</word>
<word>wolf</word>
<word>ostrich</word>
<word>penguin</word>
<word>whale</word>
<word>raccoon</word>
<word>tiger</word>
<word>camel</word>
<word>snake</word>
<word>lizard</word>
</gamedata>
As you can
see, each child node of the root node has the name word
. This is used by the if
conditional statement contained within the loop:
if (rootNode.childNodes[i].nodeName == "word")
{
var currentWord:String = rootNode.childNodes[i].firstChild.nodeValue.toString();
words.push(currentWord);
}
If the name of
the current child node equals "word", the actions inside the if
condition will be performed. Of course,
Flash replaces the construct [i]
with the current loop
iteration number (0, 1, 2, 3 etc), so that it can
check each child node: the first one, second... until the last one (which is
the fourteenth in this case). Since each child node inside the root one really is named "word", the
following two lines will be executed:
var currentWord:String = rootNode.childNodes[i].firstChild.nodeValue.toString();
words.push(currentWord);
A new variable
called currentWord
is created and it is
of the String
type (meaning it holds
a text value). Inside it, the name of the current child node node will be stored:
rootNode.childNodes[i].firstChild.nodeValue.toString();
As you can see
in the ActionScript line above, the toString
(
)
method is used to convert the value of the child element of each root node's
child node to a piece of text. Because this is XML data (nodeValue
), and not text data, it has to be converted
to a String so that you can use it later in the game. If this XML order puzzles
you, here's a nice graph explaining the hierarchy inside the
XML object:
Once this
value is retrieved and converted to text, it is stored inside the words
array (which you
created in the first lines of your code):
words.push(currentWord);
The push
method inserts an element to the end of
an array. Since the array is completely empty at the beginning, the first
element will be placed on the first place, the second one after that, etc. So, with each iteration of the loop, a word pulled out from the words.xml
file will be placed inside the words
array. Nice! And easy, as you can see.
All you have to learn to be able to make Flash read data from an XML file is write some conditional statements and a loop and that's it.
Ok, after
Flash has executed this chunk of code, you will have all the words from your
XML file at your disposal, neatly stuffed into an array. Let me show you now
how you can pull a word at random from this array so that the player has a
different word to guess each time she plays the game.
Making a
randomizing function with ActionScript
59. Paste this code after
the one from the previous section:
function
randomize(playAgain):Void {
var randomNumber:Number = random(words.length);
chosenWord = words[randomNumber];
if (playAgain) {
guessWord_txt.text = "";
}
for (var i:Number
= 0; i<chosenWord.length;
i++) {
guessWord_txt.text = guessWord_txt.text+".";
}
displayedText = _root.guessWord_txt.text;
}
As is obvious
from the first line, this function has a parameter passed to it, playAgain
. When you created this
variable earlier, you defined it as a Boolean
type of variable, with its initial value set to false:
var playAgain:Boolean = false;
This is to
make possible for different actions to execute, depending whether the player is
playing for the first time, or a subsequent one. Let's see how this actually
works: the function randomize
is called only when
the player has clicked the "Play!" button (you will add the code
for this button at the very end of this tutorial). So, suppose the player is
playing the game for the first time. The button is clicked, and the randomize
function is called,
with the playAgain
parameter passed to it with its value set to false.
The first line
inside the function creates the randomNumber
variable, of the Number type.
Its value is a random value, chosen between zero (the zero itself
included) and the number between the parenthesis (words.length
). So, in this example,
you have 14 elements inside the words
array. And Flash knows this thanks to the array's length
property which can
retrieve it. So, Flash would pick the value like this:
var randomNumber:Number = random(words.length);
randomNumber = random(14);
So a random
value is chosen between 0 and 13. Next, from this same array (words
), the word
corresponding to this random number is chosen:
chosenWord = words[randomNumber];
Flash reads
the randomNumber
variable's value and searches for the element with that position inside
the words
array, and stores it inside the chosenWord
variable. Elements of an array
have numbered positions, starting from zero, like this:
Next, Flash
checks if the value of the playAgain
variable is set to true:
if (playAgain) {
guessWord_txt.text = "";
}
And if it is,
the text field which displays the letters the player has guessed is emptied
from any text. Why? Because if playAgain
equals true, it means
the player has pressed the "Play!" button again and the game is
started again. And it is logical that if it is going to be played again, that
the text field has to be empty again.
After that,
the following code is executed, no matter if the playAgain
variable equals true or
false:
for (var i:Number = 0; i<chosenWord.length; i++) {
guessWord_txt.text = guessWord_txt.text+".";
}
displayedText = _root.guessWord_txt.text;
This is a
familiar for
loop. The condition
for the loop to exit is that i
must be lesser than the number of characters
of the word stored inside the chosenWord
String variable. Let's
say for example that the word "lion" was the one randomly picked from
the words
array. It has 4
characters (letters) inside it: lion. So, the loop will go from 0 to 3. Once it
reaches 4, it will break and stop executing the code inside itself. And this
code says the following:
guessWord_txt.text = guessWord_txt.text+".";
The text shown
inside the guessWord_txt
text field equals the text already found in
it, with a dot (.
) added to its end. So,
in the case the word "lion" was picked, the for
loop will make 4 iterations, and the following would be seen by the player in
the text field: ....
Four dots,
that's right. If you don't like the dots (which represent the letters of the hidden word), you can
put a question mark (?) or any character that you deem appropriate. The loop
goes like this: the first time, there is nothing displayed in the text field,
so:
guessWord_txt.text = guessWord_txt.text+".";
guessWord_txt.text = "" + ".";
guessWord_txt.text = ".";
During the
second loop, it goes like this:
guessWord_txt.text = guessWord_txt.text+".";
guessWord_txt.text = "." + ".";
guessWord_txt.text = "..";
etc.
And so on,
until you get 4 dots displayed. Next comes the line of
ActionScript code that comes after the loop:
displayedText = _root.guessWord_txt.text;
The text that
is displayed inside the guessWord_txt
field on the stage (i.e. the dots
representing the hidden word) is stored inside the displayedText
variable which you
defined earlier. This variable will be
used to store the letters guessed by the player along with the dots,
so that the proper thing can be displayed and compared to the complete hidden word (you will see
how this comparison is done later).
ActionScript code that makes up the main hangman game functionality
60. Paste this ActionScript code right after the one inserted so far:
function placeLetters():Void {
this.createEmptyMovieClip("allLetters_mc",
1);
allLetters_mc._y = 300;
allLetters_mc._x = 20;
for (var i:Number = 0; i<alphabet.length; i++) {
var newLetter:MovieClip = allLetters_mc.attachMovie("letterButton",
"letter"+alphabet.charAt(i), i);
newLetter.letter_txt.text = alphabet.charAt(i);
if (i<8) {
newLetter._y = 0;
newLetter._x = i*40;
} else if (i>=8 && i<16)
{
newLetter._y = 40;
newLetter._x = (i-8)*40;
} else if (i>=16) {
newLetter._y = 80;
newLetter._x = (i-16)*40;
}
newLetter.onRelease = function() {
var matchFound:Boolean =
false;
var clickedLetter:String = this._name.charAt(this._name.length-1);
for (var j:Number = 0;
j<chosenWord.length; j++) {
if (chosenWord.charAt(j) == clickedLetter)
{
_root.guessWord_txt.text = displayedText.substr(0,
j)+clickedLetter+displayedText.substr((j+1));
matchFound = true;
this._visible = false;
}
displayedText = _root.guessWord_txt.text;
}
if (displayedText == chosenWord)
{
endOfGame(true);
}
if (matchFound == false) {
this._visible = false;
_root.hangman_mc.nextFrame();
if (hangman_mc._currentframe == 10) {
endOfGame(false);
}
}
};
}
}
Now that is
one loooong function! Don't be afraid of it :). I
will show you step by step what each of this function's parts does and how it
works. Before starting, just know that this function is also called once the
player has pressed the "Play!" button.
Creating a new
movie clip instance from scratch
The first code
inside the function that gets executed are three
lines:
this.createEmptyMovieClip("allLetters_mc",
1);
allLetters_mc._y = 300;
allLetters_mc._x = 20;
The first one creates a new movie clip from scratch.
The keyword this
means that the movie
clip will be created on the main or _root timeline, since the keyword itself
resides inside the placeLetters
function which is placed on the main
timeline.
The createEmptyMovieClip
command creates, well,
an empty movie clip :). It has two parameters which must be defined: the Instance name of the new movie clip
called allLetters_mc
(without it, you
wouldn't be able to do anything with it) and the depth at which it is stored. The
depth is like a third imaginary dimension on the computer's screen. The higher
the number, the more "closer to you" and further "away from the
screen" the movie clip will be placed. The main timeline is on depth 0
(zero). So by choosing 1 as depth value fro your new movie clip is fine.
The next two
lines place this new movie clip on new
coordinates — 300 pixels from the top of the stage (_y = 300
) and 20 pixels to the
right of the stage's left edge (_x = 20
). You have to move this movie clip so that its contents
(which will come in a moment) do not overlap with the main text field (guessWord_txt
).
Placing the
letter buttons on the stage
Now comes the main for
loop which makes up the
biggest part of the placeLetters
function. Everything except the above
three lines of code is placed inside it.
for (var i:Number = 0; i<alphabet.length; i++) {
Just as the
previous for
loops, this one starts
with i
set to zero, which is
incremented by 1 at each pass of the loop. The condition that must be fulfilled
in order for the loop to exist is that i
must be lesser than
the number of characters found in the alphabet
variable. As you remember, you
made this variable at the beginning, like this:
var alphabet:String = "abcdefghijklmnopqrstuvwxyz";
This is a
String (text) variable, which holds inside all the letters of the English
alphabet. So the loop will make as many iterations as
there are letters in the alphabet (26).
This makes perfect sense, because you must write the code that will place a button for each alphabet letter on
the stage.
And here is
the code that places the letter buttons on the stage:
var newLetter:MovieClip
= allLetters_mc.attachMovie("letterButton",
"letter"+alphabet.charAt(i), i);
newLetter.letter_txt.text = alphabet.charAt(i);
if (i<8) {
newLetter._y = 0;
newLetter._x = i*40;
} else if (i>=8 && i<16)
{
newLetter._y = 40;
newLetter._x = (i-8)*40;
} else if (i>=16) {
newLetter._y = 80;
newLetter._x = (i-16)*40;
}
The first line
serves attaches a movie clip dynamically from the Library onto the stage:
var newLetter:MovieClip = allLetters_mc.attachMovie("letterButton",
"letter"+alphabet.charAt(i), i);
On the left
side of the assignment operator (=
) is the already
familiar variable definition which is here, of course, of the MovieClip
type. Then, you tell
Flash to attach a movie clip from the Library to the empty movie clip that you
have just made previously (allLetters_mc.attachMovie
). This is done by
first stating the Identifier name
of the movie clip in the Library: letterButton
in this case. You have
defined this identifier when you created the small movie clip before. It is the
one with the small dynamic text field inside. Here is the image of this movie
clip, to avoid any confusion:
After that
comes the new Instance name
of the movie clip, created dynamically: "letter"+alphabet.charAt(i)
. This must be done
like this in order to have a different
Instance name for each letter button. Since the main loop makes as many passes
as there are letters in the English alphabet (26), each movie clip attached
from the Library will have a unique name, associated with the letter it
represents. At the first iteration of the loop, when i
equals zero, you will
obtain the following result:
"letter"+alphabet.charAt(i)
"letter"+a
lettera
Then
letterb
, letterc
, etc. This is thanks to the charAt
(
)
method of the String object. The
variable alphabet
(which contains all
the letters of the alphabet) is a String. The charAt
(
)
method finds and reads
the character situated at the position written between the parenthesis. In this case, this is i
, meaning it is
different at each iteration of the loop — so every
letter of the alphabet will be read and the unique Instance name made from it.
The last parameter of the attachMovie
(
)
method is the depth of the movie clip pulled from
the Library. This is again the variable i
. This tells you that
the depth of each movie clip will be unique. Which is
excellent, because if you'd attach each movie clip on the same depth level, the
previous one would get erased.
There can be only one movie clip instance present on each depth level, on the location where you are attaching them.
In this exercice, you are attaching all these movie
clips inside the allLetters_mc
movie clip which was made from scratch.
Inside it, you can place as many movie clips as you like, as long as each one
of them has its own unique depth level. But, imagine that you had another movie
clip which would get attached ones from the Library. In it, you could again
attach them using the same depth levels (0, 1, 2, 3, etc) because this would
have no influence whatsoever on the first movie clip. Each movie clip is like a
small world which can within itself host many other movie clips.
OK. During each iteration of the loop, a movie clip gets
attached and receives its unique Instance name. And it is stored inside the newLetter
variable. This is done so that during each iteration you can just reference this newly
attached movie clip by telling Flash newLetter
, instead of typing the
whole thing, which is different each time. This simplifies your ActionScript coding greatly and makes life a lot more easier.
The next line
makes the appropriate letter appear in
the dynamic letter_txt
text field inside each
movie clip:
newLetter.letter_txt.text = alphabet.charAt(i);
Now comes an if/else if
conditional statement:
if (i<8) {
newLetter._y = 0;
newLetter._x = i*40;
} else if (i>=8 && i<16)
{
newLetter._y = 40;
newLetter._x = (i-8)*40;
} else if (i>=16) {
newLetter._y = 80;
newLetter._x = (i-16)*40;
}
This one
serves to place the letter buttons (they act as buttons, but they are movie
clip symbols, of course) on the stage in three separate rows. The first eight buttons
(i
<8
) will be placed in the
first row:
if (i<8) {
newLetter._y = 0;
newLetter._x = i*40;
That's because
the _y
property (vertical
position) is the same: 0. The horizontal coordinate (_x
) is always different: it is the result of i
(0, 1, 2, 3, etc) being multiplied by 40. Why 40?
Because the letter button movie
clip which gets attached from the Library is 31 pixels wide. So by choosing 40
you leave 9 pixels of space between each button. The next portion of letters (i
>=8 && i<16
) goes in the second
row, below the first one, by setting the _y
property of each movie clip here to 40:
} else if (i>=8 && i<16) {
newLetter._y = 40;
newLetter._x = (i-8)*40;
The _x
property is made by first substracting 8 from i
and then multiplying the result by 40. If you
don't substract this, the movie clips would be placed
further to the right, away from the first row.
And here's the
rest, following the same placement principles:
} else if (i>=16) {
newLetter._y = 80;
newLetter._x = (i-16)*40;
}
Thanks to the if
conditional statement, the final result
looks like this:
Making the
buttons clickable
Let me show
you now how the buttons are made clickable via ActionScript
(you already pasted this code, don't do it again :)):
newLetter.onRelease = function() {
var matchFound:Boolean = false;
var clickedLetter:String = this._name.charAt(this._name.length-1);
for (var j:Number
= 0; j<chosenWord.length; j++) {
if (chosenWord.charAt(j) == clickedLetter) {
_root.guessWord_txt.text = displayedText.substr(0, j)+clickedLetter+displayedText.substr((j+1));
matchFound = true;
this._visible = false;
}
displayedText = _root.guessWord_txt.text;
}
if (displayedText == chosenWord) {
endOfGame(true);
}
if (matchFound == false) {
this._visible = false;
_root.hangman_mc.nextFrame();
if (hangman_mc._currentframe ==
10) {
endOfGame(false);
}
}
};
As you can
see, all the function's code is included within each attached movie clip's onRelease
event. This event happens
when the player press and releases
the mouse button over a movie clip. If you want, you can replace this with the onPress
event, which happens the instant the mouse button is pressed over the
movie clip. But this latter event is best used when something has to happen quick, like a spaceship firing a shot in a shoot 'em up kind of game.
Inside the
function, the first two lines are these:
var matchFound:Boolean = false;
var clickedLetter:String = this._name.charAt(this._name.length-1);
First, the matchFound
variable is created,
which will be later used to check if the player has clicked on a letter that is
inside the hidden word. It is set to false
at the beginning. Now you have to make Flash know which
letter the player has clicked. To do this, you have to create a String variable
which will store the clicked letter: var
clickedLetter:String
. After that, you retrieve the clicked letter
from the movie clip's Instance name:
this._name.charAt(this._name.length-1)
The construct this._name
refers to the Instance
name of the movie clip that has been clicked. The ActionScript
keyword this
refers to the clicked
movie clip because it is placed inside
its onRelease event handler. After
that, you use the charAt
(
)
method to extract the appropriate
character/letter. Suppose the current movie clip is for example buttone
. Flash would extract
the letter e
like this:
this._name.charAt(this.name.length - 1)
this._name.charAt("lettere".length
- 1)
this._name.charAt(7 - 1)
this._name.charAt(6)
e
The length of the Instance name lettere
is 7 characters. The first character in a string always has the
position set to 0 (zero). That's why by substracting
1 from 7 you get 6, which is the position of the last character in the string,
which is e
in this case. And that
character gets stored inside the clickedLetter
variable.
Using ActionScript to find a matching letter inside a word
Now comes a
new for
loop:
for (var j:Number = 0; j<chosenWord.length;
j++) {
if (chosenWord.charAt(j) == clickedLetter) {
_root.guessWord_txt.text = displayedText.substr(0, j)+clickedLetter+displayedText.substr((j+1));
matchFound = true;
this._visible = false;
}
displayedText = _root.guessWord_txt.text;
}
Here, a new
variable, j
, is used, to avoid any
conflict with the previous i
in the main loop. It
is this for
loop that is checking if the clicked letter can be found anywhere
in the hidden word that has to be guessed. To accomplish that, the loop must pass through all the letters of the
word (to be programatically correct,
all the characters of the string). That's why the condition of the loop is: j < chosenWord.length
. The variable j
will increase until it reaches the
length (of characters) of the hidden word, the one that is stored inside the chosenWord
varaible.
The loop
checks if the clicked letter is inside the hidden word with the help of an if
conditional statement:
if (chosenWord.charAt(j)
== clickedLetter) {
This literally
tells Flash:
if (the character at position j inside the
string chosenWord equals the clickedLetter)
{
...execute the following actions...
}
REMEMBER The equality operator (==) checks if two values are equal,
while the assignment operator (=) is used to assign values to variables.
And this check
is done for each character
of the string stored in the chosenWord
variable. If a match is found, the following
three lines of code get executed:
_root.guessWord_txt.text = displayedText.substr(0, j)+clickedLetter+displayedText.substr((j+1));
matchFound = true;
this._visible = false;
The left side
of the first line clearly tells you that you are commanding Flash to display
some text in the guessWord_txt
text field. And what will be
displayed? The found letter
(if the player guessed correctly), along with the all the other hidden letters, that are represented
by dots (or question marks, if you decided so), that have yet to be guessed:
displayedText.substr(0, j)+clickedLetter+displayedText.substr((j+1));
On the
previous page, you have set the value of the displayedText
variable to dots only
— the number of which equals the number of the letters inside the hidden word.
Suppose the hidden word that has to be guessed is "penguin"
. This word is composed
of 7 letters, so in this case the value of displayedText
variable would be "......."
. Also, suppose that
the player has clicked on the letter g
.
The loop would
begin, making 3 iterations without finding a match. On the fourth iteration,
the match would be found, because the letter g is on the position number 3
inside the word "penguin" (remember, the characters in a string are
numbered beginning from zero, that's why the fourth position in a string equals number 3). The if
condition would evaluate as true,
and the code inside it would execute, and Flash would interpret like this:
displayedText.substr(0, j) + clickedLetter
+ displayedText.substr((j+1))
".......".substr(0, 3) + "g" +
"......." .substr((3+1))
"..." + "g" + "..."
"...g..."
And that's
what would the user see appear in the text field. Let me explain you this
string manipulation in more detail. The substr
(
)
method of the String object does this: it extracts a substring from a string
(i.e. a part of text), based on the
starting position and length that you provided. The easiest way
to understand this is by seeing an actual example.
Let's say that
the word you are tinkering with is "computer", and that you wanted to
extract the first three letters from it. You would do it like this:
var myText:String = "computer";
var myChunk:String = myText.substr(0, 3);
The value of
the myChunk
variable would be "com"
, which are indeed the
first three characters inside the myText
string. So, the first parameter between the parenthesis is the starting
place inside the string, where the extraction will begin. The second parameter is the length of the string that you want to
extract, including the first character.
Here is a nice visual representation of that:
If you wanted
to extract the text "mput"
, you would write substr
(
2, 4)
, because the letter m
is situated at position 2 and the
length of the string that you want to extract is 4. Allright!!!
:-)
In the actual
mechanism that writes the guessed letter along with the dots, you use this
simple but very useful method to extract the first part of the word
(represented by dots), before the guessed character:
displayedText.substr(0, j)
...after which
you add the guessed character:
displayedText.substr(0, j) + clickedLetter
...and then
you add the remaining part of the word, represented by dots, because those
letters haven't been guessed yet:
displayedText.substr(0, j) + clickedLetter
+ displayedText.substr((j+1))
You have
certainly noticed that the substr
(
)
method is used differently in this last
part. There is no second parameter
here: displayedText.substr
(
(j+1))
. The first one is the
point where the extraction will start. And since the second one (length) is
omitted, Flash will automatically pick all
the characters that are found after the starting point. The
starting point is exactly the character after
the guessed one: j+1
. In this way, the rest of the word is extracted.
Finally (whew!
:-)), the lines that get executed after this string manipulation is over are:
matchFound = true;
this._visible = false;
The variable matchFound
is set to true so that you can later tell Flash
not to advance the
hangman animation, because the player has actually guessed a letter. And the
line this._visible
= false
hides the clicked letter. You must do
this, whether the user has guessed the letter or not. You can't be cruel and
make the player commit the same mistake twice, possibly. All the letters that
are clicked must be eliminated, leaving only the ones that haven't been tried
by the player.
And after the if
conditional statement, no matter if a
matching letter was found or not, the displayedText
variable has to be
updated:
displayedText = _root.guessWord_txt.text;
It will now
reflect the current state
of the guessWord_txt
text field, with both
the hidden and revealed letters. This is done so that a proper check can be
made, to see if the whole word was
guessed by the player. And that's precisely what comes next:
if (displayedText
== chosenWord) {
endOfGame(true);
}
This
simple if
statement checks to
see if the string inside the displayedText
variable matches the
one stored in the chosenWord
variable. If it does, the endOfGame
(
)
function is called, with a Boolean true
parameter passed to it, signaling that the player has won the game. That
function comes later in the code, so I will not explain it now.
Advancing the
animation of the hangman if a wrong guess was made
And what if
the player clicked a letter that isn't found in the hidden word? Then the matchFound
variable stays false. And the following code will be
executed (you already entered it, as a part of the movie clip's onRelease
event, remember):
if (matchFound ==
false) {
this._visible = false;
_root.hangman_mc.nextFrame();
if (hangman_mc._currentframe ==
10) {
endOfGame(false);
}
}
As is clear
from the first line, this is an if
statement that checks if the matchFound
variable equals false. If it doesn't, it gets
completely ignored, along with all the code placed inside it. But since I am
explaining here what happens when the player clicked the wrong letter, I will
tell you what happens when matchFound
really does equal false
.
The first line
of code that is run is the one that hides the clicked letter movie clip:
this._visible = false;
Remember, the
letter the player has clicked has to be hidden, whether it was a good or a bad
guess. And now you have to show the
player that she or he made a mistake: the hangman must begin to
appear. This is done by advancing the
animation inside the hangman_mc
movie clip by one
frame:
_root.hangman_mc.nextFrame();
And you also
have to make Flash check if the
animation arrived at the end, in the case the player has made
all the mistakes she could and the game
is over:
if (hangman_mc._currentframe
== 10) {
endOfGame(false);
}
If the current
frame of the hangman_mc
movie clip is the tenth frame (hangman_mc._currentframe
== 10
), the endOfGame
()
function will be
called, but this time with the parameter passed to it set to false, signaling that the game is over and that the player
didn't succeed in guessing the hidden word.
I have made
this game to end after ten wrong guesses, but of course, you can give more
chances to the player if you wish so. Just remember that your hangman animation has to have the same number of
frames as there are wrong guesses that a player can make. The
animation must be more complex, too: you must add more elements that will
appear as a wrong guess is made: the eyes, nose and mouth appearing for each
bad guess, or maybe fingers on a hand. Simply decide what looks best for your
game.
Scripting the
results that will be displayed at the end of the game
61. Add this code to the
one already inserted:
function endOfGame(success:Boolean) {
allLetters_mc.removeMovieClip();
startScreen_mc._visible = true;
if (success) {
startScreen_mc.message_txt.text = "Congratulations! You did it! Want to try again? Press
the play button below.";
} else {
startScreen_mc.message_txt.text = "GAME OVER! Aaargh! You killed
the little guy! Want to try again? Press the play button below.";
}
playAgain = true;
}
The function endOfGame
(
)
governs what will be displayed on the screen that will appear at the end of a
game, whether the player succeeded in guessing the word or not.
This function has a parameter passed to it, which is a Boolean value — it can
either be true or false.
The first two
lines of code that are being executed upon function's execution do so no matter
if the parameter turned out as true or false:
allLetters_mc.removeMovieClip();
startScreen_mc._visible = true;
The first one removes all the letter buttons. These
buttons are the movie clips that were attached dynamically from the Library
inside the allLetters_mc
movie clip. So by removing this movie clip
with the removeMovieClip
(
)
method you are effectively removing all
the buttons with it.
The second
line makes the startScreen_mc
movie clip appear by setting its _visible
property to true
. This movie clip contains the text
field that displays the welcome message at the start of a game and the resulting
message at the end of a game. Also, the "Play!" button is situated
inside it.
And now comes the if
conditional statement which decides what will be shown as the message,
depending on player's success in guessing the hidden word:
if (success) {
startScreen_mc.message_txt.text = "Congratulations! You did it! Want to try again? Press
the play button below.";
} else {
startScreen_mc.message_txt.text = "GAME OVER! Aaargh! You killed
the little guy! Want to try again? Press the play button below.";
}
The construct if(
success)
has the same exact functionality as if you
had written if(success
== true)
. The former one is a shorthand version. Why write more code if
you can make it more compact? So, if the player guessed the word correctly (success
), the following ActionScript code will be executed:
startScreen_mc.message_txt.text = "Congratulations! You did it!
Want to try again? Press the play button below.";
It is a simple
command that tells Flash what to display in the message_txt
text field (placed
inside the startScreen_mc
movie clip). Just remember that the message
must be included between the quotation marks.
On the other
hand, if the player failed to guess the hidden word picked at random, the if
part of the conditional will be ignored, and the else
portion will be
executed:
startScreen_mc.message_txt.text = "GAME OVER! Aaargh!
You killed the little guy! Want to try again? Press the play button below.";
Again, the
same text field is referenced, but with a different message.
The endOfGame
(
)
function contains one more bit of code
that will be executed always, because it is outside the if conditional
construct:
playAgain = true;
The variable playAgain
is set to true
(remember, it is defined as false
at the very start of
the code), indicating to Flash that the player isn't playing for the first
time. Thanks to this, if the player begins a new game, Flash will erase the
text that stayed in the main text field from the previous game. I explained
that bit before, when showing you the inner workings of the the
randomize(
)
function. The code that resets the text
field to its initial state is shown in bold:
function
randomize(playAgain):Void {
var randomNumber:Number = random(words.length);
chosenWord = words[randomNumber];
if (playAgain)
{
guessWord_txt.text = "";
}
for (var i:Number
= 0; i<chosenWord.length;
i++) {
guessWord_txt.text = guessWord_txt.text+".";
}
displayedText = _root.guessWord_txt.text;
}
Creating the
code that powers the Play! button
62. At last, add the final chunk of ActionScript
code:
startScreen_mc.play_mc.onRelease = function() {
this._parent._visible = false;
guessWord_txt._visible = true;
hangman_mc.gotoAndStop(1);
randomize(playAgain);
placeLetters();
};
This is the
Play! button's onRelease
event handler function. It tells Flash what
to do when the player has clicked the button, as for the first time when the
game is played, as well as for all the subsequent rounds. The five lines of
code included do the following:
The first one hides the startScreen_mc
movie clip:
this._parent._visible = false;
The construct this._parent
points to the startScreen_mc
movie clip. Since it
is placed inside the play_mc
movie clip's onRelease
event, the keyword this
points to the play_mc
movie clip itself. And the keyword _parent
denotes its parent
movie clip (the one which hosts it) — startScreen_mc
.
The main text
field is made visible again:
guessWord_txt._visible = true;
And the hangman_mc
movie clip is sent back to the first frame, which
is empty:
hangman_mc.gotoAndStop(1);
You must do
this, because at the start of a new
game, no part of the hanging animation can be visible — no
potential wrong guesses have been made yet.
A new
word is picked at random, by calling the randomize(
)
function:
randomize(playAgain);
This is done
so that the game can start with a new word.
NOTE Although a new word will be picked at random each time the
hangman game is started, chances are that the same word could appear. This is
not because of Flash, but because of the law of probability. So, the more words
you insert in your XML file, the lesser the chance of the same word appearing
again. ActionScript code could be written for
creating a mechanism that would eliminate a word that has already been guessed,
but I will leave that for some other occasion :).
And as the
last action, the placeLetters
(
)
function is called, to create the allLetters_mc
movie clip anew and attach all the letter buttons dynamically again:
placeLetters();
Conclusion
The first fact
that I want to tell you is that this hangman game (the final SWF file) has a size of only 3 KB! That's pretty
cool! Both the XML and TXT files are so small in size that the whole game loads
almost instantly.
You saw how ActionScript helps to streamline tasks that would require
too much time to create manually, like the creation of all the alphabet
letters' buttons. Also, like I said before, this Flash game is completely
dynamic because once the SWF is finalized, all you
have to do to modify the game is change the data in the XML and TXT files.
As for the
animation of the hanging, you can make it more complex, even add sound — this
is just a question of much time and effort you are willing to put into it.
Pay attention
to one important detail:
this game supports only one-word guesses. You cannot insert two words inside
any of the XML elements (for example: <word>two words</word>),
because the code in this lesson isn't
created to handle non-breaking spaces. However, you have
learned a lot and I am sure that you will figure this out by yourself, if you
wish to insert this capability into your hangman game.