ActionScript Objects


Now that you know what objects are, we're ready to start talking about the kinds of objects that are available in ActionScript. We're going to cover some of these completely, leaving no property or method untouched, while we're going to skim over others. The objects that are not useful to us in game programming are described, but the actual use of those objects is left to you and the ActionScript Dictionary.

Objects can be divided into five primary groups: core, media, movie, client/server, and authoring, with core and movie being the most important. Each group of objects can either be global or instance objects, and I describe each separately. This hierarchy of objects can be seen in Figure 6.2. Note that only the core and movie object groups are shown in Figure 6.2.

click to expand
Figure 6.2: The core and movie objects are broken into two groups ” global objects and instance objects.

Core Objects (ECMA)

The first group of objects is called core objects. The ECMA-262 standard requires these objects. Table 6.1 contains a list of all of them.

 
Table 6.1: Core Object List

Name

Global/Instance

Description

Arguments

Instance

Holds arguments that are passed to a function

Array

Instance

Holds multiple variables in one block

Boolean

Instance

Has two values: true and false

Date

Instance

Holds date and time information

Error

Instance

Holds errors used by try and catch

Function

Instance

Encapsulates a function within an Object

Math

Global

Stores mathematical functions and constants

Number

Instance

Holds numerical data

Object

Instance

Serves as basic object type from which all other objects are derived

String

Instance

Holds character data

System

Global

Holds system configuration, security settings, and access to the Clipboard

Global Core Objects

There is only one global object in the core grouping: the Math object. You've already seen the Math object used in earlier chapters, but let's look at everything it has for us.

The Math Object

As you know, the Math object is used to hold mathematical constants and methods . Table 6.2 lists the constants.

 
Table 6.2: Properties of the Math Object

Constant

Value

Description

E

2.71828

The base of the natural logarithm

LN2

0.69314718055994528623

The natural logarithm of 2

LN10

2.3025850929940459011

The natural logarithm of 10

LOG2E

1.442695040888963387

Base-2 logarithm of the constant Math.E

LOG10E

0.43429448190325181667

Base-10 logarithm of the constant Math.E

PI

3.14159265358979

The ratio of the circumference of a circle to its diameter

SQRT1_2

0.707106781186

One divided by the square root of 2

SQRT2

1.414213562373

The square root of 2

These constants are defined for us because operations such as logarithm and square root are slow operations. In mathematics, things like the square root of 2 and the natural log of 2 come up so often that you don't want to calculate them at run-time. Instead, you can refer to the constant that is given for you, as in the following script:

 trace(Math.LN2); 

Now let's look at the methods available to us in Math , which are listed in Table 6.3.

 
Table 6.3: Methods of the Math Object

Method

Description

abs

Yields the absolute value of the number given

acos

Yields the arc-cosine of the number given

asin

Yields the arc-sine of the number given

a1tan

Yields the arc-tan of the number given

atan2

Acts as an alternative form of arc-tan, taking two arguments instead of a ratio

ceil

Yields the closest integer that is greater than or equal to the number given

cos

Yields the cosine of the number given

exp

Yields the constant Math.E raised to some power

floor

Yields the closest integer that is less than or equal to the number given

log

Yields the natural log of some number

max

Returns the greater of two numbers

min

Returns the lesser of two numbers

pow

Raises a number to a given power

random

Yields a random number greater than or equal to 0 and less than 1

round

Yields either the max or the min of a number, depending on which is closer

sin

Yields the sine of a number

sqrt

Yields the square root of a number

tan

Yields the tangent of a number

You should use either the reference panel or the ActionScript Dictionary to look up each of these methods. I'm going to talk about many of them, and you've seen some before, but you need to become familiar with all of them. Some of them, such as round , max , min , floor , and similar, are too easy to devote time to. The ActionScript Dictionary can fill in any holes in my coverage.

Some of these methods are worth mentioning here. Let's look at some of those now.

The Trigonometric Functions (sin, cos, tan, asin, acos, atan, atan2)

All these functions are used in trigonometry, or the study of triangles. Triangles have some special properties such that you can relate the lengths of their sides to the measure of the three angles they form.

This concept will be particularly useful to us in the future, when our games become a bit more complex. This is not the time or place to discuss trigonometry, though, so I'm going to leave that until Chapter 8, "Advanced Timing and Trigonometry: Blow 'Em Up ," when we'll have time to get into it. For now, simply realize that these seven functions allow us to perform the basic trigonometric functions.

The Exponent Functions (pow, exp, sqrt, log)

The exponent functions are used to calculate exponents. You've already seen pow , which raises a number to a power. And you have certainly seen sqrt , which calculates the square root of a number. However, you might not be familiar with exp and log .

The exp function raises the constant Math.E to a given power. Therefore, it's really the same as the following line:

 Math.pow(Math.E, myVar); 

where myVar is the argument you would normally have handed to exp . The exp function is a shorthand version of the preceding script.

The log function calculates the natural logarithm of a number. A full explanation of logarithms is beyond the scope of this book, but I will briefly summarize logarithms for you with the following script:

 x = Math.exp(32); trace(Math.log(x)); 

The output is 32 because the natural logarithm is the inverse of the exponential function. In other words, log undoes what exp does.

These logarithmic functions are not common in Flash, but they can come up in some advanced physics, so you should at least know where to find them.

The rest of the Math methods are pretty self explanatory, and you've seen many of them before. For example, round rounds a decimal number to the nearest integer. Make sure you understand what all of the remaining methods in Math do before moving on.

Instance Core Objects

Because only one global object, Math , is in the core group, that leaves all the rest as instance objects. Let's look at each one individually.

The Arguments Object

