Book HomeActionScript: The Definitive GuideSearch this book

2.5. Variable Scope

Earlier we learned how to create variables and retrieve their values using variables attached to a single frame of the main timeline of a Flash document. When a document contains multiple frames and multiple movie clip timelines, variable creation and value retrieval becomes a little more complicated.

To illustrate why, let's consider several scenarios.

2.5.1. Scenario 1

Suppose we were to create a variable, x, in frame 1 of the main timeline. After creating x, we set its value to 10:

var x;
x = 10;

Then, in the next frame (frame 2), we attach the following code:

trace(x);

When we play our movie, does anything appear in the Output window? We created our variable in frame 1, but we're attempting to retrieve its value in frame 2; does our variable still exist? Yes.

TIP

When you define a variable on a timeline, that variable is accessible from all the other frames of that timeline.

2.5.2. Scenario 2

Suppose we create and set x as we did in Scenario 1, but instead of placing the variable-setting code on frame 1 directly, we place it on a button in frame 1. Then, on frame 2, we attach the same code as before:

trace(x);

Does Scenario 2 also work? Yes. Because x is attached to our button, and our button is attached to the main timeline, our variable is indirectly attached to the main timeline. We may, therefore, access the variable from frame 2 as we did before.

2.5.3. Scenario 3

Suppose we create a variable named secretPassword on frame 1 of the main timeline. When the movie plays, the user must guess the password in order to gain access to a special section of the movie.

In addition to declaring secretPassword on frame 1, we create a function that compares the user's guess to the real password. Here's our code:

var secretPassword;
secretPassword = "yppah";

function checkPassword( ) {
  if (userPassword == secretPassword) {
    gotoAndStop("accessGranted");
  } else {
    gotoAndStop("accessDenied");
  }
}

Suppose we ask the user to enter her password on frame 30. She enters a password into an input text field variable named userPassword, which we compare to our secretPassword variable using the checkPassword( ) function on frame 1. If our password-checking code is defined on frame 1, but userPassword isn't defined until frame 30, does the userPassword variable exist when we call our checkPassword( ) function?

The answer, again, is yes. Even though userPassword is defined on a later frame than our checkPassword( ) function, it is still part of the same timeline.

TIP

Any variable declared on a timeline is available to all the scripts of its timeline for as long as that timeline exists.

2.5.4. Variable Accessibility (Scope)

The three scenarios presented earlier explore issues of scope. A variable's scope describes when and where the variable can be manipulated by the code in a movie. A variable's scope defines its life span and its accessibility to other blocks of code in our scripts. To determine a variable's scope, we must answer two questions: (a) how long does the variable exist? and (b) from where in our code can we set or retrieve the variable's value?

In traditional programming, variables are often broken into two general scope categories: global and local. Variables that are accessible throughout an entire program are called global variables . Variables that are accessible only to limited sections of a program are called local variables . Though Flash supports conventional local variables, it does not support true global variables. Let's find out why.

2.5.5. Movie Clip Variables

As we saw in the three earlier scenarios, a variable defined on a timeline is available to all the scripts on that timeline -- from the first frame to the last frame -- whether the variable is declared on a frame or a button. But what happens if we have more than one timeline in a movie, as described in Scenario 4?

2.5.5.1. Scenario 4

Suppose we have two basic geometric shapes, a square and a circle, defined as movie clip symbols.

On frame 1 of the square clip symbol, we set the variable x to 3:

var x;
x = 3;

On frame 1 of the circle clip symbol, we set the variable y to 4:

var y;
y = 4;

We place instances of those clips on frame 1, layer 1 of the main timeline of our movie and name our instances square and circle.

First question: If we attach the following code to frame 1 of the main movie timeline (upon which square and circle have been placed), what appears in the Output window? Here's the code:

trace(x);
trace(y);

Answer: Nothing appears in the Output window. The variables x and y are defined on the timelines of our movie clips, not our main timeline.

TIP

Variables attached to a movie clip timeline (like that of square or circle) have scope limited to that timeline. They are not directly accessible to scripts on other timelines, such as our main movie timeline.

Second question: If we were to place the trace(x) and trace(y) statements on frame 1 of our square movie clip instead of frame 1 of our main movie timeline, what would appear in the Output window?

Answer: The value of x, which is 3, and nothing else. The value of x is displayed because x is defined on the timeline of square and is therefore accessible to the trace( ) command, which also resides on that timeline. But the value of y, which is 4, doesn't appear in the Output window because y is defined in circle, which is a separate timeline.

