Create a Quiz Application Using AS3 Classes

Download Source Files
http://theflashconnection.com/book/export/html/23

1. The Initial Concept
This article will demonstrate how to build a simple Flash quiz application using Classes. Each step, from concept to finished product, will be explained in detail. The finished application will run the user through a series of multiple choice questions. It will provide forward and back buttons to navigate to the previous or next question. When all of the questions have been answered, the application will compute the user's score. To begin, here's a description of the concept. The application will consist of a fla file, a Document Class called QuizApp, and another class called QuizQuestion. And that's it! Two classes and a fla file! Each file will have it's own responsibilities, which we will define up front: Quiz.fla: The fla file is not going to be responsible for very much at all. It will contain no code, and will serve simply as a container for the Document Class, and also its library will contain the components we will need. Since it's a multiple choice quiz, the RadioButton component will make an excellent choice for displaying the possible answers to each question. Also, rather than making customized buttons, we'll just use instances of the Button component. QuizApp.as, which we will make the Document Class of the fla file, will be responsible for posing the questions one at a time, by creating instances of QuizQuestion (and storing them in an Array). It will also create and position the previous, next, and finish buttons, and keep track of the current question. At the end it will compute and display the score. There will only be one instance of QuizApp. It will be the main application and perform most of the work. QuizQuestion.as, of which there will be many instances, conceptually will represent one question and series of possible answers. Each instance of QuizQuestion will store the question as a string, the multiple possible answers as an array of strings, the correct answer to each question as an integer, and the answer the user supplied as an integer. I'll show you how to build the QuizQuestion class, and how to make instances of it store all this information. I hope you'll follow along and actually build this application. Or at least read the article and build the application using copy and paste. If you do, you'll learn many new things about classes and using objects made from those classes. The application is fairly simple (on purpose), but I think it does a good job of illustrating many important concepts. As always, I hope the result will be that you are inspired to take this knowledge and use it to build applications of your own. In these tutorials, I always strive to make sure that the end result is the creation of something that's actually useful. This Quiz application will be functional, but it's really just a starting point,

as it (admittedly) could really use quite a bit more polish. Mostly, it's a teaching tool to further demonstrate classes and objects, and how they might be used to build a simple application. The idea is that even if you don't care to build a Quiz application, you can still use the concepts presented here as a springboard for an idea of your own. Here's the application that we'll build:

2. Create the files and the file structure
The first step is to create the files and save them to a folder. Since it's probably unlikely that you'll ever want to use the QuizQuestion or QuizApp classes again in any other application, we won't worry about saving them into packages. We'll just save everything into the same folder. Open flash, and create a new Actionscript file. We're going to first create QuizApp.as, which will be our Document Class. So type these lines into the script pane:
package { import flash.display.Sprite; public class QuizApp extends Sprite { public function QuizApp() { trace("this is the document class"); } } }

Go to File, Save. You can use this dialog box to also create your folder. I'll assume that you know how to browse your system to get to the place where you keep your flash files. Create a new folder there to save this file into (I named my folder "Quiz"), then save it there as QuizApp.as. Notice that every class file must include the package keyword. In this case, we're not saving into a package, so the package keyword appears without anything following it. This is called using the unnamed package. Our class files will still be able to find each other without importing, because we're saving them all into the same folder. Flash's classpath always includes a reference to the current folder. Any class file that you want to use as a Document Class must extend either MovieClip or Sprite. The difference is whether you intend to use the main timeline or not. If so, use MovieClip, and if not, use Sprite. In this case, we will just choose to extend Sprite, because everything we create will be generated with Actionscript. We won't be physically placing any objects on the timeline at authoring time. Next, create a new flash file. Immediately save it to the same folder where you saved QuizApp.as. I named mine "Quiz.fla." We're not done working with this file yet, but we need to save it right away, so that when we designate the Document Class, flash will find our QuizApp class file. So make sure you save the file before proceeding.

