A Sample Migration: Chapter 18 - ActionScript 3.0 Quick Reference Guide
Pages: 1, 2
The following are the ActionScript 3.0 versions of the two previous scripts. Only language version-specific comments are included here so, if you’re unclear on overall functionality, see the equivalent ActionScript 2.0 section.
The following is the main timeline frame script.
1 import fl.controls.Button;
2
3 var imgURL:String = "bg.jpg";
4 if (root.loaderInfo.parameters.imgURL) {
5 imgURL = root.loaderInfo.parameters.imgURL;
6 }
7 var txtFrmt:TextFormat = new TextFormat();
8 txtFrmt.align = TextFormatAlign.RIGHT;
9 var txtFld:TextField = new TextField();
10 txtFld.x = 380;
11 txtFld.y = 10;
12 txtFld.width = 100;
13 txtFld.height = 380;
14 txtFld.defaultTextFormat = txtFrmt;
15 addChild(txtFld);
16
17 var bg:Loader = new Loader();
18 addChildAt(bg, 0);
19 bg.load(new URLRequest(imgURL));
20
21 var snd:Sound = new Sound();
22 snd.load(new URLRequest("../audio/bass_back.mp3"));
23 snd.addEventListener(Event.COMPLETE, onSoundLoaded, false, 0, ¬
true);
24 function onSoundLoaded(evt:Event):void {
25 var sndChannel:SoundChannel = new SoundChannel();
26 sndChannel = evt.target.play(0, 100);
27 var sndTransform:SoundTransform = sndChannel.soundTransform;
28 sndTransform.volume = .1;
29 sndChannel.soundTransform = sndTransform;
30 evt.target.removeEventListener(Event.COMPLETE, onSoundLoaded);
31 }
32
33 var particles:Particles = new Particles();
34 addChild(particles);
35
36 var controls:MovieClip = new MovieClip();
37 controls.y = 360;
38 addChild(controls);
39
40 var siteLink:String = "http://www.learningactionscript3.com/";
41 var linkBtn:SimpleButton = new BtnLink();
42 linkBtn.x = 20;
43 controls.addChild(linkBtn);
44
45 linkBtn.addEventListener(MouseEvent.CLICK, onShowLink, false, 0, ¬
true);
46 function onShowLink(evt:MouseEvent):void {
47 navigateToURL(new URLRequest(siteLink), "_blank");
48 }
49
50 var changePBtn:Button = new Button();
51 changePBtn.x = 120;
52 changePBtn.label = "Change";
53 controls.addChild(changePBtn);
54
55 changePBtn.addEventListener(MouseEvent.CLICK, onChangeParticle,¬
false, 0, true);
56 function onChangeParticle(evt:MouseEvent):void {
57 var p:MovieClip = MovieClip(particles.getChildByName(¬
"particle" + (particles.count - 1)));
58 if (p != null) {
59 p.graphics.clear();
60 p.graphics.beginFill(0xFF0000);
61 p.graphics.drawRect(-20, -20, 40, 40);
62 p.graphics.endFill();
63 particles.particleSound(p);
64 }
65 }The following is an explanation of ActionScript 3.0-specific issues that appear in the main timeline frame script.
ImportNotice in Line 1 that the class path has changed from
mxtofl.FlashVarsFlashVarsare no longer stored as global variables in the root timeline. Instead, they’re stored in theparametersobject of theLoaderInfoinstance of the root, as seen in line 4.TextFormatAlthough you can use appropriate string values, it is a best practice to use relevant constants for many property values in ActionScript 3.0. In this case, the format’s
alignproperty is populated with theRIGHTconstant of theTextFormatAlignclass, used in line 8.
The application of the
TextFormatinstance in line 14 has been changed fromsetNewTextFormat()todefaultTextFormat().TextFieldAll display objects are created with a simple consistent
new<class name>()structure. The ActionScript 2.0 TextField creation method is replaced with the ActionScript 3.0 instantiation (line 9) and followed by the assignment of property values (lines 10 through 14).- Depth Management
The ActionScript 3.0 display list automatically handles depth management so you don’t have to manually assign levels or worry about methods like
getNextHighestDepth()or theDepthManager. As such, you don’t see any level assignments in any of the object instantiation routines.However, you can still control depths. For example, you still have a
swapDepths()method for moving the background image below the text field, as seen in line 14 of the ActionScript 2.0 main timeline frame script code. However, you have an easier way to handle this when objects are added to the display list. In ActionScript 2.0, existing objects are replaced when a new object is added to the same level. ActionScript 3.0, however, moves all objects above the target level one level higher, and then inserts the addition where specified.Therefore, you can easily place the background image behind the text field when the image is added, as seen in line 18. The
addChildAt()method is used, specifying level 0. The background image appears in level 0, and the text field is moved to level 1.- Variable Declaration
While you can in some cases omit typing a variable, all variables must be declared with the
varidentifier.- Image Loading
Rather than creating an empty movie clip, a
Loaderdisplay object is used lines (17 through 19). Instead of using the image path as a string for theload()method, ActionScript 3.0 requires a consistent use of theURLRequestclass for processing the URL prior to use.- Sound
Although the creation of the
Soundinstance is the same (line 21), sound management diverges significantly from that point on. Loading is similar, with a change of method name to the more consistentload()and the ever-neededURLRequestinstance instead of a string. The event handling is significantly different in ActionScript 3.0 (and is explained in a moment), but the idea behind it, as it pertains to sound, is the same: wait until the sound is loaded, and then proceed.However, three new classes play a big part of sound management. First, each sound is typically played into its own discrete sound channel, an instance of the
SoundChannelclass (lines 25 and 26). This step is a requirement if you wish to perform sound transformations. Where thevolumeandpanproperties existed in theSoundclass in ActionScript 2.0, they’re now accessible through thesoundTransformproperty of theSoundChannelclass.To effect such a change, an instance of the second new class,
SoundTransformis derived from theSoundChannel soundTransformproperty (line 27), the desired property is changed (volume, line 28) and the new instance is reapplied to theSoundChannel soundTransformproperty once again (line 29).The third new class, not used in this example, is the
SoundMixerclass. This class lets you manipulate all the sounds at once. The isolation of sounds into their own discrete channels lets you control each sound separately and with greater precision.- Handling Events
Event handling is very different in ActionScript 3.0. For detailed information, see Chapter 14, How Do I Work with Events?. From a migration standpoint, event handlers are no longer attached to the target of the event. Instead, event listeners are created, specifying an event to listen for, and a function to trigger upon an occurrence of that event (lines 23 through 31).
A mandatory parameter is used to receive information from the event that can be used inside the function. For example, the target of the event in the mentioned listener is the
sndobject. That is referenced byevt.targetin lines 26 and 30.The events are specified as constants, as discussed previously with the
TextFormatalign property, and optional parameters allow more granular control over when the event is processed (capture or target/bubbling phases and priority) as well as whether weak references are used for a little backup help in the memory management department.Finally, you should remove the listener when you no longer need it, for optimal memory management (line 30). You also find event listeners in lines 45 through 48, and 55 through 65.
- Void
Void is now lower case (lines 24, 46, 56).
- Percent Values Scale
Percent value scales are now from 0 to 1 (instead of 0 to 100).
- Dynamic Creation of Movie Clip and Instantiation of Custom Class
ActionScript 3.0 lets you much more easily use custom classes as display objects. You don’t need to rely on a Library-based symbol, or more convoluted methods, to instantiate the class. Instead, provided the class extends
MovieClip,Sprite, Shape, or another applicable display object, you just need to instantiate it the way you would any other display object:new <classname>();(line 33). You must then add the instance to the display list for the user to see it.Another movie clip is dynamically generated in line 36. Note the simplicity of creating an empty movie clip container (to hold buttons). Rather than using one of many methods, such as
createEmptyMovieClip(), the consistentnew MovieClip()approach is all you need, coupled with theaddChild()method on line 38.- Property Underscores
Line 37 is one example of the fact that ActionScript 3.0 properties are not preceded by an underscore.
- Custom Button Instantiation
The same custom button used in the ActionScript 2.0 version can be instantiated here as a proper button (
SimpleButton, line 41) rather than using aMovieClipmethod and typing the instance as aMovieCliporObject. It’s then positioned, and added to the display list (lines 42 and 43, respectively).- Dynamic versus Sealed Classes
In this case, however, the
SimpleButtonclass is a sealed class, so you can’t add the site URL used by the button as a property. In this case, it’s stored in a standard variable.You could have brought these two examples into a more parallel structure by using movie clips for buttons in both cases, because
MovieClipis a dynamic class and would allow the addition of a property. However, the purpose of this chapter is not to change the way you want to work, but to understand how best to migrate a legacy project to the new syntax of ActionScript 3.0. Taking advantage of the newSimpleButtonclass is desirable, and even lets you create a button entirely from code (no Library assets) if preferred.To see an exact parallel, you can add an example property to the text field instance in both versions of the project. In the ActionScript 2.0 version, adding
txtFld.inUse = true;after line 10 works. However, adding the same line in the ActionScript 3.0 version after line 15 generates an error because the
TextFieldclass is sealed in ActionScript 3.0.- Opening a URL
Line 47 shows the new syntax for accessing a URL, using the
navigateToURL()method andURLRequestinstance.- Dynamically Instantiating a Component
Adding a component to your project on the fly is really no different from adding a movie clip or other display object. Just use the
Buttonclass as you would another display object class, as seen in line 50. (As with a custom asset, a Button component must be in your Library.)- Accessing Objects by Instance Name
You can’t access a dynamically created object directly by instance name. That is, setting the name property in ActionScript 3.0 doesn’t make it possible to reference the object using the dot syntax object model. Instead, you must use the
getChildByName()method, as seen in line 57.- Using the Graphics Class (formerly the Drawing API)
Although the
clear(),beginFill(), andendFill()methods are the same in ActionScript 3.0, they’re methods of theGraphicsclass, accessed through thegraphicsproperty instance of each relevant display object. Further, you don’t need a custom function to draw a rectangle, as the newdrawRect()method does that for you.
The Particles class
functionality is the same in ActionScript 3.0. It creates each particle,
establishes its behavior, and ultimately removes it from the
project.
1 package {
2
3 import flash.display.*;
4 import flash.events.*;
5 import flash.media.*;
6 import flash.net.*;
7
8 public class Particles extends Sprite {
9
10 private var _count:int;
11 private var _soundNum:int = 0;
12 private var _tempSound:Sound;
13
14 public function Particles() {
15 addEventListener(Event.ADDED_TO_STAGE, onAdded, ¬
false, 0, true);
16 addEventListener(Event.ENTER_FRAME, onLoop, false, ¬
0, true);
17 _tempSound = new Sound(new URLRequest( ¬
"../audio/note0.mp3"));
18 _tempSound.addEventListener(Event.COMPLETE, ¬
onSoundPreloaded, false, 0, true);
19 }
20
21 private function onAdded(evt:Event):void {
22 x = this.stage.stageWidth / 2;
23 y = this.stage.stageHeight / 2;
24 removeEventListener(Event.ADDED_TO_STAGE, onAdded);
25 }
26
27 private function onSoundPreloaded(evt:Event=null):void {
28 _tempSound.removeEventListener(Event.COMPLETE, ¬
onSoundPreloaded);
29 if (_soundNum < 7) {
30 _soundNum++;
31 _tempSound = new Sound(new URLRequest(¬
"../audio/note" + _soundNum + ".mp3"));
32 _tempSound.addEventListener(Event.COMPLETE, ¬
onSoundPreloaded, false, 0, true);
33 }
34 }
35
36 private function onLoop(evt:Event):void {
37 makeParticle(0x0066CC, Math.random() * 10 + 10);
38 }
39
40 private function makeParticle(col:uint=0x003366, ¬
size:Number=20):void {
41 if (Math.random() * 10 <= 2) {
42 var p:MovieClip = new MovieClip();
43
44 if (isNaN(_count)) { _count = 0; }
45 p.name = "particle" + _count;
46 _count++;
47
48 p.graphics.beginFill(col);
49 p.graphics.drawRect(-size/2, -size/2, size, size);
50 p.graphics.endFill();
51
52 p.xVel = Math.random() * 10 - 5;
53 p.yVel = Math.random() * 2 - 1;
54
55 p.addEventListener(Event.ENTER_FRAME, ¬
onRunParticle, false, 0, true);
56 addChild(p);
57
58 MovieClip(parent).txtFld.appendText(p.name + "\n");
59 MovieClip(parent).txtFld.scrollV = ¬
MovieClip(parent).txtFld.maxScrollV;
60 }
61 }
62
63 public function particleSound(p:MovieClip):void {
64 if (!p.snd && _soundNum > 0) {
65 var num:int = int(Math.random()*_soundNum);
66 p.snd = new Sound(new URLRequest(¬
"../audio/note" + num + ".mp3"));
67 p.channel = new SoundChannel();
68 p.channel = p.snd.play();
69 }
70 }
71
72 private function onRunParticle(evt:Event):void {
73 evt.target.x += evt.target.xVel;
74 evt.target.y += evt.target.yVel;
75 evt.target.rotation += 5;
76 evt.target.alpha -= .02;
77
78 if (evt.target.snd) {
79 var trans = evt.target.channel.soundTransform;
80 trans.volume = evt.target.alpha / 10;
81 trans.pan = (evt.target.x / this.x) * 2;
82 evt.target.channel.soundTransform = trans;
83 }
84
85 if (evt.target.alpha <= 0) {
86 if (evt.target.snd) {
87 evt.target.channel.stop();
88 }
89 evt.target.removeEventListener(Event.ENTER_FRAME, ¬
onRunParticle);
90 removeChild(MovieClip(evt.target));
91 }
92 }
93
94 public function get count():int {
95 return _count;
96 }
97 }
98 }As with the ActionScript 2.0 section, basic syntax issues discussed in the main timeline won’t be mentioned again.
- Class Structure
Line 1 shows that all ActionScript 3.0 classes must be enclosed in a
packagestatement. This line would also be where you would include a path to the class, if desired. Lines 8 and 14 remain consistent with ActionScript 2.0.- Import
Lines 3 through 6 import all the classes to make them accessible to the compiler. Unlike ActionScript 2.0, even classes in Flash Player must be imported.
- Class Properties
Lines 10 through 12 are consistent with ActionScript 2.0.
- Number Data Types
Lines 10 and 11 use the
intdata type because you don’t need float values. You can also see this characteristic in lines 40 and 65. 40 is a good example, as theuintdata type is used, because a color value can’t be negative.Much has been made of the performance of the
uintdata type and, to a lesser degree, theintdata type, so you can decide whether or not to use them. This is just an example.- Access to Stage
Unlike ActionScript 2.0, the stage isn’t a global object. Instead, you must access the stage through a display object. The
Particlesclass both extendsMovieClip, and is added to the display list in the main timeline frame script, so you can access the stage without passing a reference to it through the constructor.However, you can access the stage only after the display object has been added to the display list. Therefore, this class can’t access the stage within its constructor, as the class hasn’t yet been fully initialized. Instead, a new event listener is added to listen for the Event.ADDED_TO_STAGE event (line 15). Once this event fires, the display object is part of the display list, and the stage reference doesn’t return
null.Lines 21 through 25 contain the function used for this purpose and, because the listener is no longer necessary, it’s removed upon execution of this function. (The
thiskeyword is not strictly needed because the relevant scope is the class itself, but it’s been added to emphasize that you’re accessing the stage through a display object.)- Class Enter Frame Event
The use of the enter frame event for the class is the same; however, note that, because event handlers no longer exist, you can’t just name a function
onEnterFrame()and expect it to work. You must convert that structure to an event listener design, seen in lines 16 and 36 through 38.- Method Closures
You no longer need the
Delegateclass, as ActionScript 3.0 supports method closures.- Preloading Sounds
The sound preloading routine hasn’t changed, and doesn’t include any ActionScript 3.0 syntax issues that haven’t already been discussed, with one small exception. If you pass a valid URLRequest instance to the
Soundclass constructor, as in line 31, theload()method is automatically called.It’s also a good idea to look this method over with regard to removing listeners. It’s important to remove the load complete listener from
_tempSoundafter each sound has been loaded (or, if you prefer, after the last sound has loaded) to prevent the listener from remaining on the last sound.- Particle Creation
ActionScript 3.0 has nothing unique in the
makeParticle()method that hasn’t been, or won’t be, discussed elsewhere. However, be sure to read about changes to default values, accessing objects in the parent, and using the Drawing API (now commonly referred to as theGraphicsclass).- Default Values
ActionScript 3.0 allows the assignment of default values to method arguments, as seen in line 40. This action makes the associated arguments optional, but all optional arguments must appear at the end of the method signature.
Further, default values for data types have changed in ActionScript 3.0. For example, line 44 can no longer test for
undefined, as the default value for number data types isNaN(not a number). As such, you must use theisNan()method to validate its value.As is true with many intentionally injected migration issues in this exercise, this could have been handled a different way. This property could have been initialized in line 10, for example, but was not so this issue could be discussed.
- Accessing Objects in the Parent
In Lines 58 and 59, the particle must cast the type of its parent before it can access the parent’s methods or properties. Without this step, the compiler knows only that the parent’s a display object container, but not what kind. The compiler, therefore, doesn’t recognize the
txtFldproperty of the parent.When cast to a
MovieClip, however, the compiler knows thatMovieClipis a dynamic class and can, therefore, have custom properties. It then looks fortxtFldin the parent. and finds the text field you created.- Manipulating Text Fields
When adding text to the text field (line 58), the
appendText()method was used, as it’s much faster than the compound operator+=. Furthermore, the propertyscrollVmust be updated to the value ofmaxScrollV(line 59).- Particle Sound
Nothing about the
particleSound()method that is unique to ActionScript 3.0 hasn’t already been discussed. Line 64 checks to make sure the particle’sSoundinstance hasn’t already been created, and that_soundNumhas been incremented to be sure the sounds have preloaded. Line 65 creates a random number within the count of available sounds, line 66 creates an instance of theSoundclass and loads the sound, and lines 67 and 68 create aSoundChannelinstance and play the sound.- Particle Behavior
The behavior of the ActionScript 3.0 particles isn’t unique, but a few very important concepts should be discussed. To begin, the first number of the product used for the sound transformation
panvalue is calculated using the particle’sxdivided by theParticlesclass’x(line 81). This step’s in contrast to the ActionScript 2.0 calculation, which divides the first number by the class’s parent’sxvalue (line 73 of the ActionScript 2.0 class code). ActionScript 2.0 requires the Library movie clip to instantiate the class this way, so the movie clip must be referenced in the calculation. ActionScript 3.0 lets you add this class to the display list directly, so only the class needs to be referenced.Next, you must stop the sound, and remove the event listener, before removing the particle. Otherwise, the particle and its attendant objects, (such as listeners) won’t be collected by the garbage collector and purged from memory.
The compiler must be told that the object is a
MovieClipto prevent an error from occurring, because the compiler sees only the target of the method as anObjectthat may or may not be removable. However, this issue has already been addressed in the “Accessing Objects in the Parent (Type Casting)” section of this discussion.- Getter
Nothing unique about the
count()getter method is unique to ActionScript 3.0 hasn’t already been discussed
This is a small example of one possible migration path used to update a legacy project to ActionScript 3.0. Although awkward coding choices were made to show the largest number of migration issues practical in this size example, the exercise is still relatively close to a real-world scenario.
Having read this chapter, you may want to see if you can migrate this example on your own. Once you try the process a few times, you’ll have a pretty good idea of what you need, and you can evaluate the effectiveness of migration on a case-by-case basis. Depending on the extent of the changes, you may wish to use the old project as a kind of template, and then code the new version from scratch.
This excerpt is from The ActionScript 3.0 Quick Reference Guide. If you're ready to give your Flash projects a considerable performance boost, learning ActionScript 3.0 is a must. This Quick Answer Guide is designed specifically to help Flash designers and developers make the leap from ActionScript 2.0 to the new object-oriented ActionScript 3.0 quickly and painlessly. You'll learn key differences between the two language versions, allowing you to more easily leverage ActionScript 3.0 using Flash CS4 and other Adobe technologies like Flex and AIR.