You can now see why I said that ActionScript doesn't support true global variables. Global variables are variables that are accessible throughout an entire program, but in Flash, a variable attached to an individual timeline is directly accessible only to the scripts on that timeline. Since all variables in Flash are defined on timelines, no variable can be guaranteed to be directly accessible to all the scripts in a movie. Hence, no variable can legitimately be called global.

To prevent confusion, we refer to variables attached to timelines as timeline variables or movie clip variables. However, it is possible to simulate global variables using the Object class. To create a variable that is available on all timelines, use the following statement:

Object.prototype.myGlobalVariable = myValue;

For example:

Object.prototype.msg = "Hello world";

This technique (and the reason it works) is discussed under Section 12.5.4.4, "The end of the inheritance chain" in Chapter 12, "Objects and Classes".

2.5.6. Accessing Variables on Different Timelines

Even though variables on one timeline are not directly accessible to the scripts on other timelines, they are indirectly accessible. To create, retrieve, or assign a variable on a separate timeline, we use dot syntax, a standard notation common to object-oriented programming languages such as Java, C++, and JavaScript. Here's the generic dot syntax phrasing we use to address a variable on a separate timeline:

movieClipInstanceName.variableName

That is, we refer to a variable on another timeline using the name of the clip that contains the variable, followed by a dot, then the variable name itself. In our earlier scenario, for example, from the main timeline we would refer to the variable x in the square clip as:

square.x

Again, from the main timeline, we refer to the variable y in the circle clip as:

circle.y

We can use these references from our main movie timeline to assign and retrieve variables in square like this:

square.z = 5;       // Assign 5 to z in square
var mainZ;          // Create mainZ on the main timeline
mainZ = square.z;   // Assign mainZ the value of z in square

However, with just the clip.variable syntax alone, we can't refer to variables in square from our circle clip. If we were to put a reference to square.x on a frame in circle, the interpreter would try to find a clip called square inside of circle, but square lives on the main timeline. So, we need a mechanism that lets us refer to the timeline that contains the square clip (in this case, the main timeline) from the circle clip. That mechanism comes in the form of two special properties: _root and _ parent.

2.5.6.1. The _root and _ parent properties

The _root property is a direct reference to the main timeline of a movie. From any depth of nesting in a movie clip structure, we can always address variables on the main movie timeline using _root, like this:

_root.mainZ       // Access the variable mainZ on the main timeline
_root.firstName   // Access the variable firstName on the main timeline

We can even combine a reference to _root with references to movie clip instances, drilling down the nested structure of a movie in the process. For example, we can address the variable x inside the clip square that resides on the main movie timeline, as:

_root.square.x

That reference works from anywhere in our movie, no matter what the depth of clip nesting, because the reference starts at our main movie timeline, _root. Here's another nested example showing how to access the variable area in the instance triangle that resides on the timeline of the instance shapes:

_root.shapes.triangle.area

Any reference to a variable that starts with the _root keyword is called an absolute reference because it describes the location of our variable in relation to a fixed, immutable point in our movie: the main timeline.

There are times, however, when we want to refer to variables on other timelines without referring to the main timeline of a movie. To do so, we use the _ parent property, which refers to the timeline upon which the current movie clip instance resides. For example, from code attached to a frame of the clip square, we can refer to variables on the timeline that contains square using this syntax:

_ parent.myVariable

References that start with the keyword _ parent are called relative references because they are resolved relative to the location of the clip in which they occur.

Returning to our earlier example, suppose we have a variable, size, defined on the main timeline of a movie. We place a clip instance named shapes on our main movie timeline, and on the shapes timeline we define the variable color. Also on the shapes timeline, we place a clip named triangle, as shown in Figure 2-1.

Figure 2-1

Figure 2-1. A sample movie clip hierarchy

To display the value of the variable color (which is in the shapes clip) from code attached to the timeline of triangle, we could use an absolute reference starting at the main timeline, like this:

trace(_root.shapes.color);

But that ties our code to the main movie timeline. To make our code more flexible, we could instead use the _ parent property to create a relative reference, like this:

trace(_ parent.color);

Our first approach (using _root) works from a top-down perspective; it starts at the main timeline and descends through the movie clip hierarchy until it reaches the color variable. The second approach (using _ parent) works from a bottom-up perspective; it starts with the clip that contains the trace( ) statement (the triangle clip), then ascends one level up the clip structure where it finds the color variable.