You should get this message in the output window: "this is the document class. Look for the field labelled "Document Class. Type the following code into the script pane: package { import flash. QuizQuestion: Go to File. You shouldn't get any dialog box warning you that the class file couldn't be found. Components. something is wrong. you'd see it appear. but not unless their master templates are also in our library. It's being automatically instantiated when the fla is compiled. or just press CTRL-F7).as file extension): Press the Enter key. But if it did." and type "QuizApp" into that field (minus the quotes. It should say "Document" in the upper left corner of the Properties Panel. It's also being added to the stage with an automatic "addChild" command that happens behind the scenes. You would have gotten such a warning if you had not already saved this fla file somewhere. There's a little more we have to do with our fla file before we leave it. and create a new Actionscript file. drag the RadioButton component out to the stage. go to Window. so that the Properties Panel gives you the properties of the Document. as they contain all the graphics. Now the fla file is done. If you do get the warning dialog. and again press the Delete key. Let's create the other class file. Also make sure that all spelling and capitalization is correct everywhere. Next.Sprite. and make sure you don't include the . as flash is case sensitive. Drag the Button component out to the stage area. The idea here is that we can create instances of these components with Actionscript code. This isn't apparent at the moment.display. and you should check to make sure you really saved both files to the same folder. anything we add to this Document Class with addChild will also appear on the stage of our movie. of course. Press CTRL-Enter to test the movie. because it doesn't contain any graphical content yet.Next. then press the Delete key. So." This means our Document Class is working. here's how to designate the Document Class: Click somewhere on or around the stage. All of our coding is going to be done inside the two class files. New. Go to the Components panel (if it's not around anywhere. public class QuizQuestion extends Sprite { public function QuizQuestion() { . This has the effect of adding these items to your fla file's library.

an integer variable to store the correct answer to the question. private var questionField:TextField.text.TextField. here's the file as we last saved it: package { import flash. Our Document Class is working. and they all reside in the same folder. a TextField property that will be used to display the question. public function QuizQuestion() { . 3.as. There just happens to be a TextFieldAutoSize class that contains the auto sizing constants we need.} } } Save the file as QuizQuestion.Sprite. you'll start to realize when you've added something that requires another import statement. all three files have been created and saved to the same folder. Also. so we'll import that too: package { import flash. plus several others. Once again. Now all the files are created.Sprite. and we can now proceed to flesh out our class files some more.TextFieldAutoSize. You should also have all three files open in Flash. import flash. on separate tabs. Instances of QuizQuestion will have a TextField to display the question. The QuizQuestion Class At this point. a String that will store the text of the question. Next. public class QuizQuestion extends Sprite { private var question:String. In case you haven't tried my earlier tutorials. I pointed out in those that whenever you add to your class files. This is solved for us by setting the TextField's autoSize property. so the Sprite class has to be imported. import flash.display. Let's work on QuizQuestion. in the same folder where you've saved the other two files. public class QuizQuestion extends Sprite { public function QuizQuestion() { } } } This file extends the Sprite class.as first: QuizQuestion will need to have many properties. another integer variable to store the user's answer to the question.display. RadioButtons that lay out the possible answers.text. we won't know how wide to make the TextField to accomodate the length of the question. since we don't know the length of the question in advance. Let's add a "question" property.

actually.} } } Next.Sprite. package { import flash. and anything you might want to do with this parameter list had better be done in the constructor." I've also gone ahead and created some private variables to store the values that are passed in to the parameter list.. } } } . and also somehow store what we know to be the correct answer. For this reason. and using the . . Without doing this." In our case. All of this information will come into this class in the constructor's parameter list. if you use . four possible answers. we're making a multiple choice quiz. so that they can be stored for future reference.display. Within reason. we need to make provision for somehow getting the required infomation into our class... private var choices:Array. and the array's name is whatever name you supply in place of the word "rest.rest. theCorrectAnswer = theAnswer. you need to make sure it's the last parameter in the list.. We'll use the name "answers" in place of the word "rest. because we want them to all fit on the screen without the need for scrolling. five--or however many we want. it's a parameter that can store any number of arguments in itself. import flash.TextField.. display the list of possible answers. public class QuizQuestion extends Sprite { private var question:String. private var theCorrectAnswer:int. choices = answers. Basically..text. because it's a catch-all for all the arguments that are too numerous for the parameter list. and you may have heard of it and wondered how it works. we can make multiple choice questions that can have three possible answers. We're going to need to display a question.TextFieldAutoSize. It saves all the extra arguments as an array. import flash. because their values are lost after the constructor function ends.rest parameter as the last parameter will allow us flexibility in the number of possible choices that can be supplied with each question. the constructor would run. public function QuizQuestion(theQuestion:String. private var questionField:TextField. In other words. of course. theAnswer:int. I'm now going to tell you about a new feature in AS3.. It's called the .answers) { //store the supplied arguments in the private variables: question = theQuestion.text..rest parameter.

private var theCorrectAnswer:int.Sprite. spacing:int = 25.TextField. All the arguments from the third one on will be caught and stored in the .. theAnswer:int. These variables are named questionX.text. this will give one handy place to do it. theCorrectAnswer = theAnswer. and spacing. public class QuizQuestion extends Sprite { private var question:String. addChild(questionField).x = questionX. } . consider that it would be nice to have some positioning variables at the top of the code.. public function QuizQuestion(theQuestion:String. then given some positioning values. questionField. which is really an array.answers parameter." "questionField" is instantiated as a new TextField. With all these additions. . questionField. answerY. There would be variables for the x and the y of the question. answerY:int = 55. At this point. here's the code so far: package { import flash. The next thing is to create the TextField and position it. //create and position the textfield (question): questionField = new TextField(). questionY..y = questionY. and finally. Inside the constructor. There are a few more things remaining to accomplish in the constructor.Anyway. choices = answers. the value of each parameter is assigned to a class member (variable).text. Of course.. import flash. questionField. all of them integers.answers one. what will be supplied to the parameter list is first the question. answerX:int = 60.text = question. there's nothing wrong with temporarily physically laying out some things on flash's stage (in the fla file) to help you come up with these numbers.autoSize = TextFieldAutoSize. If it ever becomes necessary to change the layout. then the correct answer. including the . answerX. questionField. any number of possible multiple choice answers.display. I've called the TextField that holds the question "questionField. private var questionField:TextField. variables for the x and y of the first answer. import flash.LEFT. //variables private var private var private var private var private var for positioning: questionX:int = 25. and one other variable representing how far apart to vertically space the answers. private var choices:Array. in the variable list.answers) { //store the supplied arguments in the private variables: question = theQuestion.. questionY:int = 25.TextFieldAutoSize..

Note the three additions to the import block. questionField. Also..} } The next thing to accomplish.Event. still in the constructor. private var choices:Array. for(var i:int = 0. so that each radio button can be assigned to the same group. questionY:int = 25.group = myGroup.text = question. spacing:int = 25.RadioButtonGroup. i < choices. rb.label = choices[i].autoSize = TextFieldAutoSize. . is to create and position the radio buttons. This requires importing both the RadioButton class and the RadioButtonGroup class.CHANGE event.value = i + 1.y = answerY + (i * spacing). rb.events. theAnswer:int.TextFieldAutoSize.display. This is the Event.RadioButton.length.CHANGE.textField. public function QuizQuestion(theQuestion:String. choices = answers.controls. We'll be adding an event listener to the RadioButtonGroup instance.Sprite. answerX:int = 60. This requires importing the Event class. flash.addEventListener(Event. rb. questionField. and the additional code in the constructor: package { import import import import import import flash.text. myGroup. //create and position the radio buttons (answers): var myGroup:RadioButtonGroup = new RadioButtonGroup("group1"). //variables private var private var private var private var private var for positioning: questionX:int = 25. //create and position the textfield (question): questionField = new TextField(). answerY:int = 55. public class QuizQuestion extends Sprite { private var question:String.x = questionX. fl. rb.answers) { //store the supplied arguments in the private variables: question = theQuestion.LEFT. addChild(questionField). private var theCorrectAnswer:int. questionField.controls.autoSize = TextFieldAutoSize. rb. questionField. . flash. fl..TextField. changeHandler). rb.LEFT. there needs to be a RadioButtonGroup. flash.y = questionY. private var questionField:TextField.text.x = answerX. i++) { var rb:RadioButton = new RadioButton(). theCorrectAnswer = theAnswer.

target" will refer to the radio button group as a whole. each possible answer will have a value from 1 through 4. we can use choices[i] to set the label property of the radio button to the appropriate string of text. The important name is the variable name. in order to listen for the CHANGE event. Remember. Again. "myGroup. so at the top of the code. we create a new radio button. what we're constructing is a question and set of possible answers. .addChild(rb). So in a four answer multiple choice question. Since "choices" is an array of strings. } } } } The help files are really indispensible when you come to this point." so I just kept that.CHANGE event. respectively. until some external code does an addChild() of its own on the whole thing. Each radio button has its "value" property set to the loop counter plus one. Later on. First. Although there will be many of these instances made. and each time through the loop it refers to a new radio button. Next. Inside the changeHandler function." and that's the one we add the Event listener to. and experimenting. add the variable "theUserAnswer" to the variables list and give it an integer data type. when we write the class. the event listener for the radio button group will be triggered. QuizApp will do exactly that. we'll want to write the function "changeHandler." which will run whenever the user clicks on one of the radio buttons. Inside this function is where we want to set a private variable to the value of the button that was clicked on. in other words. Next. For each choice. and the radio button group's "selectedData" property will hold the "value" of the button that was clicked on. and our changeHandler function is called. You have to look up the RadioButton and RadioButtonGroup classes. When the user clicks on a radio button. we create a RadioButtonGroup instance. and its constructor requires that we pass it a string of text to use for its name property. at least temporarily. In the help files. We haven't created such a variable yet. "event. None of this stuff will show up on flash's stage. That's why we need only construct one radio button group. and this value property is what will be returned in the radio button group's "selectedData" property. This is just a temporary name. This is similar to what we did with the questionField textfield. and read up on whatever properties and methods of these classes you think you might need to use to accomplish your goal. it can be helpful to think of it in terms of just one instance. Flash broadcasts an Event. Each radio button is assigned to the same radio button group ("myGroup"). Each radio button has its textField property autoSized to the left. the example there uses the name "group1. The "rb" variable gets reused each time through the loop. This value will be important later on. yet. Each radio button is then positioned using the positioning variables created earlier (with a little help from the loop counter as a multiplier). When this happens. you don't find this stuff out without going through the help files quite a bit. but we must supply one nonetheless. though. and loop through the "choices" array. we set up a for loop. and then added to the display list for this Sprite using addChild(). it allows for expansion to the right. We won't be using this name.

} } private function changeHandler(event:Event) { .controls. choices = answers. flash. //create and position the textfield (question): questionField = new TextField().text = question. rb. myGroup. questionField.. private var choices:Array. public function QuizQuestion(theQuestion:String.RadioButton.RadioButtonGroup. //create and position the radio buttons (answers): var myGroup:RadioButtonGroup = new RadioButtonGroup("group1"). public class QuizQuestion extends Sprite { private var question:String. theCorrectAnswer = theAnswer. rb.The final thing to put in the code is a couple of getter functions.x = questionX.text.TextFieldAutoSize.autoSize = TextFieldAutoSize.events. answerX:int = 60.group = myGroup. //variables private var private var private var private var private var for positioning: questionX:int = 25. . Here's the final code for QuizQuestion.addEventListener(Event.textField.text.Event. changeHandler). answerY:int = 55.y = questionY. One of these will be used by external code to retrieve the correct answer to the question. spacing:int = 25. rb. i++) { var rb:RadioButton = new RadioButton().. flash.value = i + 1. private var theCorrectAnswer:int. questionField. fl. questionField. for(var i:int = 0. rb. with these two getter functions added at the end: package { import import import import import import flash. addChild(rb).controls. fl.LEFT.LEFT. flash.CHANGE.TextField. This will be important later on for calculating the score. rb. private var questionField:TextField.display. addChild(questionField). i < choices. questionField.y = answerY + (i * spacing).label = choices[i]. rb. questionY:int = 25.answers) { //store the supplied arguments in the private variables: question = theQuestion.Sprite. theAnswer:int.autoSize = TextFieldAutoSize. The other will retrieve the answer that the user supplied.length. private var theUserAnswer:int.x = answerX.

the correct answer is on the second line. You might not have realized that you're allowed to write code on multiple lines like this. let's test the QuizQuestion class. Before you run this.. "Lincoln"). and if a Sprite is your Document Class. When you're satisfied that it all worked out okay. eh? The QuizQuestion class is completely self-contained. you really need never visit the code again or worry about how it works internally. though. and storing the user's answer whenever one of the radio buttons is clicked on. "Grant". so that it corresponds. go ahead and close the running movie.selectedData. if you supply a correct answer of "3.theUserAnswer = event. complete with clickable radio buttons. 3.. Let's go to the fla file and write some code on the first frame to make an instance of QuizQuestion and display it. and the possible answers are on the lines following. You should get a nicely laid out arrangement of the question and possible answers.testing out QuizQuestion Before we turn our attention to the QuizApp class. Press CTRL-Enter to test the movie. } public function get userAnswer():int { return theUserAnswer. and is a good example of encapsulation. A short break. "Lee". you're not allowed to have any code on your timeline. Remove all of the frame code.target. a number representing the correct answer." you'll want to make sure that the answer you intend to be the correct one is the third one listed. Naturally. . "Washington". otherwise you'll get an error. temporarily take out the reference to the Document Class in the property inspector. The question is on the first line. and a list of possible answers. addChild(quizQuestion). } public function get correctAnswer():int { return theCorrectAnswer. Just give it a question. After you build it. This is because our Document Class extends Sprite. Writing it this way is not necessary. It takes care of all the other details of laying it all out on the screen. } } } 4. it's just that to me it makes it easier to read. Cool. and reinstate QuizApp as the Document Class in the properties panel. Here's how: var quizQuestion:QuizQuestion = new QuizQuestion( "Who is buried in Grant's Tomb?".

Right here I should clarify something. Actually the array doesn't physically contain the data.5. An array is just a handy way to group things. This task we will call "createQuestions." It's maybe still a little bit vague at this point. An analogy might be putting my house and your house in an array. Like I said. The tasks that need to be carried out will be listed in the constructor as various function calls. you're also creating a custom data type at the same time. We know that we need to instantiate a group of QuizQuestions. We often talk about storing data in arrays. So. except one thing: the variable we'll create will be of the QuizQuestion type. like a list. and maybe something like "Finish"?) for navigation. It involves creating a variable. so the final thing the constructor should do is take us to the first question. we'll create a variable that's an integer. but I'm giving you a crash course. but you do know that you need a variable of some kind that will keep track of the identity or index of the current question. I'd like to introduce you to an interesting technique. and this array will be an array of--guess what? QuizQuestion instances! Yep! You may not have realized it yet. This took me a long time to understand. and call it currentIndex. That's right! When you create a custom class. or we might say we stored an object or a variable in an array. The array would be more like a list that simply had my address and your address on it." From there. but we know that flash is event driven.Sprite. and datatype it to QuizQuestion! We'll call it "currentQuestion" and add it to the variable list just like any other variable: . We'll call this task "firstQuestion. This variable will keep track of the index number of whatever the current question is. clicking on the "next" button could take us to the second question. And at this point. We can use this index in combination with the array of QuizQuestions to move to the previous or next question.display. This task we will call "createButtons. and store them in our array. We can declare a variable. This class file will rely heavily on a kind of division of labor. Nothing new about that. public class QuizApp extends Sprite { public function QuizApp() { trace("this is the document class"). it's still kind of vague conceptually. } } } The first order of business will be to create an array. but rather references to the data. and so on. but an array can hold any type of data. The QuizApp Class (the Document Class) Part One Now we'll get busy working on QuizApp. The array wouldn't be a huge container that enveloped our houses. which currently looks like this: package { import flash." We know that we need to create buttons (like "Previous" and "Next" buttons.

. pointer) that we can use to refer to any of the quizQuestions in the array. That way. And you can add XML capabilities on your own later on if you want. So. then executing the above line. public function QuizApp() { quizQuestions = new Array(). we'll use it like this: currentQuestion = quizQuestions[currentIndex].var currentQuestion:QuizQuestion. . createQuestions(). Here's the createQuestions function: private function createQuestions() { quizQuestions. the createQuestions function is going to contain all the data to create all the questions. createButtons(). However. To add more questions later. public class QuizApp extends Sprite { private var quizQuestions:Array. Instead. starting with createQuestions. and that's what we'll get to next. we're going to be setting it equal to one of the QuizQuestions that are stored in the quizQuestions array. you'll have to go back and edit your QuizApp file and type in more questions. it's as easy as changing the value of currentIndex. "currentQuestion" becomes like a re-usable container (or if you prefer.display. we won't set it equal to a new instance of QuizQuestion. Having declared its type. To move to another question. . but I just want to keep this tutorial simple.accomplishes a lot! It basically gives us another name by which we can refer to the first element of the quizQuestions array. instead of giving it a hard-coded number for an index. private var currentQuestion:QuizQuestion. For example. Here's the updated class file with this new variable listed: package { import flash.Sprite. We will treat this variable a little differently than other variables we might make. But QuizApp will be flexible enough to allow you to add any number of questions you want. but there's more to it than that. The questions in the array can thus take turns being the current question. as needed. } } } The functions listed in the constructor haven't been written yet. Now. firstQuestion(). the code is much more dynamic. I know that we could create a bunch of questions and store them in an XML file..push(new QuizQuestion("What color is an orange?". writing a statement like: currentQuestion = quizQuestions[0]. 1.