This object is technically an instance object because instances of it are created, but you do not create them yourself. Instead, Flash creates an instance of the Arguments object for you inside any function call and names it arguments . You might be thinking, "But we can name arguments in Flash, so why do we need this?" The answer is that you can define functions that take a potentially infinite number of arguments in Flash. You can't name an unknown number of arguments, so you can use the variable length argument array instead. We're going to create a function that uses this property, but first recall the Math function called max . This method takes two arguments ”numbers ”and returns the greater of the two. What if we have a many numbers and we want to find the maximum of them all? We could use max calls in a big loop to do it, or we could create a new function altogether that takes a variable number of arguments and runs the loop for us. Consider the following script:

 function multi_max(){       //assign temporary maximum value       var tmax = arguments[0];       //loop for all arguments       for(var i=1; i<arguments.length;++i){             //find max between temp max and next argument             tmax = Math.max(tmax,arguments[i]);       }       return tmax; } 

Now we have a function that can take any number of arguments and return the maximum of them. You can test the script with the following line:

 trace(multi_max(5,33.2,0,-234.3,523,123)); 
The Array Object

You've already seen this object in detail, so it's unnecessary to cover it again here. Refer to Chapter 5 if you are unclear on arrays.

The Boolean Object

This is a wrapper for the boolean primitive type. Encapsulating primitives in objects might seem silly, but sometimes it's useful. In Chapter 9, we'll look at ways to define new methods and properties for these wrapper objects that can be useful to us. For now, let's just look at the predefined members of the Boolean object.

The Boolean object defines no properties and only two methods. Those methods are toString and valueOf . Let's look at each one.

Caution  

Don't be confused between the wrappers ( Boolean, String , and Number ) and the number conversion functions that are defined globally in Flash (also named Boolean , String , and Number ).The former are objects and the later are functions. Consider this script:

  x = "true";   b = Boolean(x);  

This script creates a primitive boolean named b ; it does not create a Boolean wrapper object. Note the lack of a new keyword. The call to the conversion function Boolean() has nothing to do with the Boolean wrapper object. The correct script for creating a Boolean wrapper is as follows :

  x = "true";   b = new Boolean(x);  
The Boolean.toString Method

This method returns a string containing either true or false depending on the value contained by the Boolean object. Consider the following script:

 b = new Boolean(true); trace(b); trace(typeof(b)); s = b.toString(); trace(s); trace(typeof(s)); 

First we create a new object reference, b , and assign it a new Boolean instance that is initialized to a value of true . Then we trace both b and the type of b . These outputs yield true and object respectively. After that, we call the toString method on b and assign it to a new variable called s . We conclude by tracing both s and the type of s . These yield true and string respectively.

Caution  

Don't be confused by the fact that we can trace a wrapper object and get its value. That's the intended behavior, but it makes the difference between a primitive and its corresponding wrapper object harder to see. Just be aware that although the following two traces have the same output, the elements that they trace are not the same:

  b = false;   bo = new Boolean(false);   trace(b);   trace(bo);  
The Boolean.valueOf Method

This function returns a boolean primitive containing the same value as the Boolean wrapper. It might seem strange to you, and you might wonder why you would use this function because simply referring to the Boolean gives you the same result, but think of it like this. When you use a Boolean where a boolean primitive is required, Flash automatically calls valueOf on the Boolean for you. Consider the following script:

 b = new Boolean(true); if(b){} 

In a circumstance like this, we're using a boolean inside a conditional if statement. That's the same as doing the following:

 b = new Boolean(true); if(b.valueOf()){} 

For that reason, you'll probably never call the valueOf function on a Boolean yourself; you'll let Flash call it for you.

The Number Object

Much like the Boolean wrapper for boolean primitive variables, the Number object wraps the primitive number type. Everything we talked about in regard to Boolean is also true of Number , but in addition to the two methods and one property present on Boolean , the Number object defines several more properties. Let's look at them now.

The Number.MAX_VALUE Property

This property represents the largest number that Flash can store. Anything larger than that does not fit inside a primitive number variable. The exact value of Number.MAX_VALUE is 1.79769313486231e+308, or 179769313486231 followed by 294 zeros. If you add anything to this value, it remains unchanged because the extra can't be stored. On the other hand, if you multiply Number.MAX_VALUE by anything greater than 1.0, the result is Infinity .

Caution  

Please note that the actual value of MAX_VALUE might be platform specific. In other words, depending on what OS your Flash player is running on, the actual maximum storable value might differ .

Caution  

Keep in mind that when you deal with very small and very large numbers, Flash can only handle a certain number of significant digits. For example, trace(Number.MAX_VALUE ==(Number.MAX_VALUE-1)) returns true because subtracting 1 from such a large number has no effect.

The Infinity Constant

When a number grows larger than the biggest number Flash can hold through a multiplication, Flash changes the value of the number to Infinity . That tells you that you're not able to store such a large number.

Don't be confused by the fact that Infinity is a value that a number can have. As far as Flash is concerned , Infinity is a numerical value. Even though it looks like a string to you and me, it's not. In fact, if you do something like trace(typeof(Infinity)); , you'll see that it outputs numbers.

The Number.POSITIVE_INFINITY Property

Another way to refer to the value of Infinity is to use the property Number.POSITIVE_INFINITY . Flash has two versions of the same number because the value of Infinity came before ActionScript changed over to the ECMA standard. Because ECMA requires the Number object and its POSITIVE_INFINITY property, these were added in Flash5, but the original Infinity constant still remains from the previous versions.

Both versions of Infinity are the same thing, as you can see by running the following line of script:

 trace(Number.POSITIVE_INFINITY); 

This script's output is Infinity .

The Number.MIN_VALUE Property

This property is similar to Number.MAX_VALUE except that it defines the smallest possible number that can be represented in Flash. By smallest, I mean closest to 0. The actual value of this constant is 4.94065645841247e-324, or .0000...<about 300 zeros here>...00000494065645841247. As you can see, it's quite small.

The Number.NEGATIVE_INFINITY Property

Similar to positive infinity, which is represented by Number.POSITIVE_INFINITY , this constant represents negative infinity. Flash actually evaluates Number.NEGATIVE_INFINITY as -Infinity , as you can see from the output of the following script:

 trace(Number.NEGATIVE_INFINITY); 
The Number.NaN Property

While we're on the subject of numbers, we should talk about the way Flash tells you that something is not a number. If you try to do some mathematical calculations on a string, Flash responds a globally defined constant called NaN that it uses to represent things that you ask for as a number but that Flash can't convert into a number for you.

Similar to the relationship between Infinity and Number.POSITIVE_INFINITY , there is relationship between the global constant NaN and Number.NAN . You can see this by looking at the output of the following script:

 trace(Number.NAN); 

As you might expect, the output is NaN .

The String Object

The final wrapper class we have in ActionScript is the String wrapper. It wraps, as you might guess, the string primitive. It works like Number and Boolean , but it doesn't have the numerical constants that Number has, and it defines some of its own properties and methods. The single property that String defines is called length , and it represents the length of the string wrapped in the String object.

In addition to this property, the String object defines several methods for us. Table 6.4 lists them.

 
Table 6.4: String Method List

Name

Description

substring

Returns a copy of a piece of a string using a starting index and an ending index. This function cannot work backward.

charAt

Returns the character at a given index in the string.

charCodeAt

Returns the Unicode character at a given index.

concat

Copies a second string onto the end of the first string.

fromCharCode

Converts ASCII values into characters .

indexOf

Searches a string for a substring and returns the index where it begins.

lastIndexOf

Searches a string for a substring from the end and returns the index where it begins. .

slice

Returns a copy of a piece of a string using a starting index and an ending index. This function can work backward.

split

Breaks up a string using a given delimiter and returns the pieces in an array.

substr

Returns a copy of a piece of a string using a starting index and a length.

toLowerCase

Returns a copy of the string with each character converted to lowercase.

toUpperCase

Returns a copy of the string with each character converted to uppercase.

These methods are useful for text processing, so let's look at them.

The String.charAt Method

Strings are a lot like arrays in that they contain a contiguous block of variables. All strings are indexed from 0 to length -1, and in fact, arrays are used as the implementation of strings in most programming languages. Therefore, it's logical to think about a string as an array of characters.

The charAt method works by accepting an index as an argument and returning the character that exists in that index location. It has the following general form:

 string  myString  .charAt(  index  ); 

As you can see, the function returns a string primitive. That's because there is no character type in ActionScript. Instead, a string primitive is returned containing the single character that occurs at the index given as an argument. Notice that the function is shown to be called on myString . That's because the String object is not global, so you instead call it on an instance of the object, as in the following script:

 s = new String("hello"); for(i=0;i<s.length;++i)      trace(s.charAt(i)); 

As you can see, we first create a new String named s and hand the string "hello" to the constructor. Then we loop, using s 's length property as our loop index. Inside the loop, we trace one character: the one at the loop index position. This essentially prints the string vertically in the output window with one character on each line, as in Figure 6.3.

click to expand
Figure 6.3: The charAt function prints each character in the string, one at a time.
The String.charCodeAt Method

This function returns a 16-bit representation of the character at a given index. String.charCodeAt works like charAt except that instead of giving you a string with the character inside it, charCodeAt gives you a number with the ASCII representation of that character. You can test the following script to see it in action. It's the same as the previous script with the charAt function changed to charCodeAt :

 s = new String("hello"); for(i=0;i<s.length;++i)      trace(s.charCodeAt(i)); 

Figure 6.4 shows this script in action.

click to expand
Figure 6.4: The string is printed one character at a time, but ASCII values are printed instead of the actual character.
The String.fromCharCode Method

This function might be confusing, so let me try to explain what's going on here. Even though the String object is an instance object and you call methods on instances of it, not all the methods of every instance object work that way. The String.fromCharCode method is an example of that.

This function is not called on an instance of a String object; instead, it's called on the global String object. The following is the general form of this method:

 string String.fromCharCode(  c1  [,  c2  ,  c3  ...]); 

As you can see, the function returns a primitive string (it's not capitalized), and it is called on the global String object. The following script shows an example of the use of String.fromCharCode :

 trace(String.fromCharCode(104,101,108,108,111)); 

This simply traces the string hello, built up from ASCII character codes. Notice the way the global String object is used when calling the fromCharCode method.

This function is used if you have several ASCII codes and you want to convert them into a string.

The String.concat Method

You've already seen a concat method with arrays, and this one is no different. It works by accepting a second string as its argument and copying that argument onto the end of the first string (the string that concat was called on). The newly created string is then returned:

 string  myString  .concat(  string1  [,  string2  ,  string3  ...]); 

Please note that the original string is unaffected. Also note that the method can take more than one argument. You can use concat to form a string from any number of other strings. This is demonstrated in the following example script:

 s = new String("hello "); t = new String("world "); m = new String("mom, I'm home "); trace(s.concat(t)); trace(s.concat(m,t,m,t,s,s)); 

In this script, we're creating three strings and then calling concat a couple of times. Notice that the second time, we're using the same String we called concat on as an argument. That's perfectly legal. You can see the output of this script in Figure 6.5.

click to expand
Figure 6.5: The concat method can be used to create a large string from several smaller strings.
The String.indexOf Method

This method searches a String for a specified substring. An index is given and the search begins there. The method returns the index of the first occurrence of the substring, which has the following general form:

 number  myString  .indexOf(  subString  [,  startIndex  ]); 

As you can see, the starting index is optional. If the string does not exist, -1 is returned. The following script is an example of this method's use:

 s = new String("hello world"); trace(s.indexOf("world")); 

The script's output is 6 because the String's index begins at 0 and the substring "world" first occurs at the seventh character, or index 6. Now look at a second example where a starting index is used:

 s = new String("world hello world"); trace(s.indexOf("world", 3)); 

This script's output is 12 because the search doesn't begin until index 3. That means the first occurrence of "world" is skipped and the first occurrence after the starting index is at the thirteenth character, or index 12.

Finally, let's see an example where the substring doesn't exist in the string:

 s = new String("world hello world"); trace(s.indexOf("fred")); 

In this example, the substring "fred" does not exist in the original String , so the number -1 is returned.

Note  

Strings are always case sensitive. "Fred" and "fred" are two different strings. When you are searching for a substring, it is important to have the case correct. If you want your search to be case insensitive, you should use one of the case converters that we'll cover in a bit to force the case to be either upper or lower.

The String.lastIndexOf Method

This method is the same as indexOf except that it searches a string for a substring and returns the index of the last occurrence. The lastIndexOf method has an identical general form to indexOf , so I won't give that here. Instead, let's just look at an example:

 s = new String("world hello world"); trace(s.lastIndexOf("world")); 

Again, the output is 12, but this time there is no starting index. Because this method returns the index of the last instance, the second "world" string's starting index is returned. Again, if the substring doesn't exist, -1 is returned.

Another thing to note is that this method works backward on the string. If you specify a start index, it begins at that index and searches toward the beginning of the string. Consider the following example:

 s = new String("world hello world"); trace(s.lastIndexOf("world", 5)); 

The output here is 0 because the second argument, 5, tells Flash to begin looking for the last occurrence at index 5. That means Flash begins at the end of the String but skips over all the characters after index 5. When the search starts at index 5, it looks for the last occurrence of the string, searching toward the beginning of the string. Consider a final example for clarity:

 s = new String("hi hi hi"); trace(s.lastIndexOf("hi", 5)); 

The output of this example is 3 because of the following. The second argument, the starting index, is 5. Flash begins looking for the last instance before that index. It moves left and finds what is the second instance of the "hi" substring in the original String "hi hi hi", which has a starting index of 3.

The String.slice Method

Several methods are available for dealing with parts of strings. When you are doing text processing, it's common to extract parts of strings, so Flash defines several methods for you. Many of these methods do similar things but have different arguments for your convenience. Sometimes the differences are subtle, so let's look at each one individually.

We've seen two functions that return the index of a substring. Now we're going to look at several functions that return the actual substrings if given an index. It's like the reverse of the previous two methods.

The first function we want to look at is called slice . It has the following general form:

 string  myString  .slice(  start  [,  end  ]); 

As you can see, this method returns a string. It requires one argument but can take two optionally . The first is the starting index to begin slicing, and the second, optional argument is the ending index for the slice . If you do not supply the second argument, slice continues to the end of the string. The following example illustrates this method in action:

 s = new String("Hello world, I'm happy to be here!"); trace(s.slice(6)); trace(s.slice(6, 11)); trace(s.slice(11, 6)); 

As you can see from the output in Figure 6.6, the first slice starts at index 6 and goes until the end of the string. The second slice starts at index 6 but stops at index 11. Notice that the eleventh location contains a comma in the original String , but the comma is not printed in the output. That's because slice stops just before the ending index.

click to expand
Figure 6.6: Slice is used to extract a substring from a String , given a starting index.

The third call reverses the arguments and puts a higher index first, which causes the output to be blank. That is the intended behavior for slice , and you might think I'm wasting my breath telling you about it, but some of the other methods behave differently and that will be the major difference with this method, so keep it in mind.

There is one final example of slice that I want to go over. If you use a negative number for one or both of the arguments, you get behavior demonstrated by the following script:

 s = new String("Hello world, I'm happy to be here!"); trace(s.slice(6, -2)); trace(s.slice(-6, 2)); trace(s.slice(-6, -1)); 

As you can see in the output shown in Figure 6.7, a negative argument causes slice to count from the end of the string and not the beginning. This works with either argument or both. However, the second example in which the first argument is negative and the second is positive is an unusual search and would not normally be done even though it is technically possible.

click to expand
Figure 6.7: A negative argument to slice causes Flash to count from the end of the string, not the beginning.
The String.substr Method

This method is almost identical to slice . The difference is that instead of taking an ending index as its second argument, substr takes a length. In other words, substr returns a substring starting from the first argument's index, and going through the element that is length spaces after it. Its general form then, is as follows:

 string  myString  .substr(  start  [,  length  ]); 

Again, the second parameter is optional, and if it is omitted, substr goes until the end of the String . Let's look at some examples:

 s = new String("Hello world, I'm happy to be here!"); trace(s.substr(6)); trace(s.substr(6, 2)); trace(s.substr(6, -2)); trace(s.substr(-6, 2)); 

Okay, there's a lot going on here. First notice the third call to substr . It uses a negative second argument. In slice , that causes Flash to index from the end of the String and not the beginning. But in substr , because the second argument is a length, or number of characters to grab, a negative value results in an empty string, as seen in Figure 6.8.

click to expand
Figure 6.8: The substr method is similar to the slice method, except that the second argument is a length and not an index.

Furthermore, the fourth call to substr uses a negative first argument, and that works. Because the first argument is an index and not a length, Flash indexes from the end of the String .

The String.substring Method

Yes, I know, this method's name is similar to the last one ”probably too similar if you ask me. Nevertheless, substring is its name and what follows is its general form:

 string  myString  .substring(  from  [,  to  ]); 

The way this method works is a bit tricky, so let's go slowly. The method gives you a substring as a return value and the arguments are indexes. The first argument, from , represents the beginning index to grab from. If this first argument is negative, 0 is used. The second, and optional, argument is called to , and it indicates the index of the character just prior to the end of the substring. If this argument is negative, 0 is used. Finally, if the first argument is less than the second argument, the numbers are automatically swapped before the method is executed. Let's look at some examples:

 s = new String("Hello world, I'm happy to be here!"); trace(s.substring(6)); trace(s.substring(6, 2)); trace(s.substring(6, -2)); trace(s.substring(-6, 2)); trace(s.substring(-6, -2)); trace(s.substring(2, 6)); 

As you can see in the output shown in Figure 6.9, the function behaves as described. Notice the fifth trace, however. In this one, both arguments are negative, so Flash uses 0 for both. In that case, because the arguments are equal, an empty substring is returned.

click to expand
Figure 6.9: The substring method is named in a similar way to substr but behaves much like slice .
Tip  

As you can probably see, any of the three methods slice , substr , or substring can be used to extract substrings from a given String object. The only reason to choose one over the others is convenience. Sometimes you need to do some numerical conversion to use one method, but the default behavior of another makes that conversion unnecessary. In general, however, any of these three methods can extract a substring.

The String.split Method

This method isn't used very often, but it can be very useful occasionally. Before I explain split , take a look at its general form:

 Array  myString  .split(  delimiter  [,  limit  ]); 

The first thing to notice is that the function returns an array, not a string or number. The second thing is two arguments ”one that is required and one that is optional. The function works as follows. The split method returns an array of substrings. It creates the substrings by breaking up the String object based on some character it uses as a break point, or delimiter. The second argument, limit, is used to limit the number of substrings that are extracted and placed into the array.

The function split is the opposite of join . join takes an array and makes a string by placing a specified string between each element of an array. split takes away a specified string and uses it as a separator for producing an array. These two are often used together even though they are logically parts of different objects.

Let's look at split in action:

 s = new String("Hello world. I'm happy to be here!"); myArray1 = s.split(""); myArray2 = s.split("", 2); myArray3 = s.split("o"); myArray4 = s.split("happy"); trace(myArray1.toString()); trace(myArray2.toString()); trace(myArray3.toString()); trace(myArray4.toString()); 

In this example, we're creating four arrays by calling split several times on our String object. Then we use the toString method of the Array objects to output the values in each array so that you can see what's in them. The output of this script can be seen in Figure 6.10.

click to expand
Figure 6.10: The split method returns an array of substrings, created using a delimiter handed in as an argument to split .

Notice that the first split uses the string " " as its delimiter. That causes the array to contain substrings that are broken off from the main String by the space character. The second split call uses the same delimiter but this time imposes a limit of 2 with the second argument, and the third split uses the delimiter string "o" to break up the String . The final split uses the delimiting string "happy" .

Note  

The output from Array . toString uses commas to separate the elements. Don't be tricked into thinking that the array elements contain all those commas shown in Figure 6.10; they are simply separators from the toString method.

The String.toLowerCase and String.toUpperCase Methods

You've seen these methods used before. These simple and self-explanatory methods return a string that has each element converted to either upper or lowercase, depending on which method is called. The following example should be more than adequate to demonstrate these methods, the output of which is given in Figure 6.11:

 s = new String("Hello world, I'm happy to be here!"); trace(s.toUpperCase()); trace(s.toLowerCase()); 
click to expand
Figure 6.11: The toUpperCase and toLowerCase functions are used to convert strings into all uppercase or all lowercase.

That concludes our sortie into the String object. As you can see, it's quite complex and gives us a great deal of functionality. In the future, we'll employ some of these methods when we start gathering information from the user for things like highscore boards . Let's move along and finish the rest of the instance core objects.

The Date Object

This object contains a host of methods designed to give you information about the local date and time. Things like daylight savings time are accounted for, depending on the operating system the user is running.

The specifics of the Date object are somewhat unnecessary for us as game programmers, and I won't waste pages talking about them. The ActionScript Dictionary does a fairly good job of describing Date , and I'll leave it that task. It's enough to say that you create a new Date object instance and then call methods on that instance. Consult the ActionScript Dictionary if you need more information on date processing in Flash.

The Function Object

This one is really going to bake your noodle. It's an object that allows us to encapsulate a function. In a similar way to the wrapping of a boolean, string, or number, a Function object can wrap a function for us.

The use of Function is obscure, and I have yet to find a need for it personally . That doesn't mean there isn't a purpose for it, but it's a difficult concept to understand. Macromedia's documentation doesn't do Function much justice , so I'll discuss it here just so you know how it works, in case you find yourself in need of a Function wrapper.

You instantiate the Function object just like any normal instance object: with new and a constructor call. Consider the following script:

 f = new Function(function(){trace("hi");}); 

We now have an anonymous function wrapped in a Function object. We can call a couple of methods on this new object. Let's look at both.

The Function.call Method

The call method is used to call a function. Yes, I know, we already have a way to call a function, but this gives us another way. It's essentially a way to get an object to call one of its methods on another object. In other words, if we define a method on an object a and we want to call it as if it were a method of object b, we could use the call method to do so. The general form of call is as follows:

 returnValue  myFunction  .call(  thisObject  [,  argument1  ,  argument2  ...]); 

The function is called on a Function object instance. Its return type is shown to be returnValue because it can be anything the function returns: numbers, booleans, objects, functions, void, and so on. The first argument to call is the object upon which the function should operate . That argument is followed by the individual arguments to call the function with. There can be 0 or more arguments, as usual. Consider the following script:

 f = new Function(function(amt){this._x += amt}); attachMovie("ball"," ball",1); attachMovie("square"," square",2); ball.slide = f; ball.slide.call(square, 100); 

This is some really strange code, so let's look closely. First we instantiate a new Function object called f and give it an anonymous function in the constructor, which moves it a variable number of pixels to the right (adds the argument amt to the this._x ).

Then we create two new movie clip instances with attachMovie . One is a ball and one is a square . It is assumed that these exist as symbols in the library and have been exported for ActionScript.

Finally, we attach the function f to the ball clip under the method name slide . Now comes the tricky part. We call a method of the Function object called call , which calls the function as a method of the first argument. In this case, that's square . Even though the function adds to this._x and the function is attached as a method of ball , because we used the call method and supplied a reference to the square clip as its first argument, it's actually the square clip that moves to the right, as seen in Figure 6.12.

click to expand
Figure 6.12: The call method can call a method of one object as if it were a method of another object.

This should seem quite strange to you. In fact, you'll probably never have need for the call method, and if you do, you should seriously check your design. This Function object probably wouldn't even exist in ActionScript if ECMA-262 didn't require it.

Caution  

The number conversion functions Boolean() , String() , and Number() return primitives, but the other instance objects can be instantiated by simply omitting the new keyword. Consider this:

  f = Function(); trace(typeof(f));   b = Boolean(true); trace(typeof(b));  

In this script, f is an object ”namely a Function object. B is not be a Boolean object; instead it is a boolean primitive. That's because the former is a shortcut way to write f = new Function() ; but the latter is a conversion function. There are no shortcut ways to create Boolean , String , and Number wrapper objects like this.

If you don't fully grasp this method, don't worry about it. We're not going to use it. I'm only explaining it because you'll have a hard time finding a good explanation else-where.

The Function.apply Method

This is yet another function that allows you to call a function on an object as if it were a method of that object without the function actually being attached to the object. In the call method, we did a similar thing, except that the arguments were given individually to the call method. In the apply method, the arguments are given as an array. This is useful when you need to use call , but the number of arguments is variable. In a case like that, you can use apply and hand in any arguments in an array. The general form of apply is as follows:

Tip  

Having a method of one object call itself as if it were a method of another object is probably bad design. Therefore, the call method should be used when it is the only choice. However, I can't think of a situation where it would be.

 returnType  myFunction  .apply(  thisObject  ,  argumentsObject  ); 

This is identical to Function.call except that instead of each argument being its own parameter to the call, the apply method uses what it calls an argumentsObject to give arguments to the function. The argumentsObject is just an array containing all the arguments.

In addition to the apply and call methods, the Function object defines one property: prototype . This property is used in inheritance, which is discussed in detail in Chapter 9.

The Object Object

This particular object is extremely powerful. Many aspects of it affect every other object type in Flash, and its importance cannot be overstated. Much of Objec t's power comes from inheritance, and as you know, that's not covered until Chapter 9. Even without that, there are some neat things we can do with Object . First let's instantiate one:

 o = new Object(); 

Now let's attach some properties to it:

 o._x = 100; o._y = 100; o._xscale = 50; 

Because o is an object and not a movie clip, the properties _x , _y , and _xscale don't do anything special. (They don't mean something like they do on a movie clip.) We can now use this object as an initialization object in our attachMovie calls. If you recall in Chapter 4, "Creating Instances Dynamically: The Button Menu," when I gave the general form for attachMovie , you could give an optional fourth argument in your attachMovie call. Now that we can create an object, we're ready to do that. After setting up the o object in the previous script, we can do this:

 attachMovie("ball"," ball",1,o); 

Flash takes every property of the object o and makes properties of ball that match. That means, of course, that ball has its _x changed to 100, its _y changed to 100, and its _xscale changed to 50. This allows us fast and easy initialization of movie clips. In addition, because o is still a valid object, it can be used again in the initialization of another ball clip.

Implicit Object Instantiation

Remember when we created an array without using the new keyword? That's possible with several instance objects, including the Object object. The general form of implicit object instantiation follows:

 {  p1  :  value1  [,  p2  :  value2  , ...  pn  :  valuen  ]} 

Essentially, it's a code block set off with curly braces and containing a set of properties. This property list is comma separated, with each property name being assigned its value with a colon . That means we could create an object implicitly with the following script:

 o = {_x:100, _y:100, _xscale:50, _yscale:50}; 

The preceding script is identical to the following:

 o = new Object(); o._x = o._y = 100; o._xscale = o._yscale = 50; 

I use both types in my script, depending on what's more intuitive and convenient at the time.

That concludes the sections on core objects. We're ready to move on to our next big group of objects now: the Movie group.

Movie Objects

In addition to the core objects that ECMA requires, Flash defines a set of objects that are specific to ActionScript only. They are grouped under the heading Movie Objects in the reference panel and ActionScript Dictionary. Table 6.5 lists them.

 
Table 6.5: Movie Object List

Name

Type

Description

Accessibility

Global

Tests accessibility options on the user's computer

Button

Instance

Serves as the template for all button symbols in Flash

Context Menu

Instance

Used to add menu items to the right mouse context menu

Color

Instance

Checks and sets the color of an instance on the stage

Key

Global

Refers to different keys on the keyboard

LocalConnection

Instance

Sets up a connection between .swfs for communication

Mouse

Global

Refers to different properties of the mouse

MovieClip

Instance

Creates new instances on the stage

MovieClipLoader

Instance

Contains events that respond to the loading progress of a movie

PrintJob

Instance

Manages an improved API for printing content at run-time

Selection

Global

Changes the text field that is currently highlighted

Stage

Global

Accesses and changes properties of the stage

TextField

Instance

Creates a new text field on the stage

TextFormat

Instance

Changes the properties of a text field on the stage

TextSnapshot

Instance

Holds a snapshot of static text in a movie clip

As you can see, several of these movie objects are defined globally and several are instantiated. Let's look at each group individually.

Global Movie Objects

Just like the global core objects, global movie objects are not instantiated. Instead you reference the static properties and methods of these classes by directly referring to the class name. Recall that the global core object was Math , and we called methods on it using its name with dot notation. The global movie objects are the same, so let's look at them one at a time.

The Accessibility Object

This simple object has only one method. Its purpose is to determine whether the user has a screen reader enabled. People who have reading or eye disabilities use these devices to improve their ability to view Web pages. As a developer, you can take this into consideration by building content that behaves differently if the user has enabled such a device. The Accessibility object tells you if this is the case. Its lone method, isActive , has the following general form:

 boolean Accessibility.isActive(); 

The method returns true if a screen reader is on and false if it is not.

The Key Object

The Key object is designed to help us monitor the user's keyboard presses. Each key on the keyboard is assigned a number, called a key code, and you can test to see if any key is currently pressed using its key code. Further, the Key object defines a set of properties (constants) used for some of the key codes that are not letters or digits, such as the arrow keys, page up, spacebar, control, and so on. A full list of each key and its corresponding key codes is given in Appendix B, "Key Object Bindings." The constants that Key defines are listed in Table 6.6.

 
Table 6.6: Key Constants

Name

Key

Key Code

Key.END

End

35

Key.BACKSPACE

Backspace

8

Key. CAPSLOCK

Caps Lock

20

Key.CONTROL

Either Ctrl

17

Key.DELETEKEY

Delete

46

Key.DOWN

Down Arrow

40

Key.ENTER

Enter

13

Key.ESCAPE

Esc

27

Key.HOME

Home

36

Key.INSERT

Insert

45

Key.LEFT

Left Arrow

37

Key.PGDN

Page Down

34

Key.PGUP

Page Up

33

Key.RIGHT

Right Arrow

39

Key.SHIFT

Either Shift

16

Key.SPACE

Spacebar

32

Key.TAB

Tab

9

Key.UP

Up Arrow

38

In addition to these constants, Key defines a set of methods for us. Table 6.7 lists them.

 
Table 6.7: Key Methods

Name

Description

isDown

Tests to see whether a given key is down

addListener

Adds an event listener for onKeyUp or onKeyDown

removeListener

Removes a listener event that was previous attached

getAscii

Retrieves ASCII code for the last key pressed or released

getCode

Retrieves the key code for the last key pressed

isToggled

Tests to see whether the Caps Lock and Num Lock keys are enabled

As we investigate these methods, both the Key object and its use will become clear. Let's talk about the most important method in the batch first.

The Key.isDown Method

This method tells us if a key is currently pressed. In Flash 5, this method was used extensively in game development as a way to trap the keyboard events. You would have an enterFrame handler somewhere that would test every turn to see if any of the keys that affect the player were pressed. That usually included the arrow keys for movement, the spacebar for shooting, and so on. Flash MX gives us a better way to do this, but we still need to talk about the old way first. The isDown method is simple, and it has the following general form:

 boolean Key.isDown(  keycode  ); 

You call the method on the Key object because it's a global object. You hand in a key code as the argument to tell Flash which key to test for, and the method returns a boolean indicating whether the key is down. The following example prints a message to the screen when the A key is pressed:

 this.onEnterFrame = function(){      if(Key.isDown(65))           trace("Pressing 'A'!"); } 

Notice that we are using the literal number 65 in our call to isDown . It's unfortunate that each letter doesn't have a constant, but after Chapter 9, we'll be able to fix that. For now, you must refer to Appendix B for a list of the key codes for different letters, numbers, and numeric keypad keys.

The following example uses some of the Key constants to test for the user pressing the arrow keys. Notice that we use the constants defined on the Key object ( UP , DOWN , LEFT , and RIGHT) , but we don't have to. We could have used a literal number like we did previously:

 this.onEnterFrame = function(){      if(Key.isDown(Key.UP))           trace("up!");      if(Key.isDown(Key.DOWN))           trace("down!");      if(Key.isDown(Key.LEFT))           trace("left!");      if(Key.isDown(Key.RIGHT))           trace("right!"); } 

This is simple enough, but the design has a major flaw. Suppose our game has 12 different keys that the user can press to do things in our game. That would mean we would need an onEnterFrame handler to deal with 12 separate tests every frame. One solution to that would be to use a timer and test every so many milliseconds . The problem with that is that if the user presses and releases the key quickly enough, you can miss the event completely. Fortunately, Flash MX gives us a new way to handle this. Let's look at it now.

Listeners

Chapter 4 listed most of the dynamic event handlers. I left a couple out so that we could talk about them here. Two important handlers that were omitted were onKeyUp and onKeyDown . I left them out because without listeners, these handlers can only be used with the concept of focus. I didn't want to talk about listeners or focus in Chapter 4, but now we're ready for one of the two: listeners. This is how listeners work.

You are already familiar with attaching event handlers such as onEnterFrame and onRelease to movie clips. But movie clips are not the only things that can have event handlers. Ordinary objects can have them as well, but they can't have just any handler. Instead, objects can have only a limited number of handlers, and you can't just attach them like you do with movie clips. First you attach them, but then you must register them to be a listener. This is done with special methods that are specific to the event you are trying to add. I know this sounds complicated, and it is, but some examples should help clear it up.

Key Listeners

The first listeners we're going to look at are used with the Key object. By using the Key object's addListener method, we can register any object instance to trap the onKeyUp and onKeyDown events. Let's see an example.

First we create an object that will become our listener. (It will have the handlers attached.)

 o = new Object(); 

Now we need to add a handler function to it:

 o.onKeyUp = function(){trace("key up!");} 

That's all we would have done if this were an onEnterFrame handler for a movie clip, but it's not. An object cannot have an event handler attached without also being registered as a listener for the type of event it wants to handle. This is done with a pair of methods defined on the Key object called addListener and removeListener .

Tip  

In a way, movie clips are listeners, too. The difference is that they don't have to be registered with an addListener call. Instead, all you have to do is attach the handler function and it works. No addListener call is required.

Note  

You don't have to use an Object as a Key listener; you can also use movie clips, buttons , text fields, and almost any other object type.

The Key.addListener Method

This function registers a new listener for the onKeyUp and onKeyDown events. It has the following general form:

 void Key.addListener(  listenerObject  ); 

After this call, listenerObject responds to onKeyUp and onKeyDown , assuming those events have been giving function definitions. Let's see the whole thing in action now:

 o = new Object(); o.onKeyUp = function(){trace("key up!");} Key.addListener(o); 

We create an object, define an onKeyUp handler, and then register the listener with the Key object's addListener method. When a key is released, the "key up" string is traced.

The Key.removeListener Method

If you want to remove the registration of a listener, you can use the removeListener method. It has the following general form:

 boolean Key.removeListener(  listenerObject  ); 

If the listenerObject has been registered as a listener with the Key object, this method removes it. removeListener returns true if it succeeds in removing it and false if it does not. The following line removes the listener that was created in the previous section:

 Key.removeListener(o); 

The beauty of this solution is that a listener event is only signaled when the user presses or releases a key. That way, you can test for a key only when you change state, saving you many tests compared to testing every frame with the onEnterFrame handler.

In this chapter's game, we register the user's spaceship movie clip as a listener for Key events because the user controls it with the keyboard. That allows us to handle the ship's movement easily.

The concept of listeners goes beyond the two handlers that work with the Key object, but we'll look at the other ones when we get to their registering objects. That includes the objects Selection , TextField , and Mouse . At this point, we need to finish the Key object's methods.

The Key.getAscii Method

This method simply returns the ASCII value of the key that was last pressed. It has the following general form:

 number Key.getAscii(); 

Try the following script to see it in action:

 o = new Object(); o.onKeyDown = function(){      trace(Key.getAscii()); } Key.addListener(o); 

With this script running, any key that is pressed causes the key's ASCII value to be printed. Test it and notice how the special keys that don't have ASCII values return a 0. The Shift and Ctrl keys are examples of this.

The Key.getCode Method

This method is identical to getAscii , but instead of an ASCII value, getCode returns the Flash key code for the key. Its general form is identical to the former, so I'll omit that and go right into an example:

 o = new Object(); o.onKeyDown = function(){       trace(Key.getCode()); } Key.addListener(o); 

We just change the getAscii call in the previous script to a getCode call. Notice how the special keys (such as Shift, Ctrl, and Backspace) now have values.

The Key.isToggled Method

This method tells you the state of the Caps Lock and Num Lock keys. The function has the following general form:

 boolean Key.isToggled(  keycode  ); 

The argument must be either the key code for the Caps Lock key (20) or the code for the Num Lock key on the numerical keypad (144).

The following script demonstrates isToggled :

 this.onEnterFrame = function(){      if(Key.isToggled(20))           trace("capslock down");      if(Key.isToggled(144))           trace("numlock is down"); } 

This script prints a message every frame if either of the two keys is enabled.

That concludes the Key object. It was a long one, but we'll use it quite a bit in the future. Now it's time to look at the rest of the global movie objects that are available to us.

The Mouse Object

The Mouse object does two things. First, it gives us a method to hide the mouse pointer, which allows us to display our own mouse pointer. Second, it allows us to register listeners that trigger on the mouse events onMouseUp , onMouseDown , and onMouseMove .

The Mouse methods are listed in Table 6.8.

 
Table 6.8: Mouse Methods

Name

Description

addListener

Registers an object as a listener for mouse events

hide

Hides the default mouse pointer

removeListener

Removes a registered listener

show

Displays the mouse pointer if it was previously hidden

The Mouse.hide Method

When you don't want to display the default mouse pointer, you can use this method to hide it. It has the following general form:

 void Mouse.hide(); 

If you call the hide method with no arguments, Flash stops displaying it. If you have a game in which you don't want a mouse pointer displayed, issue the following line of script to disable it:

 Mouse.hide(); 

Therefore, if you wanted to display your own mouse cursor, you could use the following script, assuming there is a symbol in the library called newMouse that has been exported for ActionScript:

 Mouse.hide(); attachMovie("newMouse"," newMouse",1); newMouse.onMouseMove=function(){      this._x = _xmouse;      this._y = _ymouse;} 

As you can see, we first hide the default mouse pointer with a call to Mouse.hide . Then we attach a new movie clip from our library to act as a new mouse pointer. Finally, we define an onMouseMove handler for the clip that updates the position of the new mouse pointer.

Because onMouseMove is only called when the mouse actually moves, this script runs less frequently than if we had used an onEnterFrame handler.

If you test this script, you'll see that the mouse pointer is actually moving somewhat sluggishly, much more so than the default mouse pointer did. That's because the default mouse pointer can be updated several times each frame, but because of the way Flash updates stage objects on the screen only once per frame, our mouse pointer is only updated once each frame instead of many times per frame like the default pointer did.

We can change that so that Flash updates the position of the new mouse pointer more than once per frame.

The updateAfterEvent Function

This function's main purpose is to allow the use of a custom mouse pointer. Because Flash only updates the screen coordinates of each clip on the stage once per frame, even if you update the coordinate properties of a clip five times in one frame, it does not appear to move until the next frame when it moves to the fifth point you gave it. By calling updateAfterEvent , you can force Flash to update multiple times per frame. The function has no return value and no arguments; therefore, just issue a call to it after you have changed something that must be able to update more than once per frame.

Try changing the display script given earlier by adding an updateAfterEvent call at the end of the onMouseMove handler, as I have done in the following script:

 Mouse.hide(); attachMovie("newMouse"," newMouse",1); newMouse.onMouseMove=function(){      this._x = _xmouse;      this._y = _ymouse;  updateAfterEvent();  } 

The mouse pointer should now move smoothly around the screen.

The Mouse.show Method

If you have hidden the mouse pointer and you want to display it again, you can use this method to do so. Mouse.show has no return type and no arguments, just like the hide method. The following script uses hide and show to change the display of the mouse pointer when the user clicks the mouse button:

 this.onMouseUp = function(){      if(hidden) Mouse.show();      else Mouse.hide();      hidden = !hidden; } 

We simply attach an onMouseUp handler to the _root timeline. Inside it, we are using a variable (scoped to the _root timeline) called hidden to monitor the state of the mouse pointer.

When the user clicks, the onMouseUp is called and if the pointer is currently hidden, we call show to display it. If, on the other hand, the pointer is not hidden, we call hide . Finally, we invert the value of hidden so that if it's currently true , it becomes false and vice versa.

Mouse Listeners

We've already seen a listener that can be registered with the Key object, but we're ready for another one now. The Mouse listener works exactly like the Key listener. You create an object, give it event handlers, and then register it with the Mouse object. The handlers that can be used with a Mouse listener include onMouseUp , onMouseDown , and onMouseMove .

Note  

Remember that movie clips can have the mouse events attached without being registered as listeners with Mouse . That's because movie clips are special and don't need registration. O88ther kinds of objects must be registered to receive onMouseUp , onMouseDown , or onMouseMove event handlers.

The Mouse.addListener and Mouse.removeListener Methods

These methods are identical to Key.addListener and Key.removeListener , so I will forgo the standard form and cut right to the example:

 o = new Object(); o.onMouseUp = function(){trace("object telling you about mouseUp");} o.onMouseDown=function(){trace("object telling you about mouseDown");} o.onMouseMove=function(){trace("object telling you about mouseMove");} Mouse.addListener(o); 

We create a new object, o , assign it three handler functions, and register it as a Mouse listener with addListener . Later, if we wanted to remove it as a listener, we could issue the following:

 Mouse.removeListener(o); 
The Selection Object

This object is used with the concept of focus to help in the creation of forms. In something like an e-commerce site, where the user is filling out several pages of forms, focus and the Selection object helps you create an easily navigated form engine.

Selection is a topic that isn't incredibly useful in game programming. As such, let's go ahead and skip over it for now. If you are interested in learning more about Selection, look in the ActionScript Dictionary under the heading "Selection."

Tip  

When you are entering data into text fields, only one can be active at a time. The text field that is currently active and accepting user input is said to have focus. The Selection object helps you handle focus in your text fields.

The Stage Object

This object allows you to do several things, including check the size of the stage, set the stage alignment, configure the way the stage is scaled, and register a listener for the onResize event. Use of this object results in some complications, so we'll need to proceed carefully . First let's look at the properties that are defined on the Stage object. They are listed in Table 6.9.

 
Table 6.9: Stage Properties

Name

Description

align

The alignment of the movie inside the browser window

height

The height of the movie in its window

width

The width of the movie in its window

scaleMode

The type of scaling currently applied to the movie

The Stage.scaleMode Property

When a Flash movie is played , it can be forced into a particular size by the HTML that it is embedded in. However, if you display the .swf file directly in a browser, the browser might scale it to the size of the browser window. You've certainly noticed that you can scale a movie while testing by changing the size of the window it runs in. The HTML determines this scaling, but you can override it with ActionScript.

The particular scale mode that you are using has an effect on the rest of the Stage properties, so8 we need to be careful about it. By default, the publish settings for the HTML set the scale mode to be showAll , but that's only 1 of 4 scale modes that you have to choose from. Table 6.10 lists all the possible scale modes that you have to choose from.

 
Table 6.10: Flash Scaling Modes

Scale Mode

Scaling

Cropping

Ratio Preserved

showAll

Yes

No

Yes

exactFit

Yes

No

No

noBorder

Yes

Yes

Yes

noScale

No

Yes

Yes

As you can see in Table 6.10, you need to consider three main criteria for each scale mode. The first is the scaling of each mode. Some modes cause your movie to scale up or down to fit the window better, and some don't. If scaling is on and the window is small, people will have a hard time seeing your text; in contrast, if the window is too large, the rendering can take too much CPU and your game can bog down. If scaling mode is off, the movie's size (in pixels) will remain fixed no matter what.

The second criterion to consider is cropping. Some modes allow your movie to get a piece sliced off it if the whole movie doesn't fit in the window. It's possible with cropping to have something on your stage that is not visible in the final movie because it's been cropped off the stage.

The third criterion to consider is the aspect ratio of the stage. When you define your stage size in your movie properties, you are giving it a ratio. If you define it to be 550 pixels wide by 400 pixels high, the aspect ratio is 550/400, 55/40, or 11/8. If the aspect ratio is preserved in a particular scale mode, then no matter what, the movie is not scaled such that the ratio of height to width changes. In other words, if it is scaled, both the height and width are scaled equally. On the other hand, if the ratio is allowed to change, as it is in the exactFit scale mode, things distort and become either fat or skinny depending on the window size that your movie is playing in.

Let's look at a description of each scaleMode one at a time with a short example script so you can test it. These modes are much easier to understand when you see the scaling happen.

The showAll Scale Mode

This is the default setting. When scaleMode is in showAll , the movie scales so that the entire thing is showing in the window but does not alter the ratio of width to height. Borders are added to either the width or the height when this scale mode is used so that the entire movie is always visible in the window with no cropping.

The exactFit Scale Mode

This setting causes the stage to scale to exactly match the window size. The ratio between width and height is not preserved, so your movie can be distorted with this mode. No cropping is necessary with this mode because the movie fits perfectly due to scaling.

The noBorder Scale Mode

This setting causes the stage to scale so that at least one of the dimensions is being shown fully. (Either the full width or the full height of the movie is being displayed.) The ratio of width to height is preserved, but some cropping must occur if the window's ratio does not match the movie's. The difference between noBorder and showAll is that showAll scales so that both width and height show and place borders on one or the other. The noBorder mode scales so that either the height or width is fully showing (whichever is closer) and then crops the remaining one. This mode is rarely useful because you get the worst of both worlds ”scaling and cropping.

The noScale Scale Mode

This setting does not allow scaling of the movie. The entire movie is visible only if the window is big enough to accommodate it. If not, cropping occurs. This is the only scale mode in which cropping can occur on both the height and the width at the same time. This is also the only mode that your movie can be in if you want to use the Stage listener event onResize .

Caution  

Unlike the other scaling modes, noScale is only available starting with the Flash 6 plug-in. The other scaling modes are available to all plug-ins.

To test these four modes, we can create a new movie and draw lines around the edges of the stage so that we can see where the stage is during testing and publish preview. We need to create a text field so that we can display current scale mode. (We could use trace for this, but that only works when testing, not publishing or publishing preview.) Add the following script:

 createTextField("tf",1,50,50,200,200); tf.text = Stage.scaleMode; 

This creates a text field dynamically with the createTextField method, which you'll learn about later in this chapter. It then sets the text to the value of the current scale mode ( showAll by default). Now we need a way to change the scale mode while the movie is running. How about pressing the spacebar? Let's set up a keyboard handler to cycle modes when the spacebar is pressed. Consider the following script as a solution:

 Key.addListener(tf); tf.onKeyDown = function(){       if(Key.getCode() == Key.SPACE){       } } 

We are registering our new text field ( tf ) as a listener for the Key object so that it responds to onKeyUp and onKeyDown messages.

Tip  

Because a TextField object we created with createTextField is an object (as are movie clips), you can attach handlers to it like any object. We could have created a new object, called o , and used it as a keyboard listener, but because we already have tf , why not use it?

At this point, all we have to do is fill in the block of code that goes with the statement if(Key.getCode() == Key.SPACE) . For each scaleMode , we want to change the text in our text field as well as shift into the next scaleMode . Consider the following switch statement:

 createTextField("tf",1,50,50,200,200); tf.text = Stage.scaleMode; Key.addListener(tf); tf.onKeyDown = function(){    if(Key.getCode() == Key.SPACE){  switch(Stage.scaleMode){   case "showAll":   tf.text = Stage.scaleMode = "exactFit";   break;   case "exactFit":   tf.text = Stage.scaleMode = "noBorder";   break;   case "noBorder":   tf.text = Stage.scaleMode = "noScale";   break;   case "noScale":   tf.text = Stage.scaleMode = "showAll";   break;   }  } } 

As you can see, we're switching on the current scaleMode , given by Stage.scaleMode . Then we have a case statement for each scaleMode . Inside, we update the text field's text and move on to the next scaleMode . If you test this script, you should be able to cycle through the scale modes using the spacebar. To see how each one differs , resize your exported .swf window. Play around with them to get a feel for them and know them by name. Figure 6.13 shows all four modes.

click to expand
Figure 6.13: By cycling through the scale modes, you can get a feel for them.
Tip  

If you set the Stage.scaleMode to anything other than the four valid values, the default showAll is used.

The Stage.height and Stage.width Properties

Both of these properties are read-only. Therefore, if you try to set one to a value, you fail. Stage.height and Stage.width are used when you want your code to respond to the size of the stage. This can be extremely powerful if you want your application to change its layout depending on how much room you have. The thing to realize is that these properties do not indicate scaling that might be applied to your movie. That means that if you have your movie, which was created at 550 — 400 pixels, inside a browser window that is scaling it up to 1100 — 800 pixels, the height and width of the stage are still reported at 550 and 400, respectively.

These height and width properties are designed to be used with the noScale scale mode only. They are fixed at their initial values when they're in any other mode. The following script demonstrates that, if it is added to the script from the previous section:

 this.onEnterFrame = function(){      trace("stage width: "+ Stage.width);      trace("stage height: "+ Stage.height); } 

As you can see, this simply prints the current stage width and height each frame. Now test your movie and cycle through the scale modes while resizing your window and keeping an eye on the Output panel. You should notice that no matter what you do, the width and height are locked at their starting values until you change to the noScale mode. In this mode, the stage height and width change each time you change the window size. In any other mode, the height and width don't budge. And even when you change the window size in noScale and change back to any other mode, the height and width revert back to their initial values.

The Stage Listener

You've already seen the Key and Mouse listeners, so this one should be easy. The Stage listener works just the same except that it listens for an onResize event. The onResize event is triggered whenever the stage is resized, but only when its scaleMode is set to noScale . If the movie is in any other mode, including the default showAll scale mode, the onResize is not triggered.

The use of this listener is just like the other listeners you've seen. All you have to do to set one up is create an object, attach an onResize handler function, and register it with the Stage object by using its listener registration function addListener .

The Stage.addListener and Stage.removeListener Methods

These are the two functions for registering and destroying listeners for the onResize event. They work just like the methods of the same name defined on Key and Mouse , so I won't go over general forms here. Let's just look at an example script:

 Stage.scaleMode = "noScale"; o=new Object(); o.onResize = function(){trace("width: "+Stage.width+" height: "+Stage.height);} Stage.addListener(o); 

As you can see, we do it like any other listener, with the exception of putting the movie into noScale mode. As I said, the onResize handler won't work in any other scale mode. Test this movie by resizing it during a test or publish preview.

The Stage.align Property

This property determines the alignment of the Flash movie inside the HTML page it's displayed in. This property, like the scaleMode property, can be set in the Publish settings for the HTML document. However, you can also override that in ActionScript if you want to. If you set align to any valid setting, your movie will respond. Table 6.11 lists the valid settings for align .

 
Table 6.11: Movie Alignment Settings

Value

Placement

"T"

Top center

"B"

Bottom center

"L"

Left center

"R"

Right center

"LT"

Left top

"TR"

Top right

"LB"

Left bottom

"RB"

Right bottom

You might notice that Table 6.11 is kind of messed up. That's a small error on Macromedia's part. Let me explain. You can set the movie to align into the top-left corner using either of the two strings "TL" or "LT" which, of course, stand for top left and left top, respectively. However, Flash converts "TL" into "LT" after you make the assignment because technically "TL" is not a valid value, but Flash knows what you mean. The bug comes from the fact that the values Flash converts into include "T", "B", "L", "R", "LT", "TR", "LB", and "RB". Notice two in particular, "LT" and "TR". They stand for left top and top right. That is clearly an inconsistent naming job, so be careful when using Stage.align .

Tip  

Not only is there an inconsistency with the alignment names, but the Stage.align property has a value "" until you set it once. That means that if you allow the HTML to set the alignment for you, you won't know what alignment has been set inside your movie. For that reason, it's usually best to set both the alignment and the scale mode using ActionScript instead of relying on an HTML page to do it for you.

Because this property is pretty simple, I'm going to adapt the script we used to toggle the scale mode so that it toggles the alignment instead. Consider the following:

  Stage.scaleMode = "noScale";  createTextField("tf",1,50,50,200,200); tf.text = Stage.align; Key.addListener(tf); tf.onKeyDown = function(){      if(Key.getCode() == Key.SPACE){           trace(Stage.align);           switch(Stage.align){                case "T": tf.text = Stage.align = "B"; break;                case "B": tf.text = Stage.align = "L"; break;                case "L": tf.text = Stage.align = "R"; break;                case "R": tf.text = Stage.align = "LT"; break;                case "LT": tf.text = Stage.align = "TR"; break;                case "TR": tf.text = Stage.align = "LB"; break;                case "LB": tf.text = Stage.align = "RB"; break;                case "RB": tf.text = Stage.align = "T"; break;                default : tf.text = Stage.align = "T";           }      } } 

As you can see, this is the same as before except we're using Stage.align instead of Stage.scaleMode everywhere. A set of case statements handles each of the modes, and the whole thing is attached to a text field that was registered as a Key listener. Figure 6.14 shows this script being tested .

click to expand
Figure 6.14: By cycling through alignments, you can get a feel for each.

I am using a default case because, like scaleMode , align contains a value of "" until you set it once.

Notice that we set the scale mode to noScale on the first line. That's not necessary for alignment to work, but it does allow you to more easily see what's happening when you change alignments. Using the default showAll mode causes the movie to scale up to fit the window, possibly hiding any alignment you might have applied.

That's it for the Stage object. It's not simple, but I think we've gotten to the bottom of it. From here, we have one more global movie object to talk about.

The System and Capabilities Objects

The System object is global, so you do not create instances of it. It has no methods and only one property. The property, called capabilities , refers to an instance of the Capabilities object that Flash has instantiated for you. You can use this object to gather information about the hardware and software your movie is being run on.

Note  

The Capabilities object is an instance object, but you do not create instances of it. Instead, Flash creates one instance for you for any given movie. It assigns this new Capabilities instance to the capabilities property of the System object. To access it, you type System.capabilites. myProperty ; where myProperty is the property you want to access.

Instance Movie Objects

Now that we've gone through all the global movie objects, it's time to look at the instance movie objects. As with core, these objects are instantiated using the new keyword and a constructor call. After you have a new instance, you can manipulate properties and call methods at your whim. Let's dig right in, shall we?

The Button Object

This is the encapsulation of a button symbol. You can attach handlers to it, alter its properties, and so on. The problem is that button symbols don't have timelines , so using Button objects is more limited than using MovieClip objects like we have in the past. For that reason, I'm not going to waste time explaining an object I will never use. Just be aware that this object exists, and if you want to, you can use it to dynamically attach button symbols.

The Color Object

This object allows you to alter the color of a movie clip. You create a new Color object instance using the movie clip you want as an argument to the Color object's constructor, which in turn creates a new Color object instance that is linked to a particular movie clip. You can then call methods of that Color instance to retrieve and alter the color of your clip. After they're created, there are four methods of the Color object that you can use. Table 6.12 lists them.

 
Table 6.12: Color Method List

Name

Description

getRGB

Retrieves the red, green, and blue values for a given movie clip

getTransform

Retrieves the red, green, blue, and alpha values of a given clip as well and their respective contrast values

setRGB

Changes the red, green, and blue values for a given movie clip

setTransform

Changes the red, green, blue, and alpha values for a given clip using a percentage plus an offset

The RGB Methods

The easiest way to change color values for a movie clip is by setting the red, green, and blue values with the getRGB and setRGB methods.

The problem is that these methods operate on hexadecimal input, which is something we haven't talked about. I don't want to spend too much time talking about hexadecimal number representation when I should be talking about Flash, so I'm going to keep this brief. You can find countless tutorials and explanations of this concept on the Web, so if my explanation is not detailed enough, feel free to supplement.

Decimal Number Representation

This is going to seem really easy to you because you've been doing it since elementary school, but bear with me.

In our conventional (decimal) representation of numbers, we use the digits 0, 1, 2, 3, 4, 5, 6, 7, 8, and 9 to express numbers. We start with 0 and increment until we get to 9. If we increment past 9, we are required to add a new digit, increment it to 1, and roll the original digit back to 0. In fact, we could write the numbers 0 through 20 using two digits each time, and we would have 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, and 20.

That's simple, right? Of course, it is.

Hexadecimal Number Representation

Hexadecimal representation is just another way of writing numbers, but instead of using 10 different symbols like we do in decimal representation, hexadecimal uses 16 symbols including 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, and F. When we count in hexadecimal, we begin with 0 and increment through F. When we increment past F, we add a new digit, increment it to 1, and roll the original digit back to 0. That means that the number 10 in hexadecimal actually represents the number 16.

When we write a number that is hexadecimal, the convention is that you prefix it with 0x, to signify to anyone reading it that you are using hexadecimal and not decimal representation. Some examples of two-digit hexadecimal numbers include 0x00, 0xFF, 0x12, 0xA5, and 0xD1.

Tip  

You might wonder why anyone in their right mind would use hexadecimal representation. In actuality, because computers use numbers built from 0s and 1s, hexadecimal matches up better than decimal. Consider this. If there is 1 bit that can be 0 or 1, you have two possible values. If you add a bit so that you now have two bits, you can have four possible values (00, 01, 10, 11). Each time you add a bit, the number of combinations doubles. If you have 8 bits, commonly called a byte, you have 256 possible values that you can represent. This can be easily represented by two hexadecimal digits because two hexadecimal digits can represent numbers from 0 to 255, which is exactly how many numbers can be represented by 8 bits (1 byte).

Tip  

It has been hypothesized that humans favor a 10-digit (decimal) number representation because we have 10 fingers and that's how most of us learned to count ”on our fingers.

Using hexadecimal numbers, we can specify many colors. A color is represented by a six-digit number, where the two place values on the left are red, the middle two are green, and the right two are blue. If you wanted to set a movie clip to be blue, for example, you would use the number 0x0000FF. If you wanted yellow, which is a combination of red and green, you would use 0xFFFF00. Keep in mind that FF here means 255.

The Color.getRGB Method

This method obtains the value and color modification you have placed on a movie clip. That means if you do not first alter a clip's color, this method returns 0. The value that is returned needs to be converted into hexadecimal representation so that the color values are separated into two-digit chunks . The getRGB method has the following general form:

 number  myColor  .getRGB(); 

However, the number you get out will be displayed as a decimal value (base 10). A decimal representation of a color won't give a someone many intuitions about the color because colors rely on base 16 to keep the place values straightened out. If you are just plugging the color back into a set RGB method, the decimal value will be fine. However, if you want to display the number in a meaningful way to your user, it is best to convert it to hexadecimal with the following script:

 myColor.getRGB().toString(16); 

The Number.toString method, when given a number as an argument, converts its output to whatever base is given. Because hexadecimal is a base-16 number system, we feed the number 16 into the toString method to get our output in hex.

Before this method can do us any good, we need to create a clip and alter its color. Then our RGB values correspond to the alterations we've made to our clip.

Tip  

The concept of base in a number system refers to the number of symbols any digit can have. In decimal, there are 10 symbols, so decimal is said to be base-10. And because hexadecimal has 16 symbols for each digit (0 “F), it can be called a base-16 number system.

The Color.setRGB Method

This method alters the color of a movie clip. It has the following general form:

 void  myColor  .setRGB(  0xRRGGBB  ); 

As you can see, there is no return type and there is one argument that I have named 0xRRGGBB . That represents a number in hexadecimal representation where the first two hex digits are the red color value, the second two are green, and the third two are blue, where each can take values from 0 “255, which is 00 “FF in hexadecimal. Figure 6.15 shows these fields.

click to expand
Figure 6.15: The first two hex digits are red, the next two are green, and the final two are blue.

Let's look at an example:

 attachMovie("ball"," ball",1, {_x:100,_y:100}); c = new Color(ball); c.setRGB(0x99AF0B); 

This changes the color of the clip to whatever color is represented by a red value of 99, a green value of AF, and a blue value of 0B. The actual color represented by these is dark yellow.

If you were to call the following getRGB method, it would work:

 trace(c.getRGB().toString(16)); 

The output would be 99AF0B, just like you made it. Figure 6.16 confirms this.

click to expand
Figure 6.16: The output of getRGB is unreadable unless you call toString(16 ) on its result.

The problem with this method is that constructing that big hexadecimal number is a pain. If you want to cycle the color of something between two shades, you can't do it easily ”and certainly not without a fair bit of bookkeeping. This method is really only good when you have a specific color value you know you want to change to. If you want to move your color slowly over time, use random colors or use colors that react to the user; you will be better served to use the transform methods instead of the RGB methods.

The Color Transform Methods

These methods give us a more powerful way to alter the color of a movie clip. The cost of this new power is an increase in complexity. Instead of two simple methods like RGB used, the transform methods for changing colors require the use of an extra object, much like the Color object. Let's look at each of the transform methods, and the way this works will become clear.

The Color.getTransform Method

This method returns to you an object that has properties defined that match the color of the movie clip in question. It has the following general form:

 object  myColor  .getTransform(); 

As you can see, the return type is an object, there are no arguments, and you call it on your Color object instance. If you have not applied color transforms, each property of the object returned is 0. Eight properties are defined on the object returned by getTransform , and they are listed in Table 6.13.

 
Table 6.13: Transform Object Properties

Name

Description

ra

Percentage of red currently applied to the clip (-100-100)

rb

Red color component value (0 “255)

ga

Percentage of green currently applied to the clip (-100-100)

gb

Offset for the green color component (0 “255)

ba

Percentage of blue currently applied to the clip (-100-100)

bb

Offset for the blue color component (0 “255)

aa

Percentage of alpha currently applied to the clip (-100-100)

ab

Offset for the alpha component (0 “255)

The object returned from getTransform has each of those eight properties defined on it and set to the currently transformed values. If no color transform has been applied, the offset is 0 and the contrast is 100.

You might be confused at this point. Seeing colors with more than just their component values is somewhat strange. In actuality, you can leave the contrast at 100 and use the component values to change the color to anything you could with setRGB . The contrast, however, gives us even more power when changing our clip colors.

For our experiments, we're going to leave the alpha at aa and ab . You can use this color-transforming technique to change the alpha of a clip, but I see no reason to do so. It's simpler to just change the _alpha property of the clip directly.

Tip  

Remember that the values you get from getRGB and getTransform are the values for the color you have transformed to, not the original color of the movie clip. It's impossible to determine what color a clip is when it comes in from the library; both the RGB and transform methods only tell you the values that you used to alter an existing clip's color.

The Color.setTransform Method

Now that we know what a color transform object is and how the properties work, it's time to do some color transformation. You simply create a new object, attach properties that correspond to the eight transform properties, give them values, and call setTransform , whose general form follows:

 void  myColor  .setTransform(  colorTransformObject  ); 

As you can see, the important thing here is that a colorTransformObject is handed in as an argument. Let's see an example now:

 attachMovie("ball"," ball",1,{_x:100,_y:100});myColor = new Color(ball); myTransform = new Object(); myTransform.rb = 25; myTransform.gb = 12; myTransform.bb = 255; myColor.setTransform(myTransform); 

We're using the setTransform method to change our ball clip this time. With these settings, the ball is blue. Notice that I'm only using rb , gb , and bb in this transformation. Assuming that the object we are color transforming is black, those three values represent the color components , so this transformation is the same as the following line:

 myColor.setRGB(0x190CFF); 

Notice that here, the color components are hexadecimal, but in the previous example, the numbers were given in decimal between 0 “255. Don't forget that you never use hexadecimal with setTransform , but you should always use it with setRGB .

The best way to get a feel for how all six color properties work in combination is to create a little application that lets us change the values to arbitrary amounts and then test them. You can also place a symbol on the stage and use the advanced color options to see the same effects without code. The values on the left are the percentages (a values), and the values on the right are the offsets (b values).

Tip  

Setting the percentagess to negative numbers inverts the colors in the movie clip, which can create some really cool effects.

I have developed a color transformation movie, seen in Figure 6.17, that you can use to easily change color values and see the results. On the CD in the Chapter 06 directory is a Flash source file called color transformer.fla. I strongly suggest that you test this movie to get a feel for what each property represents. You can also look at the code to see exactly how I'm doing things, although nothing in this movie is new to you with the exception of the calls to getTransform and setTransform . Because this movie has a lot of details with no new concepts, I'm not going to dump or explain the code here. If you are interested in how this movie works, check out what I'm doing in the .fla.

click to expand
Figure 6.17: A color transform application is a good way to get a feel for the transform parameters.
Tip  

When I am using color transforms on more than one movie clip, I attach new color objects to the myColor property of each clip. That way, each color object is accessible through the movie clip that it relates to. Remember when I made buttons that any movie clip that contained a single text field was named myText so that it would be easy to remember? It's the same with colors. Therefore, if I have a clip called mc , which will be color transformed, its color object will be mc.myColor .

The MovieClip Object

This tried-and-true object has been our focus since Chapter 2, "Flash ActionScript". Unlike most instance objects, you don't create a MovieClip by using new with a constructor call. Instead, you use attachMovie . Yes, that's right; the MovieClip object is the same old thing you've been using all along. We've used several of the properties and methods that are defined on MovieClip , but let's look at the complete list now.

The MovieClip Properties

The properties of movie clips are special. Instead of only being a variable that can be set and read as needed, movie clips can also affect elements on the stage. As we've seen in previous chapters, setting the value of a movie clip's _y property can actually move the movie clip. Let's look at the many properties available to us with movie clips, starting with Table 6.14.

 
Table 6.14: MovieClip Properties

Name

Description

_accProps

Gets or sets accessibility properties

_alpha

Changes the amount of transparency a clip has

_currentframe [*]

Represents the number of the frame that the clip's playhead is currently over

_droptarget [*]

Indicates a path to the highest clip that the registration point of a dragged movie clip intersects

enabled

Indicates whether this button movie clip is enabled

focusEnabled

Allows a movie clip to be granted focus

_focusrect

Toggles the yellow rectangle, indicating focus

_framesloaded

Represents the number of frames that has been loaded by the movie

_height

Represents the height of the clip

hitArea

Indicates a clip that determines the hit area for a movie clip button

_lockroot

Serves as a reference to the main timeline of a loaded .swf when called inside the loaded movie

_highquality

Sets the rendering quality of the movie

_name

Represents the clip's name

_parent [*]

Indicates the clip that this clip is attached to

_quality

Sets the rendering quality of your movie

_rotation

Rotates a movie clip

_soundbuftime

Represents the number of seconds before a sound begins streaming

tabChildren

Allows clips attached to this clip to be part of the tab focus order

tabEnabled

Allows this clip to be part of the tab focus order

tabIndex

Indicates the tab focus index for this clip

_target [*]

Indicates the full path of this movie clip instance

_totalframes [*]

Represents the total number of frames in this movie clip

trackAsMenu

Determines whether other buttons can receive mouse- related events

_url [*]

Represents the Universal Resource Link (URL) pointing to the .swf where the clip was downloaded

useHandCursor

Indicates whether the cursor should turn into a hand when it's over the hitArea of this clip

_visible

Toggles the visibility of this clip

_width

Indicates the width of this clip

_x

Indicates the x position of this clip

_xmouse [*]

Represents the x position of the cursor (mouse pointer) relative to this clip

_xscale

Represents the horizontal scale percentage applied to this clip

_y

Indicates the y position of this clip

_ymouse [*]

Indicates the y position of the cursor (mouse pointer) relative to this clip

_yscale

Represents the vertical scale percentage applied to this clip

[*] This method is read-only.

Because MovieClip is the most important object in Flash, it stands to reason that it would have more properties and methods than the other objects, and it does. We've already seen many of the properties, and we'll see some later. There are only a few properties I want to talk about now.

Caution  

Did you notice how most of the built-in MovieClip properties have an underscore to begin their names? That's supposed to be the convention in Flash, but not all of them conform. Just be careful when referencing these properties to use the underscore only when required. Flash's color highlighting can help you determine if you have the correct property name.

The MovieClip._target Property

This read-only property indicates the absolute path to the clip, including the name of the clip, in slash syntax. It's unusual to require the use of this property, but let's see it in action anyway:

 attachMovie("ball"," ball",1); trace(ball._target); 

The output can be seen in Figure 6.18.

click to expand
Figure 6.18: The _target property gives an absolute path name to the clip using slash syntax.
Tip  

Slash syntax is a Flash convention in which a path is given with each object on the path being separated by a slash (/). The main timeline is denoted by a slash. Therefore, if you have a clip called ball attached to the main timeline, and you attach a square clip to your ball clip, the square's path would be /ball/square. The first slash is the main timeline, followed by the ball clip, and ending with the square clip.

The MovieClip._name Property

This property is similar to _target except that it does not contain the absolute path. Instead, it only contains the name of the clip, as it was given in the attachMovie call. Therefore, a clip named ball would have its _name property assigned a value of ball .

The MovieClip.enabled Property

This property enables and disables the built-in button functionality of a clip. Do you remember how we've been creating buttons that change state automatically because we've named the frames and added at least one button event handler? If you want to easily disable this ability, you can set the enabled property to false . If you later want to enable the button, set the property to true .

When a button is disabled, it no longer changes states when the user moves the mouse over it, clicks on it, and so on. Further, none of the button events is called (including onPress , onRelease , onDragOver , and so on) when a button has enabled set to false .

Note  

The timeline of a button continues to play when it is disabled if it was playing before it became disabled. That's because, even when disabled, the object is still a movie clip and continues to behave like one. It just loses its added button functionality.

The MovieClip._quality and MovieClip._highQuality Properties

As you know, Flash can be processor intensive . When you are moving complex vector graphics with gradient fills and alpha blending around the stage, Flash chews up a great deal of CPU cycles, which reduces your frame rate. On slower computers, this performance hit can cause your games to bog down until they are unplayable. For that reason, Flash gives us the ability to reduce the visual quality of our movies in exchange for a lighter CPU load.

The problem is that the browser has some abilities in that area, and they conflict with Flash's built-in ways of degrading visual quality. For that reason, I'm going to forgo this topic until Chapter 12, "Server Side Support for Flash: Highscore Boards," when we talk about Flash's relationship to the Web browser.

When we get into the topic of using HTML to alter the visual quality of a movie, we will supplement that discussion with Flash's built-in quality controls. For now, we're leaving everything at its default setting, which oddly enough is not the highest possible setting.

The MovieClip.trackAsMenu Property

Buttons in Flash can be set to either react or not react to the mouse when it is already pressed. If trackAsMenu is set to true , even if you press on a button, you can still trigger the release of another button provided you let go of the mouse over the new button. This allows you to create drop-down menus where you can press the menu button but let go over a menu item.

By default, trackAsMenu is set to false , meaning that once you press on a button, you can only interact with that button until after you release the click.

The MovieClip._url Property

This read-only property gives the URL address that the movie clip was loaded from. If the clip came as part of the main movie, its name would occupy the _url property. If the clip was loaded with a call to loadMovie , the specific URL used in that call would occupy the property.

The MovieClip.useHandCursor Property

This property is used to enable and disable the ability of Flash to turn the mouse pointer into a hand icon when it moves over a clip. This is automatically done when a movie clip acts like a button, but if you want to disable that, you can set the useHandCursor property to false . If, on the other hand, you don't want a clip to be a button but you still want the hand cursor, set this property to true . This can be useful for a game like a shooting gallery where you want the functionality of a button, but you don't want to give away all the hotspots by having the cursor turn into a hand over them.

The MovieClip Methods

Now that we've seen nearly all the properties, it's time to dig into the methods. Most of the power of Flash is given in this set of methods, so these methods are important to us. You have seen many of them before, and I won't discuss them again. We haven't covered several others, and we'll be looking at those now. Table 6.15 lists all the methods of MovieClip .

 
Table 6.15: MovieClip Methods

Name

Description

attachMovie

Creates a new MovieClip instance from a library symbol.

createEmptyMovieClip

Creates a new empty MovieClip instance.

createTextField

Creates a new TextField instance.

duplicateMovieClip

Creates a new clip instance by duplicating an existing one.

getBounds

Determines the coordinates of the clip's bounding box.

getBytesLoaded

Determines the number of bytes of a clip that has been loaded.

getBytesTotal

Determines the total number of bytes in a movie clip.

getDepth

Determines the depth setting of a movie.

getInstanceAtDepth

Returns a reference to a movie clip at a specified depth.

getNextHighestDepth

Returns an integer of the lowest available depth above other filled depths.

getSWFVersion

Returns an integer for the version of a loaded .swf.

getTextSnapshot

Returns a TextSnapShot object with all static text in a timeline.

getURL

Loads a document from a given URL in the browser.

globalToLocal

Given a point that is relative to the stage, this method converts that point into coordinates that are relative to the clip the method is called upon.

gotoAndPlay

Moves the playhead to a given frame in a clip and starts playing.

gotoAndStop

Moves the playhead to a given frame in a clip and stops it.

hitTest

Tests for collisions (overlap) between clips. Can operate on bounding boxes or exact clip shapes .

loadMovie

Loads an .swf or .jpg from the server.

loadVariables

Loads data from the server into the properties of a clip.

localToGlobal

Given a point that is relative to this clip, this method converts it to a point that is relative to the stage.

nextFrame

Moves a clip's playhead forward one frame and stops.

play

Plays a stopped clip's playhead.

prevFrame

Moves a clip's playhead back one frame and stops.

removeMovieClip

Removes a clip dynamic instance from existence.

setMask

Specifies a second clip to use as a mask for this one.

startDrag

Begins the auto-drag of a clip.

stop

Stops the playhead of a movie clip.

stopDrag

Stops the auto-drag of a clip.

swapDepths

Changes the relative depth settings of two clips.

unloadMovie

Removes a .swf that was loaded from the server.

Like the properties, you've seen many of these methods before, but some are still unfamiliar to you. Let's look at the unknown ones now.

The MovieClip.createTextField Method

This method creates a new TextField object that will be attached to the clip you call the method on. TextField is its own type of object, which we will briefly touch on in the later section "The TextField and TextFormat Objects."

Dragging Movie Clips

Flash gives us a built-in way to make movie clips draggable. This is done with two methods ” startDrag and stopDrag ”and the property _ dropTarget . Although these methods are somewhat handy, they come with some built-in deficiencies, including the inability to drag more than one clip at a time. On the other hand, they are simple to use. First let's look at the built-in way, and then we'll briefly discuss a strategy to do your own draggable movie clip code.

The MovieClip.startDrag Method

This method is used to begin dragging a movie clip. It has the following general form:

 void  myMovieClip  .startDrag([  lock  , [  left  ,  top  ,  right  ,  bottom  ]]); 

The method is called on the clip that you want to drag. All of the arguments are optional, although if you decide to specify any of the last four, all five must be specified. The first argument, lock , indicates whether the clip is dragged by its registration point or by the point the mouse was at when startDrag was called. Consider this example:

 attachMovie("ball", "ball", 1); ball.onPress = function(){ball.startDrag()}; 

First we attach a ball clip, and then we set its onPress handler to call startDrag with no arguments. Because there is no argument, lock = false is assumed by default. Now consider this revision:

 attachMovie("ball", "ball", 1); ball.onPress = function(){ball.startDrag(true)}; 

Now when you click on the ball, it snaps to a place where its registration point is under the mouse pointer. As you drag it around, it appears to be dragged by its registration point, even if that point falls outside the shape of the clip.

The final set of optional arguments, left , top , right , and bottom , restricts the area that the clip is draggable in. Consider this example:

 attachMovie("ball", "ball", 1); ball.onPress = function(){this.startDrag(false, 0,0,100,100)}; ball.onRelease = function(){this.stopDrag()}; 

Now the ball will be draggable only in the upper-left corner of the stage. After you drag it 100 pixels right or down, it stops moving but remains in drag mode. Play around with this example to see how it works.

The MovieClip.stopDrag Method

When a clip is in drag mode and you want to stop it, you can call stopDrag on the clip. It has the following general form:

 void  myMovieClip  .stopDrag(); 

stopDrag has no return type and takes no arguments. Whatever clip stopDrag is called on ceases to be in a draggable state. Consider the following example:

 attachMovie("ball", "ball", 1); ball.onPress = function(){this.startDrag()}; ball.onRelease = ball.onReleaseOutside = function(){this.stopDrag()}; 

Now the ball is not only draggable, but when you release the mouse button, the ball stops being dragged.

Now that we've seen the built-in dragging methods, you should be able to cook up a way to do dragging yourself. Personally, I would give a movie clip that you want to be draggable two handlers: one for onPress and one for onRelease . In the onPress handler, I would attach a function to the clip's onMouseMove handler that does the dragging. Then in the onRelease method, I would set the onMouseMove handler to null . That would provide a draggable movie clip. Let's take a quick look at what that code might look like.

First we need to create a clip to make draggable, and then we need to attach the onPress and onRelease handlers:

 attachMovie("ball"," ball",1); ball.onPress = function(){      this.xoffset = this._xmouse;      this.yoffset = this._ymouse;      this.onMouseMove = drag; } ball.onRelease = function(){      ball.onMouseMove = null; } 

As you can see, we are attaching the onMouseMove handler to something called drag in the onPress handler. The onRelease handler just sets it back to null . Now we just need to define a function called drag that does the dragging and we'll be finished:

 function drag(){      this._x = _root._xmouse - this.xoffset;      this._y = _root._ymouse - this.yoffset; } 
Note  

The use of xoffset and yoffset in the preceding example is required so that the clip is not dragged by its registration point. This is the same as the first argument to startDrag , where you set the lock to either true or false . Using the offset is like setting the value to false or omitting the argument completely. To get the snap to registration point behavior that you get when setting lock to true , remove the - this .xoffset and - this .yoffset from the drag function.

The MovieClip.getBounds Method

This method gets the local coordinates of the bounding box that surrounds the movie clip. It's a little bit tricky to use because of the relative nature of coordinate systems in Flash. Remember that if you attach a movie clip to another movie clip, the inner clip's _x and _y coordinates are relative to the clip it's attached to. getBounds is the same way, except that it takes an optional argument to specify the coordinate space you want the values to be relative to. Let's look at its general form:

 object  myMovieClip  .getBounds([  targetCoordinateSpace  ]); 

The first thing to see is the return type. It's an object that will have four properties defined on it: xMin , xMax , yMin , and yMax . Therefore, it works much like a color transform object, except that you don't have to declare it first. Let's look at a simple example before we go any further:

 this.attachMovie("ball", "ball", 1); ball._x = 100; ball._y = 100; ball.onPress = function(){ball.startDrag()}; ball.onRelease = function(){ball.stopDrag()}; this.onEnterFrame = function(){      bounds = this.getBounds();      trace("xMin : "+ bounds.xMin);      trace("xMax : "+ bounds.xMax);      trace("yMin : "+ bounds.yMin);      trace("yMax : "+ bounds.yMax); } 

The onEnterFrame function is the important one. For each frame, bounds is given the return from a call to getBounds with no argument. Then each of the four properties is traced. If you click and drag the ball around, you see these values changing to reflect the new position of the ball on the stage. Try to move the ball so that its leftand topmost edges are right at the edge of the stage. You'll see the xMin and yMin values approaching 0. (You might have to draw lines on the edges of the stage so that you can see where it ends while testing the movie.) Figure 6.19 shows a possible output.

click to expand
Figure 6.19: The getBounds method finds the bounding box around a movie clip.

Now comes the tricky part. You are getting stage coordinates for the bounding box because we called getBounds with no arguments; therefore, the method is using the locally scoped timeline as its default. In this case, that's the main ( _root ) timeline. On the other hand, if you wanted to get the coordinates of the bounding box relative to some other movie clip, you could provide a reference to that clip in the call to the getBounds function and Flash would convert the coordinates for you. Consider the following script:

 this.attachMovie("ball", "ball", 1);  ball._x = 400; ball._y = 400;   this.attachMovie("ball", "ball2", 2);   ball2  .onPress = function(){  ball2  .startDrag()};  ball2  .onRelease = function(){  ball2  .stopDrag()}; this.onEnterFrame = function(){      bounds =  ball2  .getBounds(  ball  );      trace("xMin : "+ bounds.xMin);      trace("xMax : "+ bounds.xMax);      trace("yMin : "+ bounds.yMin);      trace("yMax : "+ bounds.yMax); } 

What's happening here is that we first create ball and move it into the lower-right corner of the stage. Then we create ball2 and assign it the dragging functions so that you can move it around. Finally, we attach an enterFrame handler for the main timeline that calls getBounds on ball2 using ball as the argument. That means our output will be the coordinates of the bounding box of ball2 , but they will be relative to ball . Because ball2 starts off in the upper-left corner and ball starts in the lower-right corner, these values will be large negative numbers until you drag ball2 to the other side of ball .

This example brings up all kinds of issues. Many times, you'll need the position of some clip relative to some other clip. For example, maybe you are making a sword-fighting game. You want to know if the tip of one player's spear touches another player. But the way you've developed the clips, the spear is attached to the player holding it. If you decided to use hitTest to see if the spear was inside the opponent player's shape, the test would fail because the coordinates ( _x and _y ) of the spear would be relative to the clip they were attached to. What can you do about that?

Flash gives us two methods for converting a point from one coordinate system into another. One is used to go from a local (movie clip) coordinate space into the global (stage) space, and the other is used in reverse to go from the global (stage) space into a local (movie clip) space.

The MovieClip.localToGlobal Method

As its name implies, this method transforms a point from the local coordinate system into the global coordinate system. It has the following general form:

 void  myMovieClip  .localToGlobal(  point  ); 

The return type is void and the method takes one argument: an object I'm calling point. The point argument is an object that has two properties defined: x and y . This object must be created before the call. Then you must set the x and y values to be some point that is defined locally to the movie clip that you are calling on. The coordinates are then transformed to global coordinates on your point object. After the call, your point object's x and y properties are altered to reflect the new coordinate system. Let's look at an example:

 attachMovie("ball", "ball", 1); ball._x = 200; ball._y = 200; ball.attachMovie("ball", "littleball", 1); ball.littleball._xscale = ball.littleball._yscale = 30; ball.littleball._x = ball.littleball._y = 20; ball.onPress = function(){ball.startDrag()}; ball.onRelease = function(){ball.stopDrag()}; p = new Object(); this.onEnterFrame = function(){      p.x = ball.littleball._x;      p.y = ball.littleball._y;      trace("local: ("+p.x+","+p.y+")");      ball.localToGlobal(p);      trace("global: ("+p.x+","+p.y+")"); } 

First we attach a clip called ball . Then we attach another clip to it, called littleball . We scale down this second clip and move it over 20 pixels so that you can see it more easily. We make the ball clip draggable and create a new object called p , which will be our point. Then we create an enterFrame handler that sets the value of p.x and p.y to be the coordinates of the little ball. Because the littleball clip is attached to the ball clip, its coordinates are relative to the ball clip, which means that when we trace these points, they remain 20 and 20 because that's the position of the littleball to the ball . Then we call localToGlobal using the method on ball . That causes the point, which was already relative to ball , to be transformed into a point that is relative to the stage. Figure 6.20 shows a possible output.

click to expand
Figure 6.20: The localToGlobal method takes a point that is relative to a clip and converts it into stage coordinates.

You might be a bit confused at this point over one thing in particular. What clip do we use to call localToGlobal ? Normally, you should use the clip that is local to the point you set up. Because our point is the coordinate of littleball and littleball is attached to ball , ball is the local coordinate system used with our point. Therefore, when we call localToGlobal , we do it on the ball clip.

The MovieClip.globalToLocal Method

This method works in the reverse of the previous one. If you have a point in global space and you want it in local space, you can use globalToLocal , which has the following general form:

 void  myMovieClip  .globalToLocal(  point  ); 

globalToLocal works just like the previous method, so I'm not going to belabor the point. Let's just look at an example:

 attachMovie("ball", "ball", 1); ball._x = 200; ball._y = 200;  attachMovie("ball", "littleball", 2);   littleball._x = littleball._y = 200;   littleball._xscale = littleball._yscale = 30;   littleball._x = littleball._y = 80;   littleball.onPress = function(){littleball.startDrag()};   littleball.onRelease = function(){littleball.stopDrag()};  p = new Object(); this.onEnterFrame = function(){  p.x = littleball._x;   p.y = littleball._y;   trace("global: ("+p.x+","+p.y+")");   ball.globalToLocal(p);   trace("local: ("+p.x+","+p.y+")");  } 

This time, we attach both balls ” ball and littleball ”to the main timeline. The small ball is draggable. During our enterFrame handler, we assign p the position of littleball . Because littleball is attached to the main timeline, its position is relative to the stage. Therefore, our first trace prints out the stage coordinates of littleball . Then we make our call to globalToLocal on the ball instance, which converts what was originally the stage coordinates of littleball into a point relative to ball . In other words, if you drag the littleball so that it is directly left of the ball , its new local position contains a negative x value and a y value of 0. Figure 6.21 shows this.

click to expand
Figure 6.21: The globalToLocal method turns a point relative to the stage into a point relative to the clip you called globalToLocal on.
Working with Depth

As you know, when movie clips are attached, they are given a depth setting that controls which clips overlap when being viewed on the stage. You can, through the use of some MovieClip methods, change the depths of clips at run-time.

The MovieClip.getDepth Method

This method returns the depth that a movie clip is set at. It has the following general form:

 number  myMovieClip  .getDepth(); 

The number returned is the depth that a movie clip was created at, assuming it hasn't be acted upon by our next method. Manually placed movies return a negative depth.

The MovieClip.swapDepths Method

This method changes the depth of a clip. It can be used in either of two ways. Consider this general form:

 void  myMovieClip  .swapDepths(  newDepth  ); 

In this case, the argument newDepth is a number. When it's called, myMovieClip takes the depth supplied by newDepth , and if there is a clip that exists at that depth, its depth is swapped with myMovieClip .

In the second case, you can use a target movie clip instead of a depth number. Consider this alternate form:

 void  myMovieClip  .swapDepths(  targetClip  ); 

Of course, this form is technically identical to the previous, but I've named the argument differently. This time it's called targetClip because it represents a reference to the movie clip to swap depths with.

The MovieClip.getInstanceAtDepth Method

This method returns a reference to a movie clip at a particular depth. This allows you to see if there is an instance at a particular depth. The general form is as follows:

 MovieClip  myMovieClip  .getInstanceAtDepth(  depth  ); 

The argument depth is an integer. If the specified depth is empty, getInstanceAtDepth returns undefined .

The MovieClip.getNextHighestDepth Method

This method returns an integer representing the lowest available depth that is still higher than all other filled depths. You would use this to supply a depth for methods such as attachMovie or duplicateMovieClip if you wanted to place the new movie at the highest level. The general form of getNextHighestDepth is as follows:

 Number  myMovieClip  .getNextHighestDepth(); 
The MovieClip.getURL Method

This important method is covered in Chapter 12 because it deals with using the server to support a Flash application.

The Drawing API

Flash allows us to draw on the stage using the Drawing API. The Drawing API is a set of methods contained in MovieClip that allows you to draw lines and fills inside a clip instance. This is accomplished through the use of several methods. Table 6.16 shows these drawing methods.

 
Table 6.16: MovieClip Drawing Methods

Name

Description

moveTo

Moves the drawing point to somewhere in the clip without drawing anything

lineStyle

Changes the style that the next line to be drawn uses

lineTo

Draws a line from the current drawing point to a given point

curveTo

Draws a curve from the current drawing point to a given point

beginFill

Tells Flash to fill the area currently being drawn

beginGradientFill

Tells Flash to fill the area currently being drawn with a gradient fill

endFill

Used when the current fill area has been drawn completely

The MovieClip.moveTo Method

Before we burst into this first method, we need to talk a bit about how drawing works in Flash. The idea is that you use a MovieClip instance on the stage as the canvas to draw upon. You have an imaginary point, which I call the drawing point, that keeps track of where your drawing is about to begin. You first move the drawing point to the place you want your drawing to begin. Then when it's time to draw a line, you tell Flash what kind of line to draw (width, color, and so on). Then you give Flash a second point, and Flash draws a line from the drawing point to the second point.

You tell Flash to move to the drawing point by calling the moveTo method, which has the following general form:

 void  myMovieClip  .moveTo(  x  ,  y  ); 

Because there is a void return type, the only thing to look at is the argument list. The argument list consists of two numbers, x and y , which indicate the position to move the drawing point to. The numbers are relative to the registration point of myMovieClip . Consider the following example:

 createEmptyMovieClip("mc",1); mc.moveTo(100,100); 

This creates an empty clip for us to draw in and then moves the drawing point to the coordinates (100,100). If we tell Flash to draw a line to a given point, it begins the line at this new position (100,100).

I'd like to draw a line now to demonstrate this, but I can't. I can't do this until I've told Flash what kind of line to draw.

The MovieClip.lineStyle Method

This method sets the drawing style for a movie clip. It has the following general form:

 void  myMovieClip  .lineStle([  thickness  [,  rgb  [,  alpha  ]]]); 

The first argument, thickness , sets the thickness of the line that you are about to draw. The valid range for thickness is 0 “255, even though in Flash you can manually only select a thickness up to 10. At a value of 0, Flash gives the line a hairline thickness (1 pixel wide, regardless of scale).

The second argument, rgb , indicates the color of the line to be drawn. This value is given in hexadecimal format as with the Color.setRGB method.

The final argument, alpha , indicates the amount of transparency to apply to the line.

Each of these arguments is optional, but each is embedded in the previous argument. That means if you want to set the rgb argument, you must also supply the thickness argument. Likewise, if you want to set the alpha , you must give both the thickness and rgb arguments.

After you have set the line style by calling lineStyle , it remains that style until you make another call to lineStyle .

Note  

Each movie clip has its own drawing point and line style. That means you can have several clips that you are drawing in, each with their own line style. This can save you from changing line styles too often.

We can now add another line to our sample script:

 mc.lineStyle(10, 0xFF0000, 75); 

This script sets the line thickness to 10, the color to red, and the alpha to 75%.

The MovieClip.lineTo Method

Now that we've moved our drawing point and set our line style, we're ready to draw a line. To do so, we use the lineTo method, which has the following general form:

 void  myMovieClip  .lineTo(  x  ,  y  ); 

When you call this method, you supply the two arguments, x and y , and Flash draws a line from the current drawing point to the point you supply in your call to lineTo . The currently set line style is used. Let's see an example, now that we have our drawing point and line style set with the previous examples:

 createEmptyMovieClip("mc",1); mc.moveTo(100,100); mc.lineStyle(10, 0xFF0000, 75);  mc.lineTo(200,200);  

This draws a line from the current drawing point (100,100) to the point given in the call (200,200) using the current line style, which is a 10-pixel thick, partially transparent red line, as in Figure 6.22.

click to expand
Figure 6.22: The lineTo method call draws a line, assuming you have set a line style with a call to lineStyle .
Note  

When you call lineTo and Flash draws a line, the drawing point is moved to the end point of the newly drawn line. That means if you call lineTo a second time, the new line begins where the old line ended.

The MovieClip.curveTo Method

What fun would drawing be if all you could draw were straight lines? It would be pretty boring, and Macromedia knew it. In light of this, Macromedia provides us the ability to draw curves as well as straight lines through the use of the curveTo method, which has the following general form:

 void  myMovieClip  .curveTo(  controlx  ,  controly  ,  x  ,  y  ); 

The first two arguments, controlx and controly , are used as a guide to help Flash draw the curve. The second two arguments, x and y , are used just like x and y in the previous drawing methods. They indicate the ending point of the curve to be drawn.

Let's see an example. Assume that this script is tacked onto the end of our previous script:

 mc.curveTo(250, 100, 300,200); 
Note  

The control point (given in the first two arguments to curveTo ) is not necessarily passed through by the curve. Instead, it serves only to guide the curve.

After the previous script drew its line, our drawing point was left at the coordinates (200,200). This call to curveTo begins there, draws a curve to (300,200), and uses the point (250,100) as a guide. You can see the output of this in Figure 6.23 along with a label for the point (250,100) that serves as a guide. Notice how the curve does not actually pass through that control point. In fact, it only gets halfway to it.

click to expand
Figure 6.23: The curveTo method draws a curve from the current drawing point to a given point ( x , y ), using another given point ( controlx , controly ) as a guiding point for the curve.

Getting Flash to draw the curve you want by using control points takes some practice. Your intuition serves you best in the act of picking a control point for your curve. Try playing around with curveTo to get a feel for these control points.

The MovieClip.clear Method

This method clears any drawing you've done in the given movie clip. It has the following general form:

 void  myMovieClip  .clear(); 

That should be simple enough. Try it by adding this line to the bottom of the previous examples:

 mc.clear(); 
Tip  

Like all the drawing methods, clear only affects lines, curves, and fills drawn inside the given movie clip. Drawing you've done in other clips is unaffected by clear .

The MovieClip.beginFill Method

In addition to the ability to draw lines and curves, Flash provides the ability to draw fills with the use of the beginFill method, which has the following general form:

 void  myMovieClip  .beginFill([  rgb  [,  alpha  ]]); 

The two arguments, rgb and alpha , work identically to the ones in lineStyle , except that they affect the next fill to be drawn instead of the line to be drawn.

After you call beginFill , you can use the lineTo method to draw a shape. When the shape is complete and your drawing point has moved back to the place it was when you called beginFill , Flash creates and draws the fill.

If you want to, you can omit the last call to lineTo and instead call endFill . This causes Flash to draw a straight line from the current drawing point to the original drawing point when you called beginFill . That final line allows Flash to complete the fill for you.

Take a look at the following example:

 createEmptyMovieClip("mc",1); mc.moveTo(100,100); mc.lineStyle(8,0xFF0000);  mc.beginFill(0x0000FF);   mc.lineTo(200,100);   mc.lineTo(200,200);   mc.lineTo(100,100);  

In the preceding script, we first create an empty clip to draw in called mc , as in our previous examples. We then move the drawing point to (100,100), set the line style, and call beginFill with a color of 0x0000FF (blue). Then we call the lineTo method three times, creating a triangle. When we draw the last line, we complete a closed shape and Flash takes that opportunity to create our fill. This example's output can be seen in Figure 6.24.

click to expand
Figure 6.24: After calling beginFill , Flash fills all enclosed shapes you draw with calls to lineTo .

If we continue to draw closed shapes, Flash fills them all. Flash's automatic creation of fills continues until we either stop drawing closed shapes or we tell Flash to stop with a call to endFill . If your lines cross while you are drawing a shape to fill, the fill will not be displayed after the lines crossed until they cross again.

Caution  

Make sure that filling begins and ends in one frame. Leaving the beginFill open across frames can lead to undesirable behavior.

The MovieClip.endFill Method

This method marks the ending of the line segments used to create a filled shape. If the last line you drew is not a closed shape, Flash completes the line for you by moving back to the point where you called beginFill and creates a fill in the newly created enclosure. Generally, this is not what you want; you want to create closed areas with lineTo only when you are trying to make fills:

 void  myMovieClip  .endFill(); 

The MovieClip.beginGradientFill Method

This complex method creates gradient fills. Its usage is detailed and involves employing several arrays and a transform matrix. The ActionScript Dictionary does a decent job of explaining and giving examples of beginGradientFill 's use, so I hesitate to spend the time talking about it here. Instead, I leave this final drawing method as an exercise for you.

Note  

Leaving this method as an exercise for you might seem like a cop-out if you happen to have an interest in this method. That's not what it is, though. I would rather skip this method and save the pages for more advanced topics that are of much greater importance to you as a game developer.

The MovieClipLoader Object

The MovieClipLoader class is a collection of event handlers that help to determine how much of a movie has loaded. We are going to look at this class in detail in Chapter 12, so let's skip it for now.

The TextField and TextFormat Objects

You've been adding text fields to your movies since Chapter 1, "The Flash Authoring Tool". However, as with movie clips, you'll sometimes want to create text fields dynamically at runtime. Their usage is straightforward but also detailed. Explaining text fields fully would require many pages that I am reluctant to give to the subject, so again, I direct you to the ActionScript Dictionary.

The TextFormat object is used with TextField objects to change the properties of the text displayed in the field. This works in much the same way that a transform object works with the Color object to change its color. Because we're not going to talk about TextField , we'll naturally be skipping TextFormat as well.

That concludes our look at the movie objects, both global and instance.

Media Objects

The media classes deal with embedding audio and video into Flash as well as using Webcams and microphones attached to the user's computer. For game development, the area that is most useful to us is the Sound object, which is how we will be adding sound effects to our games.

The Sound Object

So far, we've been neglecting sound effects in our games. Even the first video games had sound effects, and our study of games wouldn't be complete without them. The reason we've skipped sounds so far is because Flash is good at controlling sound without ActionScript. I could have given you a few of the methods for controlling sound several chapters ago just to get some simple sound effects playing, but I chose to save them until now so we could talk about everything at once.

In Chapter 1, we learned how to import graphics and sounds into Flash. After that's done and the sounds and graphics are in your library, you must export them for ActionScript, just like you do with movie clips.

Before we get into how this actually works, look at Table 6.17, which lists all the methods of the Sound object.

 
Table 6.17: Sound Method List

Name

Description

attachSound

Associates a sound in the library to a Sound object

getBytesLoaded

Determines how many bytes of a sound have been loaded

getBytesTotal

Determines how many bytes of data the sound file contains

getPan

Determines the current pan setting

getTransform

Retrieves an object containing the current transformations that have been applied to the sound

getVolume

Determines the current volume setting

loadSound

Loads a sound during the execution of your movie

setPan

Sets the stereo panning

setTransform

Applies a sound transform

setVolume

Changes the volume setting

start

Begins the playing of a sound

stop

Stops a sound that is playing

Actually playing sounds is a bit tricky. To use a sound in your movie, you need three things:

  • A MovieClip instance to attach the sound to

  • A Sound object to control the sound

  • A call to attachSound to bring in the sound data from your library

Tip  

You can also add sounds manually by selecting a keyframe and selecting a sound in the Properties panel.

You can create both the MovieClip object and the Sound object with one line of script each. A reference to the clip is given to the constructor for the Sound object, as in the following script:

 attachMovie("ball"," ball",1); s = new Sound(ball); 

Now we have a sound named s that is associated with the ball clip. We can use our first Sound method to grab some data from the library.

Tip  

As with movie clips, I use the same name in the sound export settings as the sound's symbol name in the library. That saves confusion later on. The difference is that when you import a sound, it might come in with a file extension, such as .wav. In that case, the symbol name might be something like blip.wav.

The Sound.attachSound Method

Before you can play a sound, you must attach it; having the sound in the library is not enough. The general form of attachSound follows:

 void  mySound  .attachSound(  idName  ); 

The argument, idName , is the export name you gave the symbol in the linkage properties.

Here is an example of attaching a sound onto our existing Sound object from the previous example:

 s.attachSound("mysound.wav"); 

Now that the sound is attached, we can play it whenever we want to. The sound does not automatically start. To do that, we use the next method.

The Sound.start Method

This is, as you might expect, the method to begin the playing of a Sound object. A simple call to start initiates playing of the Sound object, assuming the three conditions that we talked about before:

  • You have a sound in your library that is exported for ActionScript.

  • You have a Sound object that is associated with a MovieClip object.

  • You have attached the sound to the Sound object.

If all that's done, simply call start on the Sound object to which the chosen sound is attached. The start method has the following general form:

 void  mySound  .start([  secondOffset  ,  loop  ]); 

Both arguments are optional. The easiest way to play a sound is to specify neither argument, in which case the sound plays once, as it does in the following script:

 s.start(); 

If you specify the first argument, secondOffset , the sound skips over some of its data before it begins playing. Therefore, if you have a sound and you only want to play the second half of it, you can specify this argument to do so. The only thing to watch is that this argument is in seconds , not milliseconds, as most timing methods are.

The second argument, loop , specifies the number of times the sound should play repeatedly. If you have a sound that you want to play during the entire game, you can specify loop to be a large number.

The Sound.stop Method

If you have a sound that is playing and you want to stop it, simply call the stop method on it. It has the following general form:

 void  mySound  .stop([  idName  ]); 

There is an optional argument, but I've never used it. Its purpose is to allow you to specify the identifier of the sound to stop playing. But because each sound has its own Sound object, this argument is unnecessary. Technically, you can add more than one sound to a timeline, but for organization, we won't be doing that in this book. To stop a sound from playing, call the following script:

 s.stop(); 
Purpose of Associating a Sound with a MovieClip

Technically, you don't have to associate a sound with a MovieClip object. However, if you create a Sound object that has no arguments in the constructor, that object implicitly sets the _root as its target. This effectively controls the playback of all sounds in your game. This can be quite handy if you want to adjust the master volume of a game or mute all sounds; however on a sound-to-sound basis, let's stay with specifying specific timelines.

The Sound.duration Property

This read-only property is the duration in milliseconds that the sound plays. You can use this property to determine how long one particular sound effect will play after you start it.

The Sound.position Property

This read-only property is the duration in milliseconds that the sound has been playing. You can compare this property to the duration property to determine how much longer a sound will play.

The Sound.getVolume and Sound.setVolume Methods

These methods should be pretty self-explanatory. They are used to set the volume of a sound. The general form of getVolume follows:

 number  mySound  .getVolume(); 

The return value is a number that indicates the percentage of volume to use when playing the sound. The default setting is 100 percent.

The setVolume method changes the volume that a sound is going to play at; its general form follows:

 void  mySound  .setVolume(  number  ); 

The single argument indicates the percentage of volume to use when playing the sound. It should be a number greater than or equal to 0. If you go above 100 percent, the sound begins to distort.

The Sound.getPan and Sound.setPan Methods

Most home stereos have a pan control (often called balance), so you're probably already familiar with this concept. The idea is that you reduce the volume in each of the speakers separately. Pan should be thought of as a dial between left and right. When the dial is all the way to the left, you have 100 percent volume in the left speaker and 0 percent volume in the right speaker. As you gradually turn the dial to its midpoint, the volume in the right speaker goes from 0 to 100 percent. At that midpoint , both speaker volumes are at 100 percent. Then if you move the dial slowly from the midpoint to the right extreme, the volume in the left speaker goes from 100 to 0 percent.

The getPan method determines the current panning of a sound. It has the following general form:

 number  mySound  .getPan(); 

The return value is a number between -100-100. A number of -100 indicates a pan of extreme left, 100 indicates a pan of extreme right, and 0 indicates no panning at all. No panning is the default setting.

To change the current panning, use the setPan method, which has the following general form:

 void  mySound  .setPan(  number  ); 

The single argument must be a number between -100 and 100, and it corresponds to getPan .

The Sound.getTransform and Sound.setTransform Methods

These methods transform a sound in much the same way that a color object is used to change color. You set up an object created with new Object(); and then assign it parameters. The object is given as an argument to setTransform , and its parameters are used to transform the sound.

This transform essentially allows you to mix a stereo input any way you like. You can determine how much of the left signal is played in the right speaker, and vice versa. We're not going to use this feature in any of our games, and explaining it further would be a bit of a tangent, so I leave it to the ActionScript Dictionary.

The Sound.loadSound, Sound.getBytesLoaded, and Sound.getBytesTotal Methods

Sounds can contain a great deal of data, particularly with music. Sometimes you might want to wait until run-time to decide which music to load. To load sounds from the server at runtime, you can use the loadSound function. Run-time communication with the server is covered in Chapter 12. Both getBytesLoaded and getBytesTotal are used along with the loadSound method.

The Sound Event Handlers

What object would be complete without some event handlers? Certainly not this one. Two events are associated with sounds. Let's look at each one.

The Sound.onLoad Event

This event works with the loadSound method. When you load a sound, you'll often want to know when it's finished loading. You can attach this handler, and it will be called when the loadSound call has finished loading its sound from the server.

The Sound.onSoundComplete Event

This event is called when a sound finishes playing. It is not called if you stop the sound from playing with a call to stop . Also, if you use the loop argument in your call to start , onSoundComplete is not called until the sound stops playing after its final loop. In other words, if you loop a sound 10 times, you'll only get one onSoundComplete call, after the tenth loop.

Now that we've seen some of what the media objects can do for us, let's talk about dealing with dynamic data from outside the Flash file and the objects that make these tasks possible.

Client/Server and Authoring Objects

These two object groups donate a total of six objects to Flash. Table 6.23 lists those that are most useful to us.

 
Table 6.23: Client/Server and Authoring Object List

Name

Type

Group

Description

LoadVars

Instance

Client/Server

Encapsulates the communication of data from Flash to and from the server

XML

Instance

Client/Server

Creates a new XML document tree

XMLSocket

Instance

Client/Server

Creates a connection from Flash to the server identified by an IP address or a domain name

I want to say a few words about each of these objects, although we are not going to explore any of them.

The LoadVars object encapsulates the function loadVars . It's much like a Function object or other wrapper object, such as Number or String .

The XML and XMLSocket objects manipulate documents formatted with the XML document standard. XML stands for eXtensible Markup Language, and it amounts to a standard for building documents in a hierarchal format (similar to HTML). These objects manipulate such documents. The subject of XML is pretty large and really deserves its own book. There is just such a book, devoted to XML in Flash, listed in Appendix D, "Web Resources and Further Reading."

That concludes our look at objects. Finally, it's time to move on to this chapter's game.




Macromedia Flash MX 2004 Game Programming
Macromedia Flash MX 2004 Game Programming (Premier Press Game Development)
ISBN: 1592000363
EAN: 2147483647
Year: 2004
Pages: 161

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net