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:
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:
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:
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:
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 command5
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:
logic in a program
we make millions of basic decisions in our daily lives
for example, when crossing the road we decide:
a program must make similar decisions based on the state of its environment
for example:
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:
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:
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:
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:
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 screenquestion 2
: for the second question screenquestion 1
: for the first question screenchoice buttons
: for the answer buttonshousing
: for the background and instructionsadd 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:
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:
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
labels
layer, set the label to init
labels
layer, add a blank keyframelabels
layer, set the label to q2
labels
layer, add a blank keyframelabels
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:
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:
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 clickedonRelease
is the name of the eventeventHandlerFunction
is the function that should run when the button is clickedthe 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:
q1answer
new code introduced:
choice1_btn
(the button that broadcast the event)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:
q2answer
(instead of q1answer
)ending the quiz
quiz is mostly functional
to finish it, we'll:
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:
to fix these problems, we'll:
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:
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...
if the current question is not the last 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:
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:
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:
working with lists of information
the data in the quiz can be treated as lists of information:
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:
["item1", "item2"]
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 arraysplice()
removes or adds elements from any part of an arrayslice()
and concat()
create new arrays based on existing arraystoString()
and join()
convert arrays to stringsa little more fun
time for some more visual experiments
randomPattern-01.swf
through randomPattern-03.swf
in /examples/visuals
folder)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()
:
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()
:
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