overview

today we'll explore flash programming fundamentals

after each theory segment, we'll study an example: a multiple choice quiz

we'll build 3 versions of the quiz

user experience won't change with each quiz version

instead, we'll improve the code structure so it's:

  • easier to maintain
  • easier to extend
  • faster to build
  • download example files here

    the learning cycle

    always remember: learning to program is a process, not an event

    you should expect to learn something every time you program

    don't worry if you don't follow everything the first time through

    even those things you don't understand will give you get a sense of what's possible

    speaking actionscript

    programming languages are used to send information to and receive information from computers

    programming languages have vocabulary and grammar used to communicate, just like human languages

    using a programming language we tell a computer what to do or ask it for information

    expressing logic

    the art of programming lies in the formulation of logical steps

    think of programming a computer like talking to a child:

  • be explicit in every detail
  • list every single step that's necessary to complete a task
  • flash's programming environment

    Actions panel: the place you put your instructions

    Window > Development panels > Actions (or "F9")

    the "instructions" are known as "code" or "script"

    Actions panel includes a quick reference pane for help while you code

    you can also put code in external text files, but for now we'll stick to the actions panel

    what you can do with actionscript

    some of the things you can do with actionscript code:

  • control the playhead of a timeline
  • move things around
  • create and manage user interfaces
  • play sounds
  • control video
  • manage data (xml, lists, etc)
  • communicate with server-side applications (e.g., web servers)
  • where to put the code

    within a .fla file, code is attached to either a frame, button, or movie clip

    to attach code to a frame, button, or movie clip, first select it, then type in the actions panel

    notice that the actions panel title changes to match the current selection (Actions - Frame, Actions - Button, or Actions - Movie Clip

    check the actions panel title before typing so you know what you're attaching your code to

    code on a movie clip or button controls that clip or button

    generally speaking, placing code on clips and buttons is discouraged, but is sometimes convenient

    say hi to flash

    select frame 1

    type the following into the right side of the Actions panel:

    var message = "Hi there Flash!";

    that line of code constitutes a complete instruction, known as a statement

    now create three more statements:

    var firstName = "your name here"; trace(message); trace("Hi there, " + firstName + ", nice to meet you.");

    the code doesn't do anything until we export a .swf file and play the movie

    select Control>>Test Movie

    storing information

    take another look at our first line of code

    var message = "Hi there Flash!";

    a literal translation for that code is:

    Flash, please remember a piece of information for me...

    ...specifically, remember the phrase 'Hi there Flash!'

    ...please label the information message so that i can ask you for it later

    ...whenever i ask you for message, give me back the text 'Hi there Flash!

    storing information is one of the foundations of programming

    you can label stored information so that it can be used later

    variables

    look at our second line of code again:

    var firstName = "your name here";

    it asks Flash to remember our first name and label it firstName

    Flash can remember any information that is considered a valid type of data, such as numbers and text

    in programming terms a piece of "text" is also known as string

    an individual piece of data is known as a datum

    a datum (e.g., "Hi there Flash!") and the label that identifies it (e.g., message) are together known as a variable

    variable terminology

    a variable's label ("message") is called its name

    a variable's datum ("hi there Flash!") is called its value

    a variable is said to "store" or "contain" its value

    specifying a variable's value is called "assigning" or "setting" the variable

    to assign a variable a value, use the equals sign: =

    creating a variable is called declaring it

    to declare a variable, use the keyword var

    example sentence: "declare a new variable named message, and assign it the value "Hi there Flash!"

    the interpreter

    recall our third statement

    trace(message);

    it issues a command, trace, that causes data to appear in the Output window

    how does that work?

    when you create a variable or issue a command, you're actually addressing the ActionScript interpreter

    the interpreter is the part of Flash that executes ActionScript code

    the interpreter does the following:

  • runs your programs
  • manages your code
  • listens for instructions
  • performs any ActionScript commands
  • stores your data
  • sends you information
  • calculates values
  • if the interpreter understands your commands, it sends them to the computer's processor for execution

    if a command generates a result, the interpreter provides that response to you

    if the interpreter can't understand the command, it sends you an error message

    for example, try running this code:

    = "test";

    the interpreter outputs an error. it doesn't expect the = without a variable name

    remember that the interpreter has to read your code, letter by letter, and try to understand it

    error messages are GOOD! because they help you fix your code

    arguments

    commands usually require supplementary information to run

    for example, the trace() command requires the text to display

    the data sent to a command is called an argument

    to supply an argument to a command, enclose the argument in parentheses, like this:

    command(argument);

    to supply multiple arguments to a command, separate them with commas, like this:

    command(argument1, argument2, argument3);

    supplying an argument to a command is known as passing the argument

    for example, in the code gotoAndPlay(5):

  • gotoAndPlay is the name of the command
  • 5 is the argument being passed (the frame number)
  • some commands, (e.g., stop()) require parentheses but can not be passed arguments. we'll learn why later

    operators

    take another look at our fourth line of code:

    trace("Hi there, " + firstName + ", nice to meet you.");

    the + signs join (concatenate) our text together

    + is one example of a programming tool called an operator

    operators are like conjunctions ("and," "or," "but," etc.) in human languages

    all operators link phrases of code together

    most operators transform data in some way

    example operators:

  • arithmetic: -, +, *, /
  • comparison: < (less than), > (greater than)
  • logic in a program

    we make millions of basic decisions in our daily lives

    for example, when crossing the road we decide:

  • if a car is coming, we wait for it to pass
  • if a car is not coming, we cross the road
  • a program must make similar decisions based on the state of its environment

    for example:

  • if the user has seen the website's introduction already, don't show it again
  • if the user specifies the wrong password to a restricted zone, don't show the restricted content
  • a "decision" in a program means choosing whether or not to execute a section of code

    conditional statements

    to let a program decide whether to execute code, we use a conditional statement (a.k.a., a "conditional")

    generic conditional structure:

    if (this condition is met) { then execute these lines of code }

    for example:

    if (username == "James Bond") { trace ("Welcome to my website, 007."); }

    the equality operator, ==, tests if two data values are equal

    don't mistake the equality operator (two equal signs ==) with the assignment operator (one equal sign =)!

    to execute an alternative section of code when a condition is not met, use an else statement

    if (userName == "James Bond") { trace ("Welcome to my website, 007."); } else { trace ("Sorry, only James Bond can use this site."); }

    to execute one of many possible sections of code, use else if:

    if (userName == "James Bond") { trace ("Welcome to my website, 007."); } else if (userName == "Moock") { trace("Welcome to my website, Colin."); } else { trace ("Sorry, only James Bond or Colin can use this site."); }

    repetitive tasks

    suppose you want to display a five-number sequence in the Output window, starting at any number

    you could display the sequence like this:

    trace(10); trace(11); trace(12); trace(13); trace(14);

    if you want to start the sequence at 513, you have to retype all the numbers

    trace(513); trace(514); trace(515); trace(516); trace(517);

    to avoid this retyping, we use a variable:

    var x = 1; trace (x); x = x + 1; trace (x); x = x + 1; trace (x); x = x + 1; trace (x); x = x + 1; trace (x);

    to change the sequence starting number, just change the initial value of x

    but what if we want to count to 500?

    even with the variable, it's too much typing

    loops

    to perform repetitive tasks, we use a loop

    a loop is type of statement that causes a block of code to be repeated

    here's what the counting example looks like as a while loop:

    var x = 1; while (x <= 5) { trace (x); x = x + 1; }

    the statements to repeat are listed between the brackets: { }

    the keyword while starts the loop

    the comparison (x <= 5) indicates when to quit repeating the loop

    the loop stops repeating when x is less than or equal to 5

    to make the loop count to 500, simply change 5 to 500

    the for loop

    basic loops come in two varieties: a while loop and a for loop

    for does the same thing as while, but with a different syntax

    here's a for loop:

    for (var x = 1; x <= 5; x = x + 1) { trace(x); }

    the for loop is like a condensed while loop

    the contents of the loop are the same, but rearranged:

    initialize while (compare) { statements update } for (initialize; compare; update) { statements }

    the for loop makes the initialization, comparison, and update easier to find

    functions

    a function is a group of statements packaged together to form a single, reusable command

    functions let us write code once, but use it many times throughout a program

    repetition is bad

    suppose we use this code to display the area of a rectangle:

    var height = 10; var width = 20; trace(width * height);

    later we decide we want to display the area of five different rectangles

    our code gets 5 times longer:

    var height1 = 10; var width1 = 20; trace(width1 * height1); var height2 = 234; var width2 = 59; trace(width2 * height2); var height3 = 40; var width3 = 99; trace(width3 * height3); var height4 = 39; var width4 = 875; trace(width * height); var height5 = 3; var width5 = 2; trace(width5 * height5);

    notice that the same three statements are used for each rectangle

    repeating statements is error-prone and time-consuming

    instead of repeating statements, create functions that contain the repeated code

    an example function

    here's a function that displays the area of a rectangle

    function displayArea (width, height) { trace(width * height); }

    the function keyword starts the function declaration

    next comes the name of the function: displayArea

    next comes a list of arguments used by the function, in parentheses: (width, height)

    finally, we list the statements of the function, within brackets: { }

    the statements contain the code that would otherwise have been repeated

    running a function

    to run a function use same format as trace() command earlier

    first, specify the function name:

    displayArea

    then provide any required arguments:

    displayArea(10, 20);

    the statements inside the function then run with width set to 10 and height set to 20

    running a function, illustrated

    here is the flow of operations for our example function execution:

    code comparison

    here's our old code, with repeated statements:

    var height1 = 10; var width1 = 20; trace(width1 * height1); var height2 = 234; var width2 = 59; trace(width2 * height2); var height3 = 40; var width3 = 99; trace(width3 * height3); var height4 = 39; var width4 = 875; trace(width * height); var height5 = 3; var width5 = 2; trace(width5 * height5);

    here's the new code, with a function:

    function displayArea (width, height) { trace(width * height); } displayArea(10, 20); displayArea(234, 59); displayArea(40, 99); displayArea(39, 875); displayArea(3, 2);

    the new code is shorter

    the new code is easier to understand

    function names describe what the code is doing

    code comments

    to add even more descriptive information to our code, we use comments

    a comment is a note in code that is meant to be read by programmers

    any line of code that starts with // is a comment:

    // This is a comment...

    comments help programmers understand how code works

    you should always narrate your code with comments

    for example...

    // Displays the area of a rectangle in Flash's Output window function displayArea (width, height) { trace(width * height); } // Display the area of five rectangles displayArea(10, 20); displayArea(234, 59); displayArea(40, 99); displayArea(39, 875); displayArea(3, 2);

    exiting and returning values from functions

    normally, a function ends when its last statement executes

    but you can also stop a function manually, using a return statement

    for example, this revised version of displayArea() quits before the area is ever displayed:

    function displayArea (width, height) { return; trace(width * height); }

    usually, we only quit functions early based on some condition

    for example, this function quits if the supplied password is wrong:

    function enterSite(pass) { if(pass != "cactus") { // Exit if the password is wrong: return; } // This code is reached only if the password is correct. gotoAndPlay("intro"); } enterSite("hackAttack"); // Function will exit prematurely enterSite("cactus"); // Function will end naturally

    built-in functions

    take another look at the command gotoAndPlay() from the previous example:

    gotoAndPlay("intro");

    gotoAndPlay() is a built-in function, provided by ActionScript

    there are lots of built-in functions, and they are used just like any other function

    returning to the point of execution

    when a function finishes, the interpreter continues executing any code after the function call

    for example:

    // When this function is done displayArea(25, 10); // Execution resumes here trace("Done calculating area of first rectangle"); // When this function is done displayArea(13, 4); // Execution resumes here trace("Done calculating area of second rectangle");

    returning information to the point of execution

    return always terminates a function

    but return can also send information back to the script that invoked the function

    for example, the displayArea() function could return width*height instead of displaying it:

    function displayArea (width, height) { return width * height; }

    the information returned by a function is called a return value

    using a function's return value

    return values are often used to set a variable's value

    for example, this code sets rectangleArea to 200:

    var rectangleArea = displayArea(10, 20);

    now that displayArea() returns the area instead of displaying it, we should rename it to getArea()

    function getArea (width, height) { return width * height; }

    return values can even be added together

    // Sets totalArea to 260 var totalArea = getArea(10, 20) + getArea(5, 12);

    objects

    let's review a couple of concepts:

  • a statement instructs Flash to do something
  • a function groups multiple statements into a convenient command
  • an "object" takes the next logical step: it packages related functions and variables into a single code module

    each object is like a self-contained, miniature program

    multiple objects can be used together like building blocks to form complex functionality

    object-oriented programming

    object-oriented programming (oop) means structuring your code with objects

    some languages require that all code be contained by some object (e.g., Java)

    in flash, you can put all your code in objects if you want, but it's not mandatory

    custom objects vs built-in objects

    just as some functions are built-in to ActionScript, some objects are also built-in

    built-in objects let us control:

  • visuals (movie clips, buttons, text, video)
  • sounds
  • network communication
  • ....and many other things in a movie
  • to program in flash, you must use the built-in objects

    hence, some OOP knowledge is required, even if you don't structure your own code with objects

    movie clip objects

    each movie clip instance on stage is represented by an actionscript object

    to control a movie clip object, we must give the movie clip an instance name

    once a movie clip has a name, we can:

  • set its variables (also called "properties")
  • control it by calling its functions (also called "methods")
  • for example, suppose we give a movie clip the instance name ball

    we can then set the horizontal position of the ball movie clip like this:

    ball._x = 150;

    and we can make the ball movie clip stop playing like this:

    ball.stop();

    the language of objects

    using objects, we can create sentence-like instructions in code:

  • the object is a noun
  • the property is an adjective
  • the method is a verb
  • for example:

    object.property = value; noun.adjective = value;

    object.method(); noun.verb();

    let's see it all in action!

    we've now learned quite a lot of theory

    let's apply that theory to an example: a multiple choice quiz

    quiz overview

    two questions; each with three multiple-choice answers

    users submit their answers by clicking answer buttons

    user answers are recorded in a variable

    answer variables are used to calculate the user's score

    at the end of the quiz, the score is displayed

    build the layer structure

    make a layer called scripts on which to place code

    keep the scripts layer at the top so it's easy to find

    make a layer called labels for all labels in our movie

    make four layers for our quiz assets

  • quiz end: for the results screen
  • question 2: for the second question screen
  • question 1: for the first question screen
  • choice buttons: for the answer buttons
  • housing: for the background and instructions
  • add 30 frames to all layers

    create the question 1 screen

    frame 1, question 1 layer, add text: "1) When were movie clips introduced into Flash?"

    below the question text add the answer text:

  • Version 1
  • Version 2
  • Version 3
  • create the question 2 screen

    select frame 1 of question 1 layer

    right-click > copy frames

    select frame 1 of question 2 layer

    right-click > paste frames

    insert blank keyframe at frame 10 of question 1 layer

    at frame 10 of question 2 layer:

  • change the question number from "1" to "2"
  • change the text of the question to, "When was MP3 audio support added to Flash?"
  • change the multiple choice answers to Version 3, Version 4, and Version 5
  • notice that frames are used to represent application screens
  • add the answer buttons

    create a simple button for the user to choose an answer

    at frame 1 of choice buttons layer, place three answer button instances

    set instance name for buttons to: choice1_btn, choice2_btn, and choice3_btn

    initialize the quiz

    add the code that initializes the movie to frame 1 of scripts layer

    no preloader for this example

    first describe what the code does with a comment:

    // Initialize main timeline variables

    next, create variables to store user's answers:

    var q1answer; // User's answer for question 1 var q2answer; // User's answer for question 2

    next, create a variable to track number of questions answered correctly:

    var totalCorrect = 0; // Counts number of correct answers

    finally, stop the movie at the first question:

    stop();

    variable naming styles

    to indicate multiple words in variables use capital letters:

    totalCorrect

    or underscores:

    total_correct

    give variables and functions meaningful names

    for example, avoid single letters, like "x" or abbreviations, like "tc"

    well-named variables help you understand how the code works

    add frame labels

    question 2 is on frame 10, so when we want to display Question 2 we could do this:

    gotoAndStop(10);

    sensible code, right? WRONG!

    if we add frames before frame 10, our code breaks!

    to avoid this problem, use frame labels

  • at frame 1, labels layer, set the label to init
  • at frame 10, labels layer, add a blank keyframe
  • at frame 10, labels layer, set the label to q2
  • at frame 20, labels layer, add a blank keyframe
  • at frame 20, labels layer, set the label to quizEnd
  • now we can add frames before question 2 and our code will still work

    responding to answer button clicks

    to submit an answer to a question, the user clicks the appropriate answer button

    our code must record the user's choice in either q1answer or q2answer

    how do we set a variable when a button is pressed?

    using an event handler...

    event-based code vs timeline code

    two things cause code to run in flash:

  • the playhead enters a frame with a script on it
  • an event occurs (either user input or a system notification)
  • to run code in response to an event, we create an event handler function or an event listener object

    today, we'll only study event handler functions

    event broadcast

    every event in flash is triggered by some object

    for example:

  • the Stage object tells you when the movie is resized
  • the Key object tells you when a key is pressed
  • a Button object tells you when a button is clicked
  • event-handler functions

    to respond to a "button clicked" event from a button...

    ...define an event handler function on that button

    theButton.onRelease = eventHandlerFunction;

  • theButton is the button instance that was clicked
  • onRelease is the name of the event
  • eventHandlerFunction is the function that should run when the button is clicked
  • the eventHandlerFunction can be defined inline or somewhere else

    // Define the event hanlder function inline... theButton.onRelease = function () { // Store the user's answer }

    // Or define the event handler function separately... theButton.onRelease = storeAnswer; function storeAnswer () { // Store the user's answer }

    here's the general format for event handler functions:

    eventBroadcastingObject.nameOfEvent = eventHandlerFunction;

    handling the answer button events, question 1

    question 1 answer-button-handlers are defined on frame 1, scripts layer

    here's the event handler function for answer button 1 of question 1:

    // Code executed when button 1 is pressed. choice1_btn.onRelease = function () { this._parent.q1answer = 1; this._parent.gotoAndStop("q2"); };

    the function does two things:

  • records the user's choice in q1answer
  • displays question 2
  • new code introduced:

  • this means choice1_btn (the button that broadcast the event)
  • _parent means the timeline containing choice1_btn
  • code for other two answer buttons follows same pattern:

    // Code executed when button 2 is pressed. choice2_btn.onRelease = function () { this._parent.q1answer = 2; this._parent.gotoAndStop("q2"); }; // Code executed when button 3 is pressed. choice3_btn.onRelease = function () { this._parent.q1answer = 3; this._parent.gotoAndStop("q2"); };

    handling the answer button events, question 2

    frame 10, scripts layer, add a blank keyframe

    question 2 answer-button-handlers are defined on frame 10, scripts layer:

    // Code executed when button 1 is pressed. choice1_btn.onRelease = function () { this._parent.q2answer = 1; this._parent.gotoAndStop("quizEnd"); }; // Code executed when button 2 is pressed. choice2_btn.onRelease = function () { this._parent.q2answer = 2; this._parent.gotoAndStop("quizEnd"); }; // Code executed when button 3 is pressed. choice3_btn.onRelease = function () { this._parent.q2answer = 3; this._parent.gotoAndStop("quizEnd"); };

    code for question 2 answer buttons is identical to question 1 buttons except:

  • user's choice is stored in q2answer (instead of q1answer)
  • quiz end screen is displayed (instead of question 2)
  • ending the quiz

    quiz is mostly functional

    to finish it, we'll:

  • build a final results screen
  • calculate and display the user's score
  • building the results screen

    frame 20, scripts layer, add a blank keyframe for score-calculation code

    frame 20, question 2 layer, add a blank keyframe

    frame 20, choice buttons layer, add a blank keyframe

    frame 20, quiz end layer, add a blank keyframe

    frame 20, quiz end layer, add text "Thank you for taking the quiz!"

    calculating the user's score

    the score-calculation code is attached to frame 20, scripts layer

    recall that the user's score is stored in the variable totalCorrect

    if the answer to question 1 is correct, add one to totalCorrect (3 is the correct answer)

    if (q1answer == 3) { totalCorrect = totalCorrect + 1; }

    if the answer to question 2 is correct, add another one to totalCorrect (2 is the correct answer)

    if (q2answer == 2) { totalCorrect++; }

    the ++ operator adds one to a variable

    totalCorrect now stores the user's score

    displaying the score on screen

    to display the user's score, create a text field:

    this.createTextField("totalOutput_txt", 1, 150, 200, 200, 20);

    this is main movie timeline

    createTextField() is a built-in MovieClip method

    totalOutput_txt is the name of the text field

    now display the score in the text field:

    totalOutput_txt.text = "Your final score is: " + totalCorrect + "/2.";

    notice that the text field is an object (lots of things are objects)

    the text property is the text to display on screen

    a little fun

    break time! let's make a mouse toy

    see mouseTrailer-01.swf through mouseTrailer-04.swf in /examples/visuals folder

    experimentation is key

    build something simple, then play with it (change values, parameters, etc)

    centralizing code

    our quiz has two problems:

  • the code is spread over three frames (hard to find, understand)
  • the button handler code is very repetitious (prone to error)
  • to fix these problems, we'll:

  • move all code to frame 1
  • introduce two functions: answer() and gradeUser()
  • quiz v2, initialization

    as before, we stop our quiz on question 1:

    stop();

    then initialize variables

    we use q1answer and q2answer just like last time:

    var q1answer; // User's answer for question 1 var q2answer; // User's answer for question 2

    and we add these new variables:

    var numQuestions = 2; // Number of questions in the quiz var correctAnswer1 = 3; // The correct choice for question 1 var correctAnswer2 = 2; // The correct choice for question 2 var currentQuestion = 1; // The question being answered

    the answer() function

    purpose: to reduce code repetition in answer button handlers

    each answer button will call answer() when pressed

    answer() has two duties:

  • record the user's choice
  • advance the quiz to either: a) the next question, b) the end results screen
  • here's the answer function skeleton:

    function answer (choice) { }

    choice parameter stores the user's answer

    asserting that the code works

    first task in the function: debugging information

    display the current question and choice in the Output window:

    function answer (choice) { trace("Question " + currentQuestion + ". The user answered: " + choice); }

    we can now check if the code is doing what we expect

    build code incrementally: when one section works, build the next section

    setting the answer variables

    when answer() runs, we must set either q1answer or q2answer

    how do we know which one to set?

    the currentQuestion variable tells us

    when currentQuestion is 1, we should set q1answer

    when currentQuestion is 2, we should set q2answer

    here's how that looks in code:

    function answer (choice) { // Display the question and answer in the Output window for debugging. trace("Question " + currentQuestion + ". The user answered: " + choice); // Record the user's answer to this question. if (currentQuestion == 1) { q1answer = choice; } else if (currentQuestion == 2) { q2answer = choice; } }

    advancing the quiz

    once the answer has been recorded, we advance the quiz

    if the current question is the last question...

  • ...calculate user's score and display the results screen
  • if the current question is not the last question...

  • ...display the next question
  • here's the code:

    function answer (choice) { // Display the question and answer in the Output window for debugging. trace("Question " + currentQuestion + ". The user answered: " + choice); // Record the user's answer to this question. if (currentQuestion == 1) { q1answer = choice; } else if (currentQuestion == 2) { q2answer = choice; } // If we're on the last question... if (currentQuestion == numQuestions) { // ...go to the quiz end frame. gotoAndStop("quizEnd"); // And grade the user. gradeUser(); } else { // ...otherwise, go to the next question frame. gotoAndStop("q"+ (currentQuestion + 1)); // Note that we're on the next question. currentQuestion++; } }

    subcontracting labour

    notice that the answer() function calls a separate function, gradeUser()

    the code in gradeUser() could have been contained within answer()

    but its wiser to do one-task-per-function

    following the one-task-per-function rule makes code:

  • easier to debug
  • more reusable (each function can be independently)
  • new answer button handlers

    here are the new event handler functions for the answer buttons:

    choice1_btn.onRelease = function () { this._parent.answer(1); }; choice2_btn.onRelease = function () { this._parent.answer(2); }; choice3_btn.onRelease = function () { this._parent.answer(3); };

    code repetition is reduced

    answer() function keeps track of the current question...

    ...hence, handlers for question 1 and question 2 answer buttons can be the same!

    grading the user

    when the quiz is over, answer() calls gradeUser()

    gradeUser() has two duties:

  • calculate the user's score
  • display the user's score on screen
  • once again, start the function with debugging information:

    function gradeUser() { trace("Quiz complete. Now grading..."); }

    tallying the score

    to store the user's score, we'll create a variable, totalCorrect:

    function gradeUser() { trace("Quiz complete. Now grading..."); var totalCorrect = 0; }

    a variable defined within a function is called a local variable

    local variables are deleted automatically when a function ends

    calculate the score with a loop

    we'll use a loop to calculate the user's score

    the loop runs once for every question in the quiz:

    for (var i = 1; i <= numQuestions; i++) { }

    the loop body checks each answer to see if it is correct

    for (var i = 1; i <= numQuestions; i++) { if (eval("q" + i + "answer") == eval("correctAnswer" + i)) { totalCorrect++; } }

    the built-in eval() function returns the value of the specified variable

    the first time the loop runs, i is 1...

    ...so the loop body reads:

    if (eval("q" + 1 + "answer") == eval("correctAnswer" + 1)) { totalCorrect++; }

    which is equivalent to:

    if (q1answer == correctAnswer1) { totalCorrect++; }

    the second time the loop runs, i is 2...

    ...so the loop body reads:

    if (eval("q" + 2 + "answer") == eval("correctAnswer" + 2)) { totalCorrect++; }

    which is equivalent to:

    if (q2answer == correctAnswer2) { totalCorrect++; }

    when the loop is finished, the final score is ready for display

    displaying the score

    the score-display code from quiz v1 has moved to gradeUser():

    this.createTextField("totalOutput_txt", 1, 150, 200, 200, 20); totalOutput_txt.text = "Your final score is: " + totalCorrect + "/" + numQuestions;

    add a little formatting to the text:

    var format = new TextFormat(); format.size = 16; format.color = 0xC7FF9C; format.font = "_sans"; format.bold = true; totalOutput_txt.setTextFormat(format);

    quiz v2, final code

    here's all the code for version 2 of the quiz:

    // * INITIALIZATION * // Stop the movie at the first question. stop(); // Init quiz variables var numQuestions = 2; // Number of questions in the quiz var q1answer; // User's answer for question 1 var q2answer; // User's answer for question 2 var correctAnswer1 = 3; // The correct choice for question 1 var correctAnswer2 = 2; // The correct choice for question 2 var currentQuestion = 1; // The question being answered. // * FUNCTIONS * // Function: answer() // Desc: Registers the user's answers to quiz questions and // advances the quiz through its questions. function answer (choice) { // Display the question and answer in the Output window for debugging. trace("Question " + currentQuestion + ". The user answered: " + choice); // Record the user's answer to this question. if (currentQuestion == 1) { q1answer = choice; } else if (currentQuestion == 2) { q2answer = choice; } // If we're on the last question... if (currentQuestion == numQuestions) { // ...go to the quiz end frame. gotoAndStop("quizEnd"); // And grade the user. gradeUser(); } else { // Note that we're on the next question. currentQuestion++; // ...otherwise, go to the next question frame. gotoAndStop("q"+ (currentQuestion + 1)); } } // Function: gradeUser() // Desc: Tallys the user's score at the end of the quiz. function gradeUser() { // Report that we're about to grade the quiz in the Output window. trace("Quiz complete. Now grading..."); // Create a local variable to track the // number of questions user answered correctly. var totalCorrect = 0; // Count how many questions the user answered correctly. // For each question... for (var i = 1; i <= numQuestions; i++) { // If the user's answer matches the correct answer. if(eval("q" + i + "answer") == eval("correctAnswer" + i)) { // Give the user a point. totalCorrect++; } // Display the correct answer and the user's answer // in the Output window for debugging. trace("Question " + i + ". Correct answer: " + eval("correctAnswer" + i) + ". User's answer: " + eval("q" + i + "answer")); } // Display the final score in the Output window for debugging. trace("User's score: " + totalCorrect + "/" + numQuestions); // Create an onscreen text field do display the user's score. this.createTextField("totalOutput_txt", 1, 150, 200, 200, 20); // Show the user's score in an onscreen text field. totalOutput_txt.text = "Your final score is: " + totalCorrect + "/" +numQuestions; // Customize the font face, size, and color for the text field. var formatObj = new TextFormat(); formatObj.size = 16; formatObj.color = 0xC7FF9C; formatObj.font = "_sans"; formatObj.bold = true; totalOutput_txt.setTextFormat(formatObj); } // * EVENT HANDLERS * // Code executed when button 1 is pressed. choice1_btn.onRelease = function () { // Call answer(), which records the user's choice // and advances the quiz to the next question. this._parent.answer(1); }; // Code executed when button 2 is pressed. choice2_btn.onRelease = function () { this._parent.answer(2); }; // Code executed when button 3 is pressed. choice3_btn.onRelease = function () { this._parent.answer(3); };

    improving the data structure

    quiz code is now quite clean

    but the data handling is awkward

    each user choice and each correct answer require a variable

    answer() function code increases with each question

    consider the code required to record answers in a 10-question quiz:

    // Record the user's answer to this question. if (currentQuestion == 1) { q1answer = choice; } else if (currentQuestion == 2) { q2answer = choice; } else if (currentQuestion == 3) { q3answer = choice; } else if (currentQuestion == 4) { q4answer = choice; } else if (currentQuestion == 5) { q5answer = choice; } else if (currentQuestion == 6) { q6answer = choice; } else if (currentQuestion == 7) { q7answer = choice; } else if (currentQuestion == 8) { q8answer = choice; } else if (currentQuestion == 9) { q9answer = choice; } else if (currentQuestion == 10) { q10answer = choice; }

    now imagine a 100-question quiz!

    problems with the code:

  • time consuming to create
  • error prone
  • working with lists of information

    the data in the quiz can be treated as lists of information:

  • the list of user answers
  • the list of correct answers
  • to handle these lists more efficiently use arrays

    the anatomy of an array

    an array is a list of data values

    this code assigns string values to two variables:

    fruit1 = "oranges"; // A single string value fruit2 = "apples"; // Another string value

    this code creates an array to store both values:

    var fruitList = ["oranges", "apples"];

    two ways to create an array:

  • array literal
  • ["item1", "item2"]

  • array constructor:
  • new Array("item1", "item2")

    in ActionScript, arrays can contain any kind of data

    here's an array with both strings and numbers:

    shoppingList = ["oranges", 5, "apples", 2];

    array elements

    each item stored in an array is called an element

    each element's position in the array is its index

    indices start at 0

    for example, here are the indices for shoppingList:

    0: "oranges" 1: 5 2: "apples" 3: 2

    the number of elements in an array is called its length

    for example, the shoppingList's length is 4

    retrieving an element's value

    to get an element's value, use this syntax:

    theArray[theElementIndex]

    for example:

    var numberOfOranges = shoppingList[1];

    or use variables instead of numbers to specify the element index

    for example:

    var index = 3; // Set numApples to 2 var numberOfApples = shoppingList[index];

    the element index can also be calculated:

    // Set numberOfApples to 2 var numberOfApples = shoppingList[5 - 2];

    setting an element's value

    to set an element's value, use this syntax:

    theArray[theElementIndex] = theValue;

    for example:

    // Make an array var cities = ["Toronto", "Montreal", "Vancouver", "Tokyo"]; // cities is now: ["Toronto", "Montreal", "Vancouver", "Tokyo"] // Set the value of the array's first element // cities becomes ["London", "Montreal", "Vancouver", "Tokyo"] cities[0] = "London"; // Set the value of the array's fourth element // cities becomes ["London", "Montreal", "Vancouver", "Hamburg"] cities[3] = "Hamburg";

    or:

    var i = 1; // Set the value of element i // cities becomes ["London", "Prague", "Vancouver", "Hamburg"] cities[i] = "Prague";

    looping through an array's elements

    use a loop to systematically process the contents of an array

    this code reports the location of the element with the value "hip hop":

    // Create an array var soundtracks = ["electronic", "hip hop", "pop", "alternative", "classical"]; // Check each element to see if it contains "hip hop" for (var i = 0; i < soundtracks.length; i++) { trace("now examining element: " + i); if (soundtracks[i] == "hip hop") { trace("the location of 'hip hop' is index: " + i); break; } }

    array methods

    an array is an object with methods to manage its elements

    the push() method adds one or more elements to the end of an array

    for example:

    // Create an array with 2 elements var menuItems = ["home", "quit"]; // Add an element // menuItems becomes ["home", "quit", "products"] menuItems.push("products"); // Add two more elements // menuItems becomes ["home", "quit", "products", "services", "contact"] menuItems.push("services", "contact");

    the pop() method removes the last element of an array

    for example:

    var numbers = [56, 57, 58]; numbers.pop(); // numbers is now 56, 57 trace(numbers)

    the unshift() method adds one or more elements to the beginning of the array

    for example:

    // Create an empty array (notice the use of the Array constructor) var flashVersions = new Array(); // Add an element flashVersions[0] = 5; // Add another element, bumping the previous 0 element up flashVersions.unshift(4); // flashVersions is now [4, 5] // Add two elements at once flashVersions.unshift(2,3); // flashVersions is now [2, 3, 4, 5]

    the shift() method removes an element from the beginning of an array

    for example:

    var sports = ["hackey sack", "snowboarding", "inline skating"]; sports.shift(); // Now ["snowboarding", "inline skating"] sports.shift(); // Now ["inline skating"]

    other methods perform various array manipulations:

  • sort and reverse reorder the elements in an array
  • splice() removes or adds elements from any part of an array
  • slice() and concat() create new arrays based on existing arrays
  • toString() and join() convert arrays to strings
  • a little more fun

    time for some more visual experiments

  • a random pattern generator (see randomPattern-01.swf through randomPattern-03.swf in /examples/visuals folder)
  • a mouse follower (see moveTowards.swf in /examples/visuals folder)
  • using arrays in quiz v3

    update the quiz to track answers with arrays

    we'll make changes to initialization code and functions

    but answer button event handler code will not change

    quiz v3, initialization

    except for line 1, initialization code has completely changed

    line 1, stop the movie at question 1:

    stop()

    next, q1answer and q2answer are replaced by userAnswers array:

    var userAnswers = new Array();

    likewise, correctAnswer1 and correctAnswer2 are replaced by correctAnswers array:

    var correctAnswers = [3, 2];

    using correctAnswers, we can calculate the number of questions in the quiz:

    var numQuestions = correctAnswers.length;

    if the number of questions in correctAnswers changes, numQuestions updates automatically!

    quiz v3, answer() function

    quiz v3's answer() has the same duties as v2's answer():

  • record the user's choice
  • advance the quiz to either: a) the next question, b) the end results screen
  • so the function skeleton is the same:

    function answer (choice) { }

    quiz v3, recording the user's choice

    this time, the choice is stored in userAnswers instead of q1answer:

    userAnswers.push(choice);

    quiz v3, asserting that the code works

    once again, we assert that the code works

    but this time, currentQuestion is based on the number of questions answered so far:

    var currentQuestion = userAnswers.length;

    and the user's answer is the last element in the userAnswers array

    the index of the last element in an array is always one less than the array's length:

    theArray[theArray.length - 1]

    so here's our new debugging code:

    trace("Question " + currentQuestion + ". The user answered: " + userAnswers[userAnswers.length - 1]);

    quiz v3, advancing the quiz

    quiz advancing in v3 is like v2 with one exception...

    ...the currentQuestion is not incremented

    the userAnswers array length indicates the current question automatically

    // If we're on the last question... if (currentQuestion == numQuestions) { // ...go to the quiz end frame. gotoAndStop("quizEnd"); // And grade the user. gradeUser(); } else { // ...otherwise, go to the next question frame. this.gotoAndStop("q"+ (currentQuestion + 1)); }

    quiz v3, gradeUser()

    v3's gradeUser() has the same duties as v2's gradeUser():

  • calculate user's score
  • display score on screen
  • display code has not changed

    only score calculation code has changed

    old code:

    for (var i = 1; i <= numQuestions; i++) { if (eval("q" + i + "answer") == eval("correctAnswer" + i)) { totalCorrect++; } }

    new code:

    for (var i=0; i < numQuestions; i++) { if(userAnswers[i] == correctAnswers[i]) { totalCorrect++; } }

    note that new loop starts at 0 because array indices start at 0

    quiz v3, final code

    here's the final code for quiz v3:

    // Stop the movie at the first question. stop(); // =================== // INIT QUIZ VARIABLES // =================== // Create an array to contain user's answers. var userAnswers = new Array(); // Create an array to contain each question's correct answer. var correctAnswers = [3, 2]; // Create a convenience variable to store the number of // questions in the quiz. var numQuestions = correctAnswers.length; // ===================== // CREATE QUIZ FUNCTIONS // ===================== // Function: answer() // Desc: Registers the user's answers to quiz questions and // advances the quiz through its questions. // Params: choice The user's answer for the current question. function answer (choice) { // Add the current answer to the list of user answers. userAnswers.push(choice); // Create a convenient variable to store the number // of the current question. var currentQuestion = userAnswers.length; // Display the question and answer in the Output window for debugging. trace("Question " + currentQuestion + ". The user answered: " + userAnswers[userAnswers.length-1]); // If we're on the last question... if (currentQuestion == numQuestions) { // ...go to the quiz end frame. gotoAndStop("quizEnd"); // And grade the user. gradeUser(); } else { // ...otherwise, go to the next question frame. this.gotoAndStop("q"+ (currentQuestion + 1)); } } // Function: gradeUser() // Desc: Tallys the user's score at the end of the quiz. function gradeUser() { // Report that we're about to grade the quiz in the Output window. trace("Quiz complete. Now grading..."); // Create a local variable to track the // number of questions user answered correctly. var totalCorrect = 0; // Count how many questions the user answered correctly. // For each question... for (var i=0; i < numQuestions; i++) { // If the user's answer matches the correct answer. if(userAnswers[i] == correctAnswers[i]) { // Give the user a point. totalCorrect++; } // Display the correct answer and the user's answer // in the Output window for debugging. trace("Question " + (i + 1) + ". Correct answer: " + correctAnswers[i] + ". User's answer: " + userAnswers[i]); } // Display the final score in the Output window for debugging. trace("User's score: " + totalCorrect + "/" + numQuestions); // Create an onscreen text field do display the user's score. this.createTextField("totalOutput_txt", 1, 150, 200, 200, 20); // Show the user's score in an onscreen text field. totalOutput_txt.text = "Your final score is: " + totalCorrect + "/" + numQuestions; // Customize the font face, size, and color of the text field. var format = new TextFormat(); format.size = 16; format.color = 0xC7FF9C; format.font = "_sans"; format.bold = true; totalOutput_txt.setTextFormat(format); } // ================================= // DEFINE QUIZ BUTTON EVENT HANDLERS // ================================= // Code executed when button 1 is pressed. choice1_btn.onRelease = function () { // Call answer(), which records the user's choice // and advances the quiz to the next question. this._parent.answer(1); }; // Code executed when button 2 is pressed. choice2_btn.onRelease = function () { this._parent.answer(2); }; // Code executed when button 3 is pressed. choice3_btn.onRelease = function () { this._parent.answer(3); };

    building blocks

    for our last bit of fun, we'll combine our earlier mouse follower and random pattern experiments

    remember that complex programs are just like lots of little simple programs combined

    see moveAway-01.swf through moveAway-07.swf in /examples/visuals

    summary

    code is fun, even when you only know a little!

    you can learn a lot quite quickly

    best way to improve: play and experiment