We can use _ parent twice in a row to ascend the hierarchy of clips and access our size variable on the main timeline. Here we attach some code to triangle that refers to size on the main movie timeline:

trace(_ parent._ parent.size);

Using the _ parent property twice in succession takes us up two levels, which in this context brings us to the main timeline of the movie.

Your approach to variable addressing will depend on what you want to happen when you place instances of a movie clip symbol on various timelines. In our triangle example, if we wanted our reference to color to always point to color as defined in the shapes clip, then we would use the _root syntax, which gives us a fixed reference to color in shapes. But if we wanted our reference to color to refer to a different color variable, depending on which timeline held a given triangle instance, we would use the _ parent syntax.

2.5.6.2. Accessing variables on different document levels

The _root property refers to the main movie timeline of the current level (i.e., the current document), but the Flash Player can accommodate multiple documents in its document stack. The main timeline of any movie loaded in the Player document stack may be referenced using _leveln, where n is the level number on which the movie resides. Level numbers start with 0, such as _level0, _level1, _level2, _level3, and so on. For information on loading multiple movies, see Chapter 13, "Movie Clips". Here are some examples showing multiple-level variable addressing:

_level1.firstName         // firstName on level1's main timeline
_level4.ball.area         // area in ball clip on level4's main timeline
_level0.guestBook.email   // email in guestBook clip on level0's timeline

WARNING

When addressing variables across movie clip instance timelines using dot syntax, make sure that you have named your clip instances on the Stage and entered the names correctly when referring to them in your code. If your instances are not named, your code will not work even if it is otherwise syntactically correct. Unnamed instances and misspelled instance names are extremely common sources of problems.

2.5.6.3. Flash 4 versus Flash 5 variable access syntax

The Flash 4-style slash-colon constructions such as /square:area have been superseded by Flash 5's dot syntax, a much more convenient way to refer to variables and timelines. The old syntax is deprecated and no longer recommended. Table 2-1 shows equivalencies between Flash 4 and Flash 5 syntax when addressing variables. See Appendix C, "Backward Compatibility", for other syntactical differences.

Table 2-1. Flash 4 Versus Flash 5 Variable Addressing Syntax

Flash 4 Syntax

Flash 5 Syntax

Refers to . . .

/
_root

Movie's main timeline

/:x
_root.x

Variable x on movie's main timeline

/clip1:x
_root.clip1.x

Variable x in instance clip1 on movie's main timeline

/clip1/clip2:x
_root.clip1.clip2.x

Variable x in instance clip2 within instance clip1 within the main movie timeline

../
_ parent

Timeline upon which the current clip resides (one level up from current clip timeline) [1]

../:x
_ parent.x

Variable x on timeline upon which the current clip resides (one level up from current clip timeline)

../../:x
_ parent._ parent.x

Variable x on timeline that contains the clip that contains the current clip (two levels up from current clip timeline)

clip1:x
clip1.x

Variable x in instance clip1, where clip1 resides on the current timeline

clip1/clip2:x
clip1.clip2.x

Variable x in instance clip2, where clip2 resides within clip1, which, in turn, resides on current timeline

_level1:x
_level1.x

Variable x on the main timeline of a movie loaded onto level 1

_level2:x
_level2.x

Variable x on the main timeline of a movie loaded onto level 2

[1] The "current clip timeline" is the timeline that contains the code with the variable reference.

2.5.7. Movie Clip Variable Life Span

Earlier, we said that the scope of a variable answers two questions: (a) how long does the variable exist? and (b) from where in our code can we set or retrieve the variable's value? For movie clip variables, we now know the factors involved in answering the second question. But we skipped answering the first question. Let's return to it now with one final variable-coding scenario.

2.5.7.1. Scenario 5

Suppose we create a new movie with two keyframes. On frame 1, we place a clip instance, ball. On the ball timeline, we create a variable, radius. Frame 2 of our main timeline is blank (the ball instance is not present there).

From frame 1 of the main movie timeline, we can find out the value of radius using this code:

trace(ball.radius);

Now the question: If we move that line of code from frame 1 to frame 2 of the main timeline, what appears in the Output window when our movie plays?

Answer: Nothing appears. When the ball clip is removed from the main timeline on frame 2, all its variables are destroyed in the process.

TIP