stageHeight . "Blue". prevButton.addEventListener(MouseEvent. prevButton = new Button(). "Stan Lee and Steve Ditko". prevButton. 3. Gaines". nextButton. addChild(prevButton).y = yPosition. You're not limited to 4 questions by any means. prevHandler). 2."Orange".label = "Previous". quizQuestions.40. "none of the above")). "Flat". "Cube". 20. "Brown")).label = "Next". Notice that each new instance of QuizQuestion is not assigned to a variable name. .addEventListener(MouseEvent.push(new QuizQuestion("Who created Mad?". quizQuestions. "Al Feldstein".y = yPosition. "Steve Ditko". prevButton. "Harvey Kurtzman". addChild(nextButton). The array's name and the index number in brackets become our way of referring to individual quiz questions.push(new QuizQuestion("What is the shape of planet earth?". and some tidbits of trivia from comic book history.x = 30. prevButton. nextButton = new Button().width + 40. nextHandler). Next. but there is really no need to name a variable. Put in 10.x + prevButton. "Shabby")). "none of the above")).CLICK. nextButton. either.x = prevButton. or however many you want. 50. "Stan Lee". nextButton. "Jack Kirby". quizQuestions. "Round".push(new QuizQuestion("Who created SpiderMan?". 2.CLICK. "William M. nextButton. but is instead immediately pushed into the quizQuestions array. "Jack Davis". It could be done either way. } These are a combination of some nonsensical questions I made up. let's go on to writing the createButtons function: private function createButtons() { var yPosition:Number = stage. Feel free to change these around and/or use your own questions if you want. finishButton = new Button(). "Purple".

