Suppose that we have these requirements for the quiz application:
Be able to display a set of multiple choice quiz questions.
Each question can have 4 answers to choose from. User
can click one of the answers to select it. A message will be
displayed after each click, showing whether the selection is correct
or not.
A summary screen will be displayed at the end showing the
percentage of the questions answered correctly.
The Flash movie must be able to read the quiz data from a
file.
The quiz data should be easily changed by an average user without
rebuilding the Flash movie.
Because of requirement 3 and 4, we will need a way to use one of
Flash read file mechanism. There are several to chose from, such
as using getURL(), using XMLSocket, or loadVariables().
In this
example, I will be utilizing the XML
object for two reasons:
The structured organization of an XML file is better than the messy format
of using text file (see
here).
An XML file can be easily edited using a text editor.
XML is a mature standard, and you could potentially use the XML
file for other purposes (such as displaying on a web page; or format
the data to make a printout of the quiz).
To see how this might be done with a plain text file, see
here.
Warning: This tutorial and the application
described here is mainly for informational and entertainment
purpose. The application should not be used for
serious data collection or any other purpose which requires
critical and accurate scoring. The application does not
attempt to create a secure environment; and someone can easily
hack the application - including cracking the answers. To illustrate the risk,
consider this:
If you're running IE browser or later, you can type the
URLbelow into the browser and see the answer for all the items on the quiz: http://www.permadi.com/tutorial/flashMXQuiz/quiz.xml
CREATING THE XML TEMPLATE
XML on itself is a rather complicated subject and I won't go into
details. There are certainly many books that covers this subject,
from beginner to advanced. For example:
this
or
this
(note: the link goes to a product page at at Amazon)
If you have done some html, you might see some resemblances
between the two. Furthermore, once
you see the sample XML file used on this tutorial, it will be
quite obvious on how this particular XML data is structured. I will also explain
how to modify the data.
Here's the XML file used on this tutorial: quiz.xml
(right click and select Save As to download it).
This
file can be opened using a text editor to edit and view. You can
also find some links to XML editors on the Related
Products page.
(Note:
XML file is a plain-text file. If you
are using
Wordpad or MSWord, you must save the file as a plain text file.) A
portion of the file is shown below (I only show 3 questions here, the
file has about 11 questions):
<?xml version="1.0"?>
<!DOCTYPE quiz [
<!ELEMENT quiz (title, items)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT items (item)+>
<!ELEMENT item (question, answer, answer+)>
<!ELEMENT question (#PCDATA)>
<!ELEMENT answer (#PCDATA)>
<!ATTLIST answer correct (y) #IMPLIED>
]>
<quiz>
<title>The Quiz</title>
<items>
<item>
<question>In which continent is the country Japan located?</question>
<answer correct="y">Asia</answer>
<answer>Europe</answer>
<answer>Africa</answer>
<answer>America</answer>
</item>
<item>
<question>Which one cannot swim?</question>
<answer>Tuna</answer>
<answer correct="y">Cow</answer>
<answer>Whale</answer>
<answer>Lobster</answer>
</item>
<item>
<question>How many points are on a hexagon?</question>
<answer>5</answer>
<answer correct="y">6</answer>
<answer>7</answer>
<answer>8</answer>
</item>
</items>
</quiz>
The root element is called <quiz>
A <quiz>
has a <title> and a set of <items>.
<items> - plural - contains one or more <item>
- singular.
An <item> consists of 1 <question> and 2
or more <answer>s.
<question> must come before <answer>s.
The correct answer is indicated by this attribute: correct="y".
Below is an example of an <item>. (It starts with <item>
tag and
ends with </item> tag.)
<item>
<question>A new question here.</question>
<answer>An answer choice here.</answer>
<answer>Another answer choice here also.</answer>
<answer>Yet another answer choice here.</answer>
<answer correct="y">This is the correct answer.</answer>
</item>
To add questions, just add/copy/replace an
<item> element and
change the content. You can then change the question and the answers. The correct
answer should have the attribute: correct="y". For
example, above, the 4th answer is the correct answer. There
should be only one correct answer per <item>.
You might want to make sure that the questions (and the answers) are not too long, or
they might not fit the Flash movie. For now, you must put 4 answers per
question. Later, we will see how this can be changed.
You might not use the & or < within the
question or answers. If
you need to use an &, type & (note the "&"
at the beginning and the ";" at the end and no
space). If you need to use <, type < instead.
<item>
<question>Which number is < than 3?</question>
<answer correct="y">1 & 2.</answer>
<answer>5.</answer>
<answer>8.</answer>
<answer>777.</answer>
</item>
In that example above, the question will be displayed as: "Which
number is < than 3?" but it must be written that way.
Similarly, the first answer will be displayed as: "1 & 2"
by the XML processor. Additionally, it's recommended to use the
special notation for these symbols (these are also known as Name
Entities) :
Symbol
Name Entities
>
>
"
"
'
'
&
&
<
<
You can also change the <title> element with any title you want
to use. For example, below, I added a new question at the end;
replaced the 2nd question, and changed the title.
<?xml version="1.0"?>
<!DOCTYPE quiz [
<!ELEMENT quiz (title, items)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT items (item)+>
<!ELEMENT item (question, answer, answer+)>
<!ELEMENT question (#PCDATA)>
<!ELEMENT answer (#PCDATA)>
<!ATTLIST answer correct (y) #IMPLIED>
]>
<quiz>
<title>Sample Quiz (2/20/2002)</title>
<items>
<item>
<question>In which continent is the country Japan located?</question>
<answer correct="y">Asia</answer>
<answer>Europe</answer>
<answer>Africa</answer>
<answer>America</answer>
</item>
<item>
<question>Which one can fly?</question>
<answer correct="y">A pigeon</answer>
<answer>A rabbit</answer>
<answer>A pig</answer>
<answer>A lobster</answer>
</item>
<item>
<question>How many points are on a hexagon?</question>
<answer>5</answer>
<answer correct="y">6</answer>
<answer>7</answer>
<answer>8</answer>
</item>
<item>
<question>Which number is the largest?</question>
<answer>2</answer>
<answer>20</answer>
<answer>200</answer>
<answer correct="y">2000</answer>
</item>
</items>
</quiz>
CREATING THE FLASH MOVIE
Open a new Flash movie and create the following layers configuration:
Put a
frame label called: "LoadData" on the frame 1 of Labels
layer. Then, put an image or something on the frame 1 of Bgr layer.
This will be the preloader screen.
LOADING THE QUIZ DATA For this example, the quiz data file is
called "quiz.xml," which you have seen
above. We will need to have Flash
open the file and read the data. Here's the code that reads
the file. This code needs to be put on the Actions layer, frame
1.
function QuizItem(question)
{
this.question=question;
this.answers=new Array();
// reset statistic
this.numOfAnswers=0;
this.correctAnswer=0;
// this function returns the question of this item
this.getQuestion=function()
{
return this.question;
}
// add answer to multiple choice items
this.addAnswer=function(answer, isCorrectAnswer)
{
this.answers[this.numOfAnswers]=answer;
if (isCorrectAnswer)
this.correctAnswer=this.numOfAnswers;
this.numOfAnswers++;
}
// this function returns the n-th answer
this.getAnswer=function(answerNumberToGet)
{
return this.answers[answerNumberToGet];
}
// this function returns the index of the correct answer
this.getCorrectAnswerNumber=function()
{
return this.correctAnswer;
}
// this function checks if the passed number is the
// correct answer index
this.checkAnswerNumber=function(userAnswerNumber)
{
if (userAnswerNumber==this.getCorrectAnswerNumber())
gotoAndPlay("Correct");
else
gotoAndPlay("Wrong");
}
}
// this function parses the XML data into our data structure
function onQuizData(success)
{
var quizNode=this.firstChild;
var quizTitleNode=quizNode.firstChild;
title=quizTitleNode.firstChild.nodeValue;
var i=0;
// <items> follows <title>
var itemsNode=quizNode.childNodes[1];
// go through every item and convert it into our data structure
while (itemsNode.childNodes[i])
{
var itemNode=itemsNode.childNodes[i];
// <item> consists of <question> and one or
// more <answer>.
// <question> always comes before <answer>s
// (Ie: <question> is the node 0 of <item>)
var questionNode=itemNode.childNodes[0];
quizItems[i]=new
QuizItem(questionNode.firstChild.nodeValue);
var a=1;
// Go through every answer and add them
// to our data structure.
// <answer> follows <question>
var answerNode=itemNode.childNodes[a++];
while (answerNode)
{
var isCorrectAnswer=false;
if (answerNode.attributes.correct=="y")
isCorrectAnswer=true;
quizItems[i].addAnswer(
answerNode.firstChild.nodeValue,
isCorrectAnswer);
// goto the next <answer>
answerNode=itemNode.childNodes[a++];
}
i++;
}
// We're done decoding, now we can start
gotoAndStop("Start");
}
var myData=new XML();
myData.ignoreWhite=true;
myData.onLoad=onQuizData;
myData.load("quiz.xml");
stop(); // I'm telling Flash not to continue until the XML is loaded.
The red section of code above opens the XML file and creates an XML
object. Flash will notify us when the file is completely loaded by
calling a function called "onLoad". At that
time, we still need to parse the file or the data will not be
usable. We override the onLoad function with onQuizData.
This means that when the file is loaded, the onQuizData
function will be called. The stop() action at the ends
tells Flash to stop running because I do not want to continue until the
XML file is loaded. So when does the code continues?
This will happen when the XML data is "completely"
loaded.
So, let's assume that the data is loaded. We're now entering
the onQuizData() function. onQuizData() parses the
data and creates a set of objects called quizItems.
After that, the line gotoAndStop("Start")
will signal us that the XML file has been parsed.
DATA STRUCTURE FOR THE QUIZ OBJECT If you're
not into programming, you might want to skip to CREATING THE QUIZ SCREEN
below.
Let's go back and examine the structure of the XML file above
again. An <item> contains 1 question, and 4 answers;
one of the 4 answers will be correct. It will be nice if we can reproduce the structure in the
Flash application. And that's what quizItems are.
Here are the properties of a quizItem.
Notice several things:
question contains the question for
the current item. This represents the <question> element
from the XML.
answers is an array that contains the
set of answers. This represent the <answer>s
element from the XML file.
correctAnswer is the index of the
correct answer. The index starts at 0, so 0 in the above
example means answers[0] ="Asia"
is the correct answer. The index represent the element with <answer correct="y"> in the XML.
in addition, there are several functions
that can be called by a quizItem:
addAnswer(answer): called by
onQuizData to add answer as the XML data is being parsed.
checkAnswerNumber(userAnswerNumber):
used when user clicks an answer. You will see more of this
later.
getAnswer(index): returns answers[index];
Since there are 11 questions in quiz.xml, there will be 11 quizItems.
Each one can be accessed like this: quizItems[index], where index
is the question index (starting at 0). Here' you can see the
quizItem[0] being shown again. You can compare it to the first <quiz>
item in the XML file example, and see that they match.
<item>
<question>In which continent is the country Japan located?</question>
<answer correct="y">Asia</answer>
<answer>Europe</answer>
<answer>Africa</answer>
<answer>America</answer>
</item>
CREATING THE QUIZ SCREEN
Extends the timelines for all the layers to about 50 frames. Then,
create a key frame on the Label
layer at around frame 10. Put a frame label: "Start."
On the Bgr layer, make another key frame at the same frame (at
the frame labelled "Start").
Here, put a background image to be used when the quiz is running.
For example, I have this gray background, and I added the letter A, B,
C, D on top of the background (you should try not to include the A, B,
C, D in the background image itself):
Make sure that there is enough space to put 2 or 3 lines of text for
the question and answers. Also, each answer choice should at least be able to
accommodate long answers (spanning two lines).
On the same frame of the QA Box layer, create 5 textboxes for
the question and answers like below (the blue boxes are
textboxes): These textboxes will contain the questions
and answers when the application is running.
To be able to change the text during runtime, we must make sure that
the textboxes are of type: "Dynamic Text." Also,
since a the text might not fit on a single line, make sure to select the
"Multiline" option (see below). You might also
want to make the text left justified. Also, select a common
font such, otherwise some users might not have the font.
We need to associate the textbox with a variable name so that the
textbox will display the text that we want. For the Question
placeholder textbox, I decided that I want the textbox to display a
variable which I will call "question." so in Var:
box, put "question" like below:
Make sure that this button
is off so that user can't select (highlight) the text. It will
look weird if you allow user to select the text. For the answer boxes, the settings are similar, except "Var:
answer1" (see below).
Do the same thing for the remaining 3 answer boxes. Name then answer2,
answer3, and answer4.
SHOWING THE QUIZ DATA ON THE QUIZ SCREEN
Now that we have the quiz screen laid out,
let's put the questions into the screen.
Put this piece of code in the frame labeled "Start"
frame of the "Actions" layer.
var currentQuestionNumber=1;
var numOfQuestionsAnsweredCorrectly=0;
var numOfQuestionsAnsweredIncorrectly=0;
gotoAndStop("ShowQuiz");
The currentQuizItems variable holds the currentQuizItem.
In the beginning, we set currentQuestionNumber to 1, indicating
that we want to show the first quiz item. Then we set 2 variables
indicateing how many quations has been answered incorrectly and
incorrectly (we'll use those to calculate the final score). The next line tells
Flash to go to another frame which is labeled "ShowQuiz."
We will be creating that frame now.
Then, on the Labels layer, at about frame 20, create a key
frame named: ShowQuiz. At this time, we need to extract the content of
current quiz from the quizItems
array that we created on the LoadData frame. Put this piece of code in the frame labeled "Start"
frame of the "Actions" layer.
var currentQuizItem=quizItems[currentQuestionNumber-1];
var hasAnswered=false;
question=currentQuizItem.getQuestion();
for (var i=1; i<=4; i++)
{
_root["answer"+i]=currentQuizItem.getAnswer(i-1);
}
stop();
The first line of the code assigns a variable currentQuizItem to the value of the current quiz item so that it's easy to refer to it
in the future. We can access the quiz items using quizItems[index].
Since we have 10 quiz items, we have quizItems[0], quizItems[1], and so
on, up to quizItems[9]. In the beginning, we want to start with
the first quiz item, so we get the first quiz item by quizItems[currentQuestionNumber-1]
(we set currentQuestionNumber to 1 on the previous section).
The line:
question=currentQuizItem.getQuestion();
extracts the <question> portion of the quiz and puts it to the variable question. The code
then loops through the answers and assigns the answers to variables answer1,
answer2, answer3, and answer4. Since we have named
our textboxes with the same name as those variables (see CREATING THE
QUIZ SCREEN above), when this piece of code is run, the textboxes will
display the value of the variables, which is exactly what we wanted.
Test the movie. It should display the first quiz item like
below:
Play around There is no interactivity at this point. We still have to add
the code for allowing the user to click the answer, and for checking the
answer. Make sure this part runs before continuing.
Download FLA (this FLA contains the progress up to this section,
continue to the next pages for subsequent versions)
Download XML (right click and do "Save As")
Try changing the first question on the XML file and see the changes
being shown in the movie.
Note: This tutorial requires Flash 6/MX
plug-in/player to be installed to run properly. Although XML is supported from Flash 5;
there's a problem on some older Flash
5 player
that causes a movie not to be able to read some XML files correctly. This
problem occurred in Flash player version 5.0.41 and was fixed on
version 5.0.42. If
the example above does not run on your machine, you should
download the latest flash player from Macromedia. If you
need to support Flash 5 players, then see this document
for some workarounds.