Chapter 1. Introducing ActionScript 3.0
If you chase perfection, you often catch excellence.
The term “perfect” is a powerful word. From a practical standpoint, it represents a state that arguably cannot be achieved. Hey, that’s a relief already! This book doesn’t expect the impossible. This isn’t the print version of an office know-it-all, itching for you to slip up. You won’t hear any anxious hand wringing in these pages over why you haven’t yet upgraded to, much less mastered, ActionScript 3.0. (Yes, even though it was available in Flash CS3 Professional.) Instead, the following chapters will take their cue from a sage observation by William Fowble: If you chase perfection, you often catch excellence. In other words, chin up! Aim for the best and enjoy the road trip. ActionScript 3.0—the current version of the programming language for the Adobe Flash Platform—is a language that indeed catches excellence. This book is designed to explain a bit about why that is. In so doing, our hope is to help you chase perfection by introducing you to the improved organization, syntax, and workflows of the new language. Catching excellence, for all of us, is a matter of practice, and comes with time.
This book is going to introduce you to new ways of thinking about the Flash Platform. ActionScript 3.0 requires these new ways because the language is actually structured around them. That’s a big part of why the new language improves on previous versions. Like its precursor, but to a greater extent, ActionScript 3.0 is based on a specification called ECMAScript, which is a standard proposed by a body of experts known as Ecma International. This group is something like the World Wide Web Consortium (W3C), whose responsibility includes HTML, XML, CSS, and other widely used markup languages. Such a standard’s benefit is that ActionScript 3.0 isn’t just an arbitrary language invented to meet Adobe’s needs. ECMAScript is a relatively mature specification, already in its third revision. The Ecma International team includes authorities from industry powerhouses like Microsoft, the Mozilla Foundation, and Adobe. The specification is built on the collective insight and success of these diverse experts in the field. Of all the versions of ActionScript, the current version comes closest into full compliance with this specification—at this point, closer even than the other famous ECMAScript derivative, JavaScript. This makes ActionScript 3.0 a model of best practices, habits you can use in both Flash CS4 Professional and Flex Builder 3. In many cases, you may even find that these practices benefit your involvement with existing projects coded in previous versions of ActionScript. Sure, the syntactical details change, but achievement in programming is all about structure and purpose. It’s the concepts and good habits that carry you.
For the nuts and bolts, the relevant ActionScript Language Reference is always a mere keystroke away (the F1 key). Even so, a new set of Help docs can be daunting, especially if you’re already well-versed in ActionScript 2.0. Fortunately, the ActionScript 3.0 documentation is every bit as helpful as it used to be, even if it looks different. The layout of the Help docs is still organized around the layout of the language itself—around the classes that define the objects you will use—and its class entries still summarize the usable apparatus of each object: its characteristics, called properties; the things it can do, called methods; and the things it can react to, called events. In the new documentation, code samples are presented as custom classes, rather than frame scripts. This requires you test them as standalone, simple text files, according to the new document class concept described in Chapter 6. Fortunately, this also means you can test these classes in other programs, such as Flex Builder. This book will help you get familiar not only with the new language, but also with the documentation that explains it.
Keep in mind, ramping up to ActionScript 3.0 isn’t merely about learning the latest syntax: it’s about becoming a better, more efficient programmer. This isn’t meant to slight ActionScript 2.0 at all, but plenty has changed since its introduction in late 2003. It’s no exaggeration to say that several aspects of the language have been completely overhauled. In fact, ActionScript 3.0 requires an entirely new virtual machine, which is the module inside Flash Player that interprets compiled ActionScript. As of Flash Player 9, the runtime that displays Flash movies does so with two virtual machines: AVM1 for legacy SWF files based on ActionScript 1.0 and 2.0, and the new AVM2 for ActionScript 3.0. That’s a first in the history of Flash Player. Thanks to the new virtual machine, ActionScript 3.0 runs faster and more efficiently by an order of magnitude. This bodes well for the overriding goal of the new language: to facilitate a wide range of interactive media and Rich Internet Applications (RIAs)—to do so simply, with better performance, and highly compatible with industry standards. As you can imagine, an upgrade of this scale means you may have to reshape some of your current habits. But take heart. Reshape doesn’t necessarily mean tear down and rebuild. As ActionScript has matured, it has consistently moved in the direction it currently stands. Again, honing your skills in light of ActionScript 3.0 will help you in your current projects and also in legacy project maintenance. Migration can be intimidating, but much of that uncertainty comes from trying to find your stride. Once you take the first few steps, the momentum keeps you going.
Here’s a look at some of the new features.
Examining ActionScript 3.0, the Language
Section 4 of the ECMAScript standard (http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf) defines an important facet of any language that implements it. Such languages “will provide not only the objects and other facilities described in this specification but also certain environment-specific host objects, whose description and behaviour are beyond the scope of this specification.” In other words, any ECMAScript derivative needs a set core functionality that stands on its own and will then provide additional functionality specific to the environment that interprets it. This is exactly what ActionScript 3.0 does, and its host environments include Flash Player for web browsers, intended for Flash-enabled websites such as http://YouTube.com; Flash Lite for devices, such as video games for your cell phone; and Adobe Integrated Runtime (AIR) for applications installed on the hard drive, such as eBay Desktop (http://desktop.ebay.com/).
Here is a brief summary of a number of core updates.
Runtime Exceptions
In ActionScript 2.0, many runtime errors failed without drawing attention to themselves. On the plus side—and this is a very weak plus—this meant that errors of this sort often failed “gracefully.” In other words, they might not halt someone’s experience with something abrupt or laden with technical jargon, such as an alert or dialog box. On the minus side, this also meant such errors might go unnoticed by the developer—until complaints started rolling in that people were experiencing slow playback or even lockups. Such errors could be hard for developers to pinpoint and repair, precisely because they were silent.
ActionScript 3.0 allows for a variety of runtime exceptions to be
handled with purpose. This includes Error
objects generated both by the runtime
environment and, potentially, by
the programmer. In ActionScript 3.0, the Error
class is considerably more robust than
its forerunner, and tailor-made Error
objects can be built from this class as desired, inheriting and
extending its functionality to provide highly customized error messages.
Exceptions can even provide source file and line number information,
which greatly enhances the debugging experience, letting developers
quickly track down errors.
Runtime Types
ActionScript 2.0 introduced the ability to strongly type
variables, parameters, and function return values. This was, and still is, an optional way to let Flash know
exactly what sort of data a particular variable, parameter, or return
value could cope with. This ability was a boon to developers in terms of
debugging, because it gave you a way to display error messages in cases
of a type mismatch. For example, if you were going to perform a math operation
on two numbers provided by the user, you might take those numbers from
input text fields. This would actually make them strings, which meant
your math operation would give you unexpected results (for example, 1 +
2 would become “12” instead of 3). By strongly typing the parameters of
the function that performed this operation—in other words, by specifying
intended variable types with a colon (:
), then the type—you could benefit from a
meaningful error message in the Output panel such as this:
// ActionScript 2.0 var userVar1:String = inputField1.text; var userVar2:String = inputField2.text; function getSum(a:Number, b:Number):Number { return a + b; } trace(getSum(userVar1, userVar2)); // Displays: **Error** Scene=Scene 1, layer=Layer 1, frame=1:Line 8: Type mismatch. getSum(userVar1, userVar2);.
A type mismatch notice is a great reminder to use something like
parseInt()
or parseFloat()
to convert those strings into
numeric values. Useful indeed, but this was only a first step in a good
direction. In ActionScript 2.0, this sort of error checking only
occurred at compile time. Under many circumstances—such as evaluating
data from dynamic sources like XML—the feature wasn’t “smart” enough to
catch every contingency. In ActionScript 3.0, it is.
Sealed Classes
Following in the same vein as runtime exceptions and runtime
types, ActionScript 3.0 establishes the concept of sealed
classes in a stricter, more formalized way than in
ActionScript 2.0. A sealed class is one that can’t have properties or
methods assigned to it at runtime, such as String
. By default, classes in ActionScript
3.0 are sealed, but this can be overruled when you write your
own.
var str:String = "" // Or: new String(); str.customProperty = "This generates a compiler error."; // Displays: Access of possibly undefined property customProperty // through a reference with static type String.
In contrast, a class that actually can have properties and methods
assigned to it at runtime is called dynamic.
One of the most familiar dynamic classes is MovieClip
, though historically speaking, many
frame script developers haven’t considered movie clips in terms of a
class. The same could be said of buttons and text fields, because you
can create such elements with Flash’s drawing tools. (Of the elements
just mentioned, only movie clips are dynamic.) For frame script coders,
movie clips are often thought of simply as symbols or timelines, and
timelines have always been able to receive new variables at runtime.
True enough. What’s really going on, though, is that variables defined
in keyframe scripts are in reality dynamic properties of a MovieClip
instance; functions are actually
dynamic methods.
Declaring a variable in a keyframe of the main timeline or in a movie clip’s timeline is conceptually the same as the following:
var mc:MovieClip = new MovieClip(); mc.customProperty = "This is perfectly acceptable.";
Custom classes in ActionScript 3.0 can behave this way too, if and
only if they are declared with the dynamic
attribute:
package {
public dynamic class CustomClass() {
// class code here
}
}
On paper, this is also how it was in ActionScript 2.0, but in
fact, even non-dynamic classes could be altered at runtime by
manipulation of the Object.prototype
property
(inherited by all objects) or by the array access operator ([]
). Advanced programmers who used such an
approach in the past will find it no longer works in ActionScript 3.0
for sealed classes.
// ActionScript 2.0
var str:String = "";
str.customProperty = "Secret back door.";
// Displays: There is no property with the name 'customProperty'.
str["customProperty"] = "Secret back door.";
// Works just fine in ActionScript 2.0, but in 3.0 displays:
Cannot create property customProperty on String.
In ActionScript 3.0, non-dynamic classes actually are what they claim to be. This makes for stricter compile-time checking and improves memory usage because class instances can now be guaranteed to require no more than a pre-declared amount of system memory.
Method Closures
Of all the updates to ActionScript 3.0, it’s no surprise that developers, regardless of skill level, encounter one in particular early on: method closures. Why? Because the introduction of method closures changes the point of view, or scope, of methods in ActionScript 3.0.
Scope refers to the conceptual area of a program in which code executes. The availability of code definitions, such as variables, functions, properties, and methods, depends on the scope of the code being executed. For example, if a variable is declared in a timeline frame, that variable can be referenced by any other code in that frame, as long as that code appears after the declaration. Even a function defined in that frame can reference the variable scoped to the timeline, because scopes can be nested, and the flow moves from outer scope to inner: the timeline’s definitions become available to the function.
// A variable declared here ... var favoriteCereal:String = "Star Crunchers!"; // can be referenced here ... trace(favoriteCereal); // Displays: Star Crunchers! function myFunction():void { // and here ... trace(favoriteCereal); // Displays: Star Crunchers! } myFunction();
In contrast, a variable declared inside a function can only be referenced by that function, because the scope of the function is confined to itself.
function myFunction():void { // A variable declared here ... var favoriteCereal:String = "Star Crunchers!"; // can only be referenced here ... trace(favoriteCereal); // Displays: Star Crunchers! } myFunction(); // but not in the outer scope ... trace(favoriteCereal); // Displays: **Error** Scene=Scene 1, layer=Layer 1, frame=1:Line 10: Access of undefined property favoriteCereal.
Up to now, this should be familiar to ActionScript 2.0 developers. How, then, have things changed? Consider the next few examples.
In ActionScript 2.0, a button click might be handled like this:
// ActionScript 2.0 myButton.onRelease = buttonHandler; function buttonHandler():Void { trace(this); // Displays: _level0.myButton // other event handler code }
Prior to ActionScript 3.0, the scope of the function shown
belonged to the myButton
instance. In
this case, the button code could conveniently be abbreviated with the
use of the this
keyword, which self-referenced the current scope (myButton
). In some cases, this made for a
handy way to achieve certain goals. For example, to repeatedly loop a
Sound
instance in ActionScript 2.0,
the following would do:
// ActionScript 2.0 var audio:Sound = new Sound(); audio.loadSound("externalFile.mp3", true); audio.onSoundComplete = completeHandler; function completeHandler():Void { this.start(); }
Again, the function is scoped to the instance. In this case, the
expression this.start()
amounts to
invoking the Sound.start()
method on
the audio
instance. Although
convenient in this sort of situation, difficulties arose when the event
handler needed to reference objects outside the scope of the function,
especially in custom classes.
To a large extent, this issue could be addressed in ActionScript
2.0 with the Delegate
class,
which allowed you to reroute the scope as desired:
// ActionScript 2.0 import mx.utils.Delegate; var audio:Sound = new Sound(); audio.loadSound("externalFile.mp3", true); audio.onSoundComplete = Delegate.create(this, completeHandler); function completeHandler():Void { audio.start(); }
The Delegate.create()
method
accepted two parameters: first, the desired scope; second, the function
or method to execute in that scope. Note that because of this change,
the function invokes audio.start()
directly. In this case, the this
keyword no longer refers to the audio
instance to which the listener was attached, but rather to the timeline
frame in which the listener was assigned.
In ActionScript 3.0, method closures let a function or method
remember where it was defined. In short, you get the best of both worlds. In the
following ActionScript 3.0,
written in a keyframe, the reference to this
shows that the scope belongs to the main
timeline—to the frame in which the function is defined, rather than to
the myButton
instance. No extra
baggage, like the Delegate
class, is
required.
myButton.addEventListener(MouseEvent.CLICK, buttonHandler); function buttonHandler(evt:MouseEvent):void { trace(this); // Displays: [object MainTimeline] }
To reference the button rather than the frame, use the Event.target
property of the parameter that is passed into the function
automatically by the event. In this snippet, the parameter is
arbitrarily named evt
:
myButton.addEventListener(MouseEvent.CLICK, buttonHandler); function buttonHandler(evt:MouseEvent):void { trace(evt.target); // Displays: [object SimpleButton] trace(evt.target.name); // Displays: myButton }
ECMAScript for XML (E4X)
Flash has long supported XML, but the addition of ECMAScript for XML (E4X) syntax is a significant productivity boost. Like ActionScript, E4X is an Ecma International specification, which affords a powerful yet concise set of language constructs for retrieving data from XML, and manipulating it.
In ActionScript 2.0, you can certainly navigate among the nodes of
a loaded XML document, but the effort becomes progressively more tedious
as the XML’s complexity increases. The ActionScript 2.0 XML
class provides a handful of necessary
navigation properties, such as firstChild
, nextSibling
, lastChild
, and childNodes
. Choosing from these, and assuming an XML document has
already been loaded and parsed into an XML
instance named myXML
, you might select the title of the fifth
track of The Beatles’ Abbey Road album (“Octopus’s
Garden”) like this:
// ActionScript 2.0 myXML.firstChild.firstChild.firstChild.childNodes[4].attributes.¬ title; // Contents of the loaded XML document <?xml version="1.0" encoding="iso-8859-1"?> <library> <artist name="The Beatles"> <album name="Abbey Road"> <track title="Come Together" /> <track title="Something" /> <track title="Maxwell's Silver Hammer" /> <track title="Oh! Darling" /> <track title="Octopus's Garden" /> <track title="I Want You (She's So Heavy)" /> <track title="Here Comes the Sun" /> <track title="Because" /> <track title="You Never Give Me Your Money" /> <track title="Sun King" /> <track title="Mean Mr. Mustard" /> <track title="Polythene Pam" /> <track title="She Came in Through the Bathroom Window" /> <track title="Golden Slumbers" /> <track title="Carry That Weight" /> <track title="The End" /> <track title="Her Majesty" /> </album> </artist> </library>
In the preceding whopping expression, myXML
refers to the parsed XML document; the
three mentions of firstChild
refer,
respectively, to the <library>
,
<artist>
, and <album>
nodes; and childNodes[4]
refers to the fifth <track>
node (bear in mind, childNodes
returns an array, and arrays start
at zero). Finally, the attributes
property leads to the title
attribute
of the selected node.
E4X lets parsed XML be referenced as if it were a native object. This lets you traverse the loaded data incredibly more intuitively. In the ActionScript 3.0 equivalent, the same track can be referenced like this:
// ActionScript 3.0
myXML.artist[0].album[0].track[4].@title;
or, thanks to the descendent accessor operator (..
), even something as short as this:
myXML..track[4].@title;
Which would you rather type?
In addition, you can compare data using a familiar set of
operators. For example, if the XML document at hand contains numerous
recording artists, The Beatles’ <artist>
node could be singled out as
easily as this:
myXML.artist.(@name == "The Beatles")
Note
The E4X specification is available in Adobe PDF format at the Ecma International website: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-357.pdf.
Regular Expressions
The term regular expressions refers to a set of specialized language constructs for retrieving data from strings (that is, text content), and manipulating such data. In this regard, regular expressions (often abbreviated as regex) shares a number of similarities with E4X: both mechanisms are compact and efficient in their tasks. The syntax of regex tends to be initially harder to grasp than E4X—here, normal letters and punctuation are used to represent whole sets of characters, in addition to filtering rules—but the results are well worth the effort.
What can you do with regular expressions? To answer that, consider
two familiar methods of the String
class, indexOf()
and lastIndexOf()
, which have been available in
ActionScript for years. These methods both accept two parameters: first,
a string to look for within a container string; second, optionally,
where to start looking within the container string. Each method takes
its starting point from opposite ends of the container string.
var pangram:String = "The quick, brown fox jumps over a lazy dog."; trace(pangram.indexOf("o")); // Displays 13 trace(pangram.indexOf("o", 14)); // Displays 18 trace(pangram.lastIndexOf("o")); // Displays 40
In the first trace()
statement,
only one parameter is supplied, "o"
,
and the return value is 13 because the letter “o” makes its first
appearance at index 13 (starting with 0, the thirteenth character in the
string pangram
). In the second
statement, the return value is 18 because of the optional second
parameter 14
, which instructs the
method to begin after the index of the first “o”. In the third
statement, the return value is 40 because the method lastIndexOf()
begins its search from the end
of the string.
For simple searches, indexOf()
and lastIndexOf()
fit the bill, but
what if the requirement is something like “find all US ZIP codes,” which
could be any 5-number combination, or “find all words in this paragraph
that contain three or more vowels”? Suddenly, the task seems
considerably more difficult, if not impossible. Believe it or not, the
RegExp
class in ActionScript 3.0
handles this requirement very easily. The solution requires a
pattern of specialized characters, expressed either
as an instance of the RegExp
class or
passed as a parameter to one of the regex-related methods of the String
class (match()
, replace()
, or search()
).
Given a variable, paragraph
,
set to the text content of the previous paragraph, the following code
shows how to retrieve words with three or more vowels:
var re:RegExp = /\b(\w*[aeiou]\w*){3}\b/gi;
var result:Object = re.exec(paragraph);
while (result != null) {
trace(result[0]);
result = re.exec(paragraph);
}
// Displays: searches, indexOf, lastIndexOf, requirement,
// something, and other words with three or more vowels
A full discussion of regular expressions syntax is beyond the
scope of this book, but here’s a brief overview of how the previous
example works. A variable, re
, is set
to an instance of the RegExp
class by
way of the RegExp delimiter operator (/
pattern
/
flags
). Between
the two slashes of this operator, the pattern \b(\w*[aeiou]\w*){3}\b
spells out the search
requirement. After the second slash, the flags (gi
) configure the pattern as global and case
insensitive. The RegExp.exec()
method
executes the pattern on the string paragraph
and returns an object (result
) that contains information about the
search. The search is repeated until result
is null
.
If the preceding example seems outlandish, imagine the same sort of power applied to the validation of user input. You can manage even potentially complex requirements without much difficulty. These include questions such as, “Is this email address correctly formed?” (Checking for the “@” character isn’t enough!) “Is this a valid telephone number?” (People might enter anything from (123) 456-7890 to 123.456.46789 to 123456789.) “Has the user tried to sneak in an inappropriate word by using a nonstandard spelling?” Patterns that match these requirements not only find the strings in question, but can also manipulate them in order to, for example, format telephone numbers consistently or replace questionable words with Xs.
Note
For an exhaustive and highly regarded treatise on regular expressions, be sure to read Mastering Regular Expressions, by Jeffrey Friedl (O’Reilly). Numerous tutorials are also available online at the unrelated http://www.regular-expressions.info/ website.
Namespaces
In advanced programming scenarios, the concept of
namespaces brings a valuable new mechanism to
ActionScript 3.0. In short, namespaces are essentially custom access
specifiers—like public
, private
, protected
, and internal
—except with names you choose.
Namespaces let you control the visibility of your properties and
methods, even to the point of overriding package structures. They also
let you qualify members under various guises. As a quick example, you
might develop an AIR application that performs one behavior while an
Internet connection is present, and another when no connection is
present. By using namespaces, you can define multiple versions of the
same method that, for instance, checks an online inventory when the
user’s WiFi connection is available but defaults to a cached version
otherwise. Or you might define series of variables in several languages,
where the value of a variable depends on the user’s regional settings.
These distinctions are determined by custom prefixes and the name
qualifier operator (::
):
// Three versions of the same String variable english::newFeatures // Value of "Lots of new stuff" german::newFeatures // Value of "Viele neue Sachen" french::newFeatures // Value of "Plien de nouvelles choses"
Namespaces are outfitted with a Universal Resource Identifier (URI) to avoid collisions, and are also used to represent XML namespaces when working with E4X.
New Primitive Types
ActionScript 3.0 introduces two new primitive types, int
and uint
, bringing the full list to Boolean
, int
, Null
,
Number
, String
, uint
, and void
(note the change in capitalization from
Void
). These new numeric types reduce memory usage in cases when
a numeric value need only be an integer. How? The familiar Number
data type is an IEEE-754 double-precision floating-point number,
which, thanks to its structure, always requires 64 bits of
memory. Number
objects range from
1.79e+308 (1.79 with over 300 zeroes after it!) down to 5e-324. That’s
an unimaginably large range, which isn’t always necessary. Sometimes you
just want to count through a for
loop, and all you need is an integer.
Enter int
, which is a
relatively small 32-bit number (only 4 bytes), whose range is still an
impressive 2,147,483,647 (over two billion) down to −2,147,483,648. That
range should do for most of the for
loops you’ll encounter. By contrast, uint
numbers (unsigned integers) range from 0
to 4,294,967,295, which is the same span as int
, but entirely on the positive side of the
number line. If your for
loop’s
counter, or any other integer value, needs a higher range than offered
by int
, uint
makes a good choice—provided the range
doesn’t dip below zero. Neither type ever requests more than 32 bits of
system memory.
Warning
One note of caution: because uint
values are always positive, take care
when trying to subtract a uint
into
negative territory. A uint
rolls
around to 4,294,967,295 if you subtract it past zero, as the following
code demonstrates.
var n:uint = 0; trace(n); // Displays 0 n--; trace(n); // Displays 4294967295
Exploring Flash Player API Updates
In the “ActionScript 3.0, the Language” section of this chapter, you learned that the ECMAScript specification on which ActionScript is based actually expects the language to provide functionality tailored to the platform that hosts it. In the case of ActionScript, hosts include Flash Player, AIR, and Flash Lite—all various flavors of the Flash Platform. Though each host is designed to meet specific needs—websites, desktop applications, and mobile content, respectively—their overlap is considerable. ActionScript 3.0 institutes a significant restructuring of its application programming interface (API), summarized handily in the colossal migration table available on the Adobe LiveDocs website (http://help.adobe.com/en_US/AS3LCR/Flash_10.0/migration.html) and also in the Help panel in the appendices of the ActionScript 3.0 Language and Component Reference, under the heading “ActionScript 2.0 Migration”. In large part, existing functionality has been restructured into packages that make better sense from an organizational standpoint. However, Flash does have a number of philosophical changes in the way it carries out its fundamental tasks. The following paragraphs list some of the more notable updates.
Note
As of the publication of this book, Flash Lite does not yet support ActionScript 3.0, due to the inherent processor and memory limitations of mobile devices. The features recounted here apply to Flash Player 9 (and higher) and AIR, but won’t apply to Flash Lite until that runtime adds support for ActionScript 3.0.
DOM3 Event Model
Before ActionScript 3.0, you could handle events in Flash in at least five different ways, some of which were interchangeable:
The legacy
on()
handler, available since Flash 2 and still in wide use, even in ActionScript 2.0 scenarios, but gone in ActionScript 3.0The legacy
onClipEvent()
handler, also widely used and unavailable in ActionScript 3.0The dot notation syntax that combined and replaced
on()
andonClipevent()
(for exampleButton.onPress =
functionDefinition
,MovieClip.onEnterFrame
, and so on)The
addListener()
method of several—but not all!—ActionScript 2.0 classes, such asTextField
,Mouse
, andMovieClipLoader
The
addEventListener()
method used by the v2 component set (user interface, data, and media components)
This varied assortment was a result of incremental improvements to ActionScript with every new release of the authoring tool, with the older approaches retained for backward compatibility. For longtime Flash developers, each new technique was simply a small addition to the workflow, but newcomers to recent versions, such as Flash 8 or Flash CS3, were understandably confused by an API with so many seemingly arbitrary possibilities.
Note
Are on()
and onClipEvent()
really so bad? From a workflow
standpoint, no. From a practical standpoint, they aren’t nearly as
valuable as their dot notation replacement. In ActionScript 2.0, the
combination of on()
and onClipEvent()
provide access to only
slightly more than half the events available to movie clips and
buttons. In addition, you can’t assign, manipulate, or remove their
event handlers at runtime. Their absence in ActionScript 3.0 marks the
end of a long transition period from ActionScript 1.0 through
2.0.
Because ActionScript 3.0 relies on a new virtual machine, it can
afford to make a clean break in the way it handles events. With one
small exception (discussed in Chapter 4), event handling is
now consolidated across the board into a single, consistent approach:
the EventDispatcher.addEventListener()
method.
This mechanism is based on the W3C’s Document Object Model
(DOM) Level 3 Events Specification (http://www.w3.org/TR/DOM-Level-3-Events/). This means that in ActionScript 3.0, event handling syntax
is the same in nearly all cases, no matter if the event dispatcher is a
button, an audio clip, or a loader object for XML or JPEG files. The
basic structure looks like this:
eventDispatchingObject
.addEventListener(EventType
,functionToPerform
);
Display List API
In ActionScript 3.0, movie clips can be instantiated with the
new
keyword as easily as
this:
var mc:MovieClip = new MovieClip();
which is more intuitive than what it took in ActionScript 2.0:
var mc:MovieClip =existingMovieClip
.createEmptyMovieClip(¬instanceName
,depth
);
And it gets better. Depth management is now automatic. Notice that the expression new MovieClip()
does not require a depth
parameter. This change is due to a fundamental new approach to the
display of visual objects in ActionScript 3.0: a concept called the
display list, which represents the hierarchical display of all graphical
objects in Flash Player. This concept is embodied in the DisplayObjectContainer
class, the base class for all objects that can serve as visual
containers, including movie clips, the new Sprite
and Loader
classes, and more. Thanks to
inheritance, DisplayObjectContainer
provides new methods to these classes for considerably better control
over the management of object z-order. For example, while the MovieClip
class in ActionScript 2.0 featured
getDepth()
and swapDepths()
, the ActionScript 3.0 version
offers all of these:
addChild()
addChildAt()
contains()
getChildAt()
getChildByName()
getChildIndex()
removeChild()
removeChildAt()
setChildIndex()
swapChildren()
swapChildtenAt()
How’s that for control?
These methods are also available to Sprite
, which is effectively a movie clip without the overhead of
a timeline; Loader
, which loads external SWF files and image files (JPEG, PNG,
or GIF) at runtime; and any other class in the DisplayObjectContainer
family
tree.
Under the display list system, objects can be re-parented at any time. This ability simplifies cases in which groups of objects need to be manipulated at once. Consider a jigsaw puzzle game, for example. If you want to combine partially solved areas, so that snapped-together pieces move as one unit, you can simply remove the piece from its current parent and add it as a child to the parent that represents the partially solved group. Before ActionScript 3.0, this action would have required individual sophisticated tracking of each jigsaw piece.
New Sound APIs
Flash Player 8 was the first to support 32 simultaneous sound
channels, a significant increase from the original eight-sound channel
limit. Although present for as long as Flash Player has supported sound,
these sound channels, as such, had no clear representation in code
before ActionScript 3.0. In previous versions of the language, the
Sound
class was self-contained,
handling all of its functionality in a relatively simple manner, but at
the cost of some clarity of purpose. For example, in order to control
the volume and panning of one sound distinctly from another, you had to
associate each sound with its own movie clip. You made this association
by way of an optional “target” parameter in the Sound
constructor function. Because target
movie clips might or might not contain other content, their ambiguous
roles had the potential to confuse.
ActionScript 3.0 clarifies programmed sound by complementing the
Sound
class with three companions:
SoundChannel
, SoundTransform
, and SoundMixer
. These new APIs give you more
explicit control over imported and embedded sounds. The SoundMixer.computeSpectrum()
method even lets
you retrieve spectral data from sounds, which you can use to program
responses to changes in audio pitch and volume.
Binary Data and Sockets
The new ByteArray
class enables
interoperability with existing custom protocols, and lets advanced
developers read, write, and manipulate data on the byte level. This has
led adventurous programmers to cultivate projects previously unheard of
in Flash, such as Tinic Uro’s PNG encoder (http://www.kaourantin.net/2005/10/png-encoder-in-as3.html,
now updated and featured in the as3corelib library at http://code.google.com/p/as3corelib/) and a dynamic tone
generator by André Michelle and Joa Ebert, capable of playing MIDI-like
Amiga MOD files (http://8bitboy.popforge.de/).
Understanding Players and Support
Although this book focuses primarily on the Flash authoring tool, it’s important to realize that Adobe offers two official ActionScript 3.0 compilers. One of these compilers is built into Flash CS4 itself. As you would expect, this one takes into consideration objects in the document’s Library, as well as global SWF file settings, such as background color and frame rate, as configured in the Property inspector. This compiler can also compile previous versions of ActionScript. Separate from that, there’s the command line compiler included with the free Flex Software Development Kit (SDK) available at http://www.adobe.com/go/flex_trial/. This second compiler is the one used by the Flex Builder integrated development environment (IDE), which doesn’t include drawing tools, timelines, or a library. In addition to ActionScript 3.0, the Flex compiler understands MXML, the declarative markup language used for laying out Flex applications. For want of a library, the second compiler lets metadata embed assets into resultant SWF files. The Flash authoring tool supports only limited metadata, an undocumented feature at the time of writing.
These distinct compilers serve independent workflows. To facilitate the development of RIAs, the Flex SDK features an elaborate framework of user controls and data handlers that aren’t available to the Flash authoring tool, even though the framework is written in ActionScript 3.0. By comparison, Flash offers a modest subset of user controls in its Components panel, including support for the playback and manipulation of Flash video files (FLV).
In the end, there’s only one ActionScript 3.0, and it behaves the same when compiled under either tool. The reason for this consistency is that Flash CS4 and the Flex SDK both publish SWF files for the same Flash Player 9 or higher. It’s quite possible—and often done—to create custom classes that can be used under either circumstance. The concept of the document class (see Chapter 6), introduced in Flash CS3, means that an entire application, composed of numerous external classes, can be compiled by Flash or the Flex command line compiler (including Flex Builder) from identical source files.
Because ActionScript 3.0 requires AVM2, as mentioned earlier in this
chapter, Flash Player 9 is the minimum required runtime to display such
content. Flash Player 9 runs on numerous operating systems, including
several versions of Windows, Macintosh, Linux, and Solaris. Due to the varied nature of these operating systems and
occasional bug fixes required by each, in addition to ongoing new
features, Flash Player 9 includes a number of minor point releases, as
summarized in Table 1-1.
Flash CS4’s default output is aimed at Flash Player 10, which may
eventually see a list of minor point releases just as long. Time will
tell. To determine what version of Flash Player the user has installed,
reference the static version
property
of the Capabilities
class.
Flash Player version | Notable changes |
9.0.16.0 | ActionScript 3.0, including runtime exceptions and error handling, sealed classes, method closures, ECMAScript for XML (E4X), regular expressions, namespaces, new primitive types, DOM3 event model, display list APIs, new sound APIs, and binary data and sockets. |
9.0.20.0 | Bug fixes and optimizations related to the Intel-based Macintosh platform. |
9.0.28.0 | Support for Windows Vista
operating system. Addition of |
9.0.31.0 | Support for Linux operating systems. |
9.0.45.0 | Bug fixes and improvements for Adobe Flash CS3 Professional. Affects only Windows and Macintosh platforms. |
9.0.47.0 | Support for Solaris operating system. Security enhancements. |
9.0.48.0 | Linux security enhancements. |
9.0.115.0 | H.264 video and High Efficiency AAC (HE-AAC) audio codec support. Hardware acceleration, hardware scaling, multi-threaded video decoding, and enhanced image scaling. Flash Player cache enables common components, such as the Flex Framework, to be cached locally and then used by any SWF from any domain. Flash Media Server buffering maintains stream buffer while a stream is paused. |
9.0.124.0 | Media streaming security patch and minor display update for Windows Vista. |
Note
A full listing of all Flash Player release notes, including bug fixes, can be found at http://www.adobe.com/support/documentation/en/flashplayer/releasenotes.html.
Learning ActionScript 3.0 on the Heels of 2.0
Pretend for a moment you’re a carpenter. For years, you were making do with a hand-crank drill, but then the Macromedia Hardware Company introduced an electric model called ActionScript 1.0 stamped with gold letters on the handle. Beautiful thing! No reason to ever use anything else. Sure, you could operate the drill only within six feet of an electrical outlet (because that was the length of the cord), but the advantages were resoundingly clear. Plus, you could always carry around an extension cable. A few years later, Macromedia announced a new and improved ActionScript 2.0 model. This drill had an optional battery back. For some, the new battery pack was a godsend, because it freed them from the previous six foot limitation. They embraced the new feature and literally found themselves running with it. Other carpenters found the battery pack a bit too advanced. They weren’t sure, for example, if they were supposed to drain the batteries completely before recharging. And honestly, that was fine: the drill still had a cord, of course, so they continued within their previous comfort zone, which was still a considerable improvement over the hand-crank days. Carpenters were a happy bunch. Eventually, the Macromedia Hardware Company became Adobe. Everyone looked forward to the new drill—ActionScript 3.0—and when it came ... they found that the cord had been replaced with a docking station. Suddenly, carpenters who had opted not to use the ActionScript 2.0 battery pack felt trapped. They had no experience with batteries, but if they were going to use an ActionScript 3.0 model, they had no choice.
It goes without saying that every analogy has its flaws. Certainly,
the changes in ActionScript 3.0 amount to more than the obvious benefit of
a battery pack. Clearly, the new APIs are more complex than the question
of how to recharge a set of batteries. In any case, ActionScript does a
lot more than drill holes! Still, it can be useful to think of
ActionScript 2.0 as a preparatory transitional period between, on one
hand, the very roots of the language—that is, ActionScript 1.0 and even
earlier—and, on the other hand, the current version. As with the carpenter
story, numerous features in ActionScript 2.0, such as strict typing
(:Number
, :Void
, etc.) and formalized custom class files,
were optional. (Unlike the analogy, those particular features are still
optional in ActionScript 3.0.) Voluntary though they were, such then-new
conventions were an early invitation to practice a more efficient
workflow. Developers who opted to experiment with
object-oriented programming (OOP), to the point of
writing their own custom classes, may feel more at home with ActionScript
3.0 than others. For those who were perfectly comfortable with the
conventions of ActionScript 1.0,
they might understandably feel trepidation in light of the current
version, especially now that ActionScript 3.0 has dropped support for some
previously optional features, such as on()
and onClipEvent()
. Flipping through the ActionScript
3.0 Language and Components Reference takes considerably longer than
before. Everything has been arranged into a potentially overwhelming new
hierarchy of packages. Most of the Help panel sample code has been written
as class files, to make it applicable both for keyframe and class file
programmers.
These changes are big, but not insurmountable. One of this book’s driving purposes is to help you feel caught up, whether or not you pursued the optional new conventions of ActionScript 2.0—the features that, in hindsight, were a gentle ramp up to today’s recommended best practices. The important thing to keep in mind is that ActionScript 3.0 is scalable in terms of complexity. If you want to plunge headlong into OOP principles such as inheritance and design patterns, ActionScript 3.0 will oblige. If you prefer to stick with traditional timeline coding, ActionScript 3.0 will oblige—with a number of provisos covered in the following chapters.
Deciding to Migrate or Write Code from Scratch
If you work with a set of in-house templates, be they FLA files, custom classes, or a combination of both, sooner or later you’ll have to decide how to update them. For the sake of discussion, these files are stable ones that have made your company money for years, and they work just fine. Nonetheless, you’d like to take advantage of the speed increases—or any of the other benefits—afforded by ActionScript 3.0. Should you painstakingly tinker with existing files, tweaking as you go, or should you ditch everything and start from square one? Which approach would require less effort?
For better or worse, there is no sure-fire way to determine which endeavor is more advantageous in a given situation. While you can theoretically upgrade a FLA file’s Publish Settings to ActionScript 3.0 and compile without errors or warnings, the prospect becomes progressively more unlikely as a project gains in complexity. Chances are high that one incompatibility will occur in concert with many: in other words, when it rains, it pours. That said, here are a few thoughts to consider.
If all or most of your code exists on frames in a FLA file, you may
have no realistic choice but to migrate the ActionScript in place, for the
obvious reason that the code is so closely tied to the file’s visual
design. To start from scratch could require careful transportation of
symbols from one FLA file to another, possibly including intricate nested
timeline effects. For simple banner ads and linear slideshows, an in-place
update may not be as difficult as it sounds. Standalone calls to stop()
, gotoAndPlay()
, and the like, will carry over
without a hitch. By all means, select File→Publish
Settings→Flash→Script→ActionScript 3.0, and then hold your breath and see
what happens.
Don’t forget to exhale if the compile works, and frankly, prepare
yourself now for numerous entries in the Compiler Errors panel. If any of
the frame code involves event handlers, loads external assets, or even
calls a new web page (getURL()
is now
navigateToURL()
), you’ll have to update
it. The good news is, the Compiler Errors panel is one of many helpful new
tools in Flash CS4 (introduced in
Flash CS3). This panel not only tells you where the erroneous code is, by
class file, scene, layer, keyframe, and line number, it often makes
suggestions on what to change, including a list of common migration
issues.
Note
The Compiler Errors panel and other debugging tools are covered in Chapter 11.
If most of your code exists in external class files, your project probably involves more than a smattering of ActionScript. Although this likely means you’ll spend more time on code migration (because there’s more of it!), the fact that your code is separate means you can test and revise each class individually. In either case, frame code or class files, this book will help you get your bearings.
Get The ActionScript 3.0 Quick Reference Guide now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.