controls.MouseEvent. so that if you later change the size of the flash application's stage area. we'll write the remaining function referred to in the constructor.width + 40. finishButton. firstQuestion: private function firstQuestion() { currentQuestion = quizQuestions[0]. finishHandler). } private function nextHandler(event:MouseEvent) { trace("next").label = "Finish". } private function finishHandler(event:MouseEvent) { trace("finish"). so their y positions will all be the same. Next. and each also has an event listener assigned to it. private var nextButton:Button. finishButton. import flash. one for each button: private function prevHandler(event:MouseEvent) { trace("previous"). private var finishButton:Button. } It's going to be necessary that we import the Button class. here's the entire file so far: .y = yPosition. Let's go ahead and write some empty handler functions. Also. this code will not need to be changed.addEventListener(MouseEvent. They are going to be in a row across the bottom of the screen.x + nextButton. Similarly. The temporary variable "yPosition" is obviously for setting the y position of all the buttons. Later. now. and also the MouseEvent class. Each button is added to the display list. so add these items to the import block: import fl.events.Button. we will fill in the real actions. add the variables for the buttons to the variable list: private var prevButton:Button. and also allow us to test the movie without getting errors. addChild(finishButton). stage. } If you've added all these things. hard coded numbers were mostly avoided.x = nextButton. finishButton. addChild(currentQuestion). and the buttons' x properties are all expressed in terms of the previous one.finishButton.CLICK.stageHeight was used as a base. too. } The dummy actions inside these handler functions just give us some feedback that our buttons are working. which will be whatever we want to have happen whenever one of those buttons is clicked.

private var currentQuestion:QuizQuestion.push(new QuizQuestion("Who created Mad?". Gaines". 3. "Shabby")).push(new QuizQuestion("What color is an orange?". private var nextButton:Button.40.events.push(new QuizQuestion("What is the shape of planet earth?".package { import flash. public function QuizApp() { quizQuestions = new Array(). } private function createQuestions() { quizQuestions. } private function createButtons() { var yPosition:Number = stage. "Blue".controls. "Jack Kirby". "Orange".Sprite. createQuestions().MouseEvent. "none of the above")). "Steve Ditko". private var finishButton:Button. import flash. "none of the above")). createButtons(). . private var prevButton:Button. public class QuizApp extends Sprite { private var quizQuestions:Array. "Round". "Stan Lee". "Al Feldstein".stageHeight . "Brown")).display. firstQuestion(). quizQuestions. prevButton = new Button(). 2. "Purple". "Harvey Kurtzman". 2. 1. "Jack Davis". "Stan Lee and Steve Ditko". "Cube". quizQuestions. quizQuestions. "William M. "Flat".Button. import fl.push(new QuizQuestion("Who created SpiderMan?".

finishHandler). when the user clicks the "next" button. and the finish button to compute the score when all the questions have been answered.x = prevButton. nextButton. 6.label = "Next". you get the trace output for each one. Naturally.y = yPosition. addChild(prevButton). You should get the display of the first quiz question.y = yPosition. addChild(finishButton). we want the program to advance to the next question in the array. nextHandler).y = yPosition. prevButton.addEventListener(MouseEvent. the previous button to take us to the previous question.label = "Finish". For example. } private function finishHandler(event:MouseEvent) { trace("finish"). and finish buttons that we need to work into the code. finishButton. } private function prevHandler(event:MouseEvent) { trace("previous"). finishButton.prevButton. Also. prevHandler). nextButton = new Button().x + nextButton. nextButton. finishButton = new Button(). addChild(currentQuestion). } private function firstQuestion() { currentQuestion = quizQuestions[0].CLICK. } private function nextHandler(event:MouseEvent) { trace("next"). prevButton.CLICK.x = nextButton.x + prevButton. addChild(nextButton).addEventListener(MouseEvent. prevButton. we probably .x = 30. finishButton. we want the next button to take us to the next question. and when you click the buttons.width + 40. previous. We'll take all that on next. nextButton.width + 40. we'll add all the remaning functionality to the QuizApp class. } } } Press CTRL-Enter to test your movie.CLICK. nextButton.label = "Previous". unless the current question is the last question. There is a certain logic to the next. The QuizApp Class (the Document Class) Part Two Next.addEventListener(MouseEvent. finishButton.

Add the following to the variables list: private var status:TextField. If that's the case. So add this function right after the createStatusBox one: . we want the program to go ahead and compute the score. } This just creates a new TextField instance named "status. and display the results.TextField. All this logic will be programmed into the buttons. we won't put any check to make sure the user has answered the current question. when the "previous" button is clicked. any other messages we need to get across could be diplayed in this box." autosizes it to the left (so it'll expand to the right). We're going to be calling on this textbox to display messages so often that it will be handy to make a function for that purpose. which can be done at any time. we want to display the previous question in the array. unless the current question is the very first one in the array.TextFieldAutoSize.y = stage. If the "next" button is clicked.autoSize = TextFieldAutoSize. we just have to translate the above into Actionscript. but before the firstQuestion one: private function createStatusBox() { status = new TextField(). Similarly. Similarly. as they will most likely move forward again and return to it. but only if all of the questions have been answered. Finally. once again. when the "finish" button is clicked. Now we're all set to write the createStatusBox function. which we'll call showMessage. just after createButtons but before firstQuestion: createStatusBox().stageHeight . addChild(status).80.text. and places it 80 pixels above the bottom of the stage. we will import the TextField and TextFieldAutoSize classes: import flash.text. So. We could also use it to display the final results. which will be just above the row of buttons. In this case. status. Add the following command to the constructor. Add in this function just after the createQuestions and createButtons functions. status.want to disallow moving to the next question until the user has supplied an answer to the current one. we could use this message box to tell them so.LEFT. and the user hasn't answered the current question. But first. it would be nice if we had something like a text box where we could display messages to the user. then it will go ahead and compute their score. import flash.

length. We'll replace those trace messages with the real actions we want to perform. createQuestions(). Your constructor function should now look like this: public function QuizApp() { quizQuestions = new Array(). Here's the code for the "previous" button: . i++) { addChild(quizQuestions[i]).x = (stage. } This function accepts a String as a parameter. status. But first. we've got our buttons. and we've got a way to display messages on the screen. which will be whatever message we want to display. } } private function hideAllQuestions() { for(var i:int = 0. currentQuestion. hideAllQuestions(). createStatusBox(). and then the next line centers it on the screen. when we want to hide or show a question. we'll create another function that will make them all invisible. Earlier. we've got our array of quizQuestions. hideAllQuestions(). i < quizQuestions.private function showMessage(theMessage:String) { status. It sets it as the text of the status textbox.width / 2). } Now. After that.text = theMessage. after everything else but (once again) before firstQuestion: addAllQuestions(). addAllQuestions(). we can program the buttons.visible = true.(status. } Next. firstQuestion(). change the firstQuestion function to the following: private function firstQuestion() { currentQuestion = quizQuestions[0]. The next obvious step is to program the buttons.visible = false. i < quizQuestions. let's create a function that will put all of the questions on the display list.length. Now. we'll just toggle its visibility using its "visible" property. add these function calls to the constructor. i++) { quizQuestions[i]. Then. } } Also. Here are the functions to add: private function addAllQuestions() { for(var i:int = 0. I described the logic. createButtons().stageWidth / 2) .

But now it's a different question than it was three lines ago. } } The logic here is similar to the last one. if(currentIndex > 0) { currentQuestion.userAnswer == 0) { showMessage("Please answer the current question before continuing"). Long story short. This time. it's now the previous one in the array of questions. return. Here's the code for the "next" button: private function nextHandler(event:MouseEvent) { showMessage(""). they haven't answered the question yet.visible = true. and the "userAnswer" getter function returns that. currentQuestion.length . currentIndex--.visible = false. then set currentQuestion equal to quizQuestions[currentIndex]. if it's still 0. } if (currentIndex < (quizQuestions. } else { showMessage("This is the first question. If it's not. or Previous to go back"). with a few differences. We'll include this as the first action of all the buttons. currentQuestion. But if currentIndex is greater than 0. and our custom "showMessage" function is employed to tell the user that. Finally. inside of QuizQuestion the variable "theUserAnswer" gets set to the value of whatever multiple choice button they clicked. } } The first action here is to clear the status text box of anything that might already be in it.1)) { currentQuestion. currentQuestion = quizQuestions[currentIndex]. currentIndex++. currentQuestion = quizQuestions[currentIndex]. take away one from the currentIndex. if (currentQuestion. Remember that "userAnswer" is one of the "getter" functions built into QuizQuestion. the first check is to see if the user has answered the question in front of them. The return statement there causes the function to stop executing. } else { showMessage("That's all the questions! Click Finish to Score.private function prevHandler(event:MouseEvent) { showMessage(""). in which case the else block takes over. Whenever the user answers the question.visible = true. we make currentQuestion visible again.visible = false. . it's 0. and we're at the first question. there are no previous ones"). we first hide currentQuestion. The if statement checks to see if the currentIndex is greater than 0. and there is no previous question to go to.

hideAllQuestions().length.userAnswer == quizQuestions[i]. though.userAnswer == 0) { finished = false. If not. The loop is then terminated. we need a variable named "score" in our variables list. i++) { if (quizQuestions[i]. Here's the code for the "finish" button: private function finishHandler(event:MouseEvent) { showMessage(""). } } if (finished) { prevButton. i < quizQuestions. and makes a call to a function (which we'll write next) called computeScore. i++) { if (quizQuestions[i]. computeScore(). the following statements proceed to the next question. If so. for (var i:int = 0. } } showMessage("You answered " + score + " correct out of " + quizQuestions. The first question that passes this if test will cause the "finished" variable to be set to false. and if so. it displays an appropriate message. var finished:Boolean = true. If that's the case. First. nextButton.correctAnswer) { score++. } else { showMessage("You haven't answered all of the questions"). the showMessage function is called to display a message telling you so. break. so add this line there: private var score:int = 0.visible = false. all the questions are run through in a loop and each one tested to see if any of them haven't been answered yet.visible = false. finishButton. } } This function first sets up a local Boolean variable called "finished. } . Now. The next if statement uses the result of that test to see if the user really answered all the questions.The next if statement checks to make sure the user is not at the last question. hides all the questions." which is set to true. it hides all the buttons.length. i < quizQuestions. the final thing to write is the computeScore function. Here's the code for computeScore: private function computeScore() { for (var i:int = 0. Next.length + " questions.").visible = false.

"Round".push(new QuizQuestion("What is the shape of planet earth?".text. fl. private var finishButton:Button. . createQuestions(). "Jack Kirby".Sprite.MouseEvent. showMessage is once again called upon to display the results. "Shabby")). "Stan Lee and Steve Ditko". private var status:TextField. "Blue". flash.controls. flash. hideAllQuestions(). after the loop completes. 3.display.TextField. If they match. "Orange". "Cube". private var nextButton:Button. createButtons(). flash. 2. private var currentIndex:int = 0. the score is incremented by 1.push(new QuizQuestion("Who created SpiderMan?".push(new QuizQuestion("What color is an orange?". //scoring and messages: private var score:int = 0.Once again. and each one's user answer is compared to the correct answer. private var currentQuestion:QuizQuestion. Here's the entire completed QuizApp file: package { import import import import import flash. "Brown")). public class QuizApp extends Sprite { //for managing questions: private var quizQuestions:Array.TextFieldAutoSize. "Flat".events. //the buttons: private var prevButton:Button. firstQuestion(). public function QuizApp() { quizQuestions = new Array(). the array of quizQuestions is run through. addAllQuestions(). quizQuestions. } private function createQuestions() { quizQuestions. createStatusBox().Button.text. "Purple". Finally. 1. quizQuestions.

x + nextButton. "none of the above")).label = "Finish". prevHandler).visible = false.80. nextButton.y = yPosition.label = "Previous".CLICK.width + 40.x = 30. "William M.autoSize = TextFieldAutoSize. finishButton.width / 2).addEventListener(MouseEvent. } private function createStatusBox() { status = new TextField(). "Steve Ditko".CLICK.length. 2. . i++) { quizQuestions[i]. addChild(status). "Harvey Kurtzman". addChild(nextButton). "Jack Davis". nextHandler).stageHeight .CLICK. prevButton = new Button(). addChild(prevButton).x + prevButton.LEFT.addEventListener(MouseEvent.label = "Next". finishButton. nextButton. quizQuestions. status.text = theMessage.stageHeight .x = nextButton. } private function showMessage(theMessage:String) { status. "Al Feldstein". finishHandler). } private function addAllQuestions() { for(var i:int = 0. addChild(finishButton).y = stage.x = prevButton. } } private function hideAllQuestions() { for(var i:int = 0.addEventListener(MouseEvent. finishButton = new Button(). i < quizQuestions. finishButton.y = yPosition. } private function createButtons() { var yPosition:Number = stage. prevButton. prevButton. finishButton.40.stageWidth / 2) ."Stan Lee". status. nextButton = new Button(). Gaines".y = yPosition.length.(status. i++) { addChild(quizQuestions[i]).width + 40. status. "none of the above")).x = (stage. prevButton.push(new QuizQuestion("Who created Mad?". nextButton. nextButton. prevButton. i < quizQuestions.

currentQuestion = quizQuestions[currentIndex]. there are no previous ones"). return. } else { showMessage("This is the first question. nextButton. var finished:Boolean = true. } } if(finished) { prevButton.userAnswer == 0) { showMessage("Please answer the current question before continuing"). } if(currentIndex < (quizQuestions.visible = false.length . } } private function nextHandler(event:MouseEvent) { showMessage(""). if(currentQuestion.length. } else { showMessage("That's all the questions! Click Finish to Score. currentQuestion. if(currentIndex > 0) { currentQuestion.} } private function firstQuestion() { currentQuestion = quizQuestions[0]. i++) { . finishButton. or Previous to go back").length. } } private function computeScore() { for(var i:int = 0. } else { showMessage("You haven't answered all of the questions").visible = false. currentIndex--. i < quizQuestions. } } private function finishHandler(event:MouseEvent) { showMessage(""). computeScore(). currentIndex++. currentQuestion. currentQuestion. for(var i:int = 0. i++) { if(quizQuestions[i].visible = true.visible = true.userAnswer == 0) { finished = false.visible = true. } private function prevHandler(event:MouseEvent) { showMessage("").1)) { currentQuestion. break. hideAllQuestions().visible = false. currentQuestion = quizQuestions[currentIndex].visible = false. i < quizQuestions.visible = false.

The details may differ in what you want to make. but the underlying concepts of objects and classes are going to remain the same. It just served as a simple example application. This application is "bare bones" and needs a lot more work. .if(quizQuestions[i]. See the introduction to this article (click the "up" link below) to download a ZIP file of this application. Making a fancier transition when changing questions (maybe fly-in. it's not that the quiz itself is any big deal. fly-out?) Give feedback at the end as to the correct answer to each question. I'll try to keep them coming as I myself learn more. PS. but rather a slideshow. or a menu. Maybe you don't want to make a quiz. I enjoy writing these. In actuality.userAnswer == quizQuestions[i].length + " questions."). I hope you enjoyed this article. Get the question and answer data from an XML file. There are a lot of ways this application could be jazzed up. including: Styling the text using a different font. though. and I've been getting a lot of good feedback from them. } } } Closing Comments: That concludes this tutorial.correctAnswer) { score++. } } showMessage("You answered " + score + " correct out of " + quizQuestions. The concept of classes and objects is the thing to take away from this. or an MP3 player.

Sign up to vote on this title
UsefulNot useful

Master Your Semester with Scribd & The New York Times

Special offer for students: Only $4.99/month.

Master Your Semester with a Special Offer from Scribd & The New York Times

Cancel anytime.