Movie clip variables last only while the clip in which they reside is present on stage. Variables defined on the main timeline of a Flash document persist within each document but are lost if the document is unloaded from the Player (either via the unloadMovie( ) function or because another movie is loaded into the movie's level).

A variable's life span is important when scripting movies that contain movie clips placed across multiple frames on various timelines. Always make sure that any clip you're addressing is present on a timeline before you try to use the variables in that clip.

2.5.8. Local Variables

Movie clip variables are scoped to movie clips and persist as long as the movie clip on which they are defined exists. Sometimes, that's longer than we need them to live. For situations in which we need a variable only temporarily, ActionScript offers variables with local scope (i.e., local variables), which live for a much shorter time than normal movie clip variables.

Local variables are used in functions and older Flash 4-style subroutines. If you haven't worked with functions or subroutines before, you can skip the rest of this section and come back to it once you've read Chapter 9, "Functions".

Functions often employ variables that are not needed outside the function. For example, suppose we have a function that displays all of the elements of a specified array:

function displayElements(theArray) {
   var counter = 0;
   while(counter < theArray.length) {
      trace("Element " + counter + ": " + theArray[counter]);
      counter++;
   }
}

The counter variable is required to display the array but has no use thereafter. We could leave it defined on the timeline, but that's bad form for two reasons: (a) if counter persists, it takes up memory during the rest of our movie; and (b) if counter is accessible outside our function, it may conflict with other variables named counter. We would, therefore, like counter to die after the displayElements( ) function has finished.

To cause counter to be automatically deleted at the end of our function, we define it as a local variable. Unlike movie clip variables, local variables are removed from memory (deallocated ) automatically by the interpreter when the function that defines them finishes.

To specify that a variable should be local, declare it with the var keyword from inside your function, as in the preceding displayElements( ) example.

Take heed though; when placed outside of a function, the var statement creates a normal timeline variable, not a local variable. As shown in Example 2-4, the location of the var statement makes all the difference.

Variables within functions need not be local. We can create or change a movie clip variable from inside a function by omitting the var keyword. If we do not use the var keyword, but instead simply assign a value to a variable, Flash treats that variable as a nonlocal variable under some conditions. Consider this variable assignment inside a function:

function setHeight( ){
   height = 10;
}

The effect of the statement height = 10; depends on whether height is a local variable or movie clip variable. If height is a previously declared local variable (which it is not in the example at hand), the statement height = 10; simply modifies the local variable's value. If there is no local variable named height, as is the case here, the interpreter creates a movie clip (nonlocal) variable named height and sets its value to 10. As a nonlocal variable, height persists even after the function finishes.

Example 2-4 demonstrates local and nonlocal variable usage.

Example 2-4. Local and Nonlocal Variables

var x = 5;                         // New nonlocal variable, x, is now 5
function variableDemo( ){
   x = 10;                         // Nonlocal variable, x, is now 10
   y = 20;                         // New nonlocal variable, y, is now 20
   var z = 30;                     // New local variable, z, is now 30
   trace(x + "," + y + "," + z);   // Send variable values to Output window
}
variableDemo( );   // Call our function. Displays: 10,20,30
trace(x);         // Displays: 10 (reassignment in our function was permanent)
trace(y);         // Displays: 20 (nonlocal variable, y, still exists)
trace(z);         // Displays nothing (local variable, z, has expired)

Note that it is possible (though confusing and ill-advised) to have both a local and a nonlocal variable that share the same name within a script but have different scopes. Example 2-5 shows such a case.

Example 2-5. Local and Nonlocal Variables with the Same Name

var myColor = "blue";
function hexRed( ){
   var myColor = "#FF0000";
   return myColor;
}
trace(hexRed( ));   // Displays: #FF0000 (the local variable myColor)
trace(myColor);    // Displays: "blue" (setting the local variable,
                   // myColor, to #FF0000 did not affect the nonlocal version)

2.5.8.1. Local variables in subroutines

Although functions are the preferred mechanism for producing portable code modules, Flash 5 still supports Flash 4-style subroutines. In Flash 4, a subroutine could be created by attaching a block of code to a frame with a label. Later, the subroutine could be executed remotely via the Call action. But in Flash 4, any variable declared in a subroutine was nonlocal and persisted for the lifetime of the timeline on which it was defined. In Flash 5, you can create local variables in subroutines the same way we created them in functions -- using the var statement. However, variables defined with var in a subroutine are created as local variables only when the subroutine is executed via the Call function. If the script on the subroutine frame is executed as a result of the playhead simply entering the frame, the var statement declares a normal timeline nonlocal variable. Regardless, the more modern functions and local function variables should be used instead of subroutines.



Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.