A Sample Migration: Chapter 18 - ActionScript 3.0 Quick Reference Guide

by David Stiller, Rich Shupe, Darren Richardson, Jen deHaan

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.

buy button

You’ll typically find it fairly straightforward to choose which version of ActionScript to use when you start a new project. You usually decide based on which version of the Flash Player you’re trying to target, the need for enhanced performance, or a specific feature you wish to use. Deciding what to do with existing projects, however, is another matter. Often you need to determine whether or not it’s worth the time and effort to migrate to ActionScript 3.0 from a prior version of the language, or just to start over.

You can’t easily determine what to do; each project’s characteristics probably significantly affect your decision. The clarity of your existing code, the extent to which you use particular features, project size, and your comfort level, among other factors, help you decide.

This chapter walks you through a small-scale, manufactured example of a migration from ActionScript 2.0 to ActionScript 3.0. Read the text linearly, as code isn’t always explained in detail twice. It is very important to understand that this example isn’t a demonstration of real-world best practices at work. This example is significantly constrained, and attempts to insert as many migration issues as possible into its tiny footprint. Throughout the example, what may appear to be odd choices, poorly optimized code, or even mistakes, have been intentionally injected into the code to either set up a migration task or bring the two versions into a parallel structure.

For example, objects are added out of order intentionally to demonstrate depth management, different methods of providing or checking default values have been used, objects are created in a variety of ways, both component and custom buttons are used, function/method placement isn’t consolidated, and so on. The project demonstrates both timeline- and class-based coding, but is by no means an example of good object oriented programming practices. The class and timeline are coupled too tightly, to mention one example.

If you remember that this scenario is artificial, designed to illustrate migration issues, it may help you form a plan or checklist of sorts to help when it comes time to update your next legacy project.

A Simple Particle System

This representative example creates a particle system that performs a few basic tasks. At startup, it plays an ambient audio loop. It then attempts to draw a blue square particle upon each enter frame event, based on a simple conditional. If successful, the particle moves away from the center of the stage, rotating and fading to transparency. Each time a particle is created, its name is added to a text field.

Finally, two buttons add functionality to the system. The first opens a web page. The second selects the previously created particle, replaces its content with a larger red square, and plays a new random sound. The altered particle affects its associated sound, panning based on the particle’s position, and fading based on the particle’s alpha.

Both examples require a custom button with a linkage of "BtnLink" and a Button component. The ActionScript 2.0 FLA file also requires an empty movie clip called "Particles." These assets are provided in the downloadable source files (see Preface).

ActionScript 2.0

To start, the complete ActionScript 2.0 code will be presented, with numbered lines. The project features a single class used by a brief frame script in the main timeline. This structure helps demonstrate migration issues related to the use of classes, as well as general syntax. Discussion of each script follows, with a general explanation following the ActionScript 2.0 code, and migration comments following the ActionScript 3.0 code.

Main Timeline

The main timeline builds the user interface, and creates an instance of the Particles class by adding a movie clip to which the class is linked. The class does all the work with the particles, and will be explained in a moment.

Production: The lines of code in this chapter contain turnover characters and soft returns to indicate that code lines are continued on the next line. The continued line should not have a line number. Robyn

1  import mx.controls.Button;
2
3  if (!imgURL) {
4      var imgURL:String = "bg.jpg";
5  }
6
7  var txtFrmt:TextFormat = new TextFormat();
8  txtFrmt.align = "right";
9  var txtFld:TextField = this.createTextField("particleInfo", 1, 380, 
     10, 100, 380);
10 txtFld.setNewTextFormat(txtFrmt);
11
12 bg = this.createEmptyMovieClip("bckgrnd", 2);
13 bg.loadMovie(imgURL);
14 bg.swapDepths(txtFld);
15
16 var snd:Sound = new Sound();
17 snd.loadSound("../audio/bass_back.mp3");
18 snd.onLoad = function(success:Boolean):Void  {
19     if (success) {
20         snd.setVolume(10);
21         snd.start(0, 100);
22     }
23 };
24
25 var particles:MovieClip = attachMovie("Particles", "particles", 3);
26
27 var controls:MovieClip = this.createEmptyMovieClip("btns", 4);
28 controls._y = 360;
29
30
31 var linkBtn:MovieClip = controls.attachMovie("BtnLink","link", 5);
32 linkBtn._x = 20;
33 linkBtn.siteLink = "http://www.learningactionscript3.com/";
34 linkBtn.onRelease = function():Void  {
35     getURL(this.siteLink, "_blank");
36 };
37
38 var changePBtn:Button = controls.createClassObject(mx.controls.Button, 
     "chng", 6, {label:"Change"});
39 changePBtn.move(changePBtn.x + 120, 0);
40 function changeParticle():Void {
41     var p:MovieClip = particles["particle" + (particles.count - 1)];
42     p.clear();
43     p.beginFill(0xFF0000);
44     makeRect(p, -20, -20, 40, 40);
45     p.endFill();
46     particles.particleSound(p);
47 }
48 changePBtn.addEventListener("click", changeParticle);
49
50 function makeRect(mc:MovieClip, xp:Number, yp:Number, w:Number, 
     h:Number):Void {
51     mc.moveTo(xp, yp);
52     mc.lineTo(xp + w, yp);
53     mc.lineTo(xp + w, yp + h);
54     mc.lineTo(xp, yp + h);
55     mc.lineTo(xp, yp);
56 }

The following includes discussions of ActionScript 2.0 syntax, but also a basic explanation of the project—much of which applies to both ActionScript 2.0 and 3.0 versions.

Import

Line 1 imports the Button component class to make it accessible to the compiler.

FlashVars

Lines 3 through 5 check for the presence of a variable called imgURL, and then initialize it to the URL of a background image in case no value for the variable is found. This step lets you pass a path to a background image into the project through the HTML host file. If this feature isn’t used, the hard-coded background image isn’t displayed.

TextFormat

Lines 7 and 8 create a simple TextFormat instance to right-justify text in a field.

TextField

Lines 9 and 10 dynamically initialize a TextField. Line 9 creates the field and gives it an instance name of particleInfo, places the field at a depth of level 1, places the field at point (380, 10), and sizes the field to a width of 100 pixels and height of 380 pixels. Line 10 applies the previously created TextFormat to the field.

Depth Management

ActionScript 2.0 requires that you set a level for every asset added to your project. Asset levels are hard-coded in lines 9, 12, 25, 27, 31, and 38. This step requires either careful preplanning or arbitrary level assignment (buttons between 100 and 200, movie clips between 300 and 400, and so on) and a good memory.

You can determine the next available level for symbol instances like movie clips, using the getNextHighestDepth() method. However, significant problems arise when adding components (which occurs later in the script) because the getNextHighestDepth() method can return errant levels beginning with 1048576. Not only does this wreak havoc with your level management, it’s outside the valid level range, making it impossible to remove assets dynamically.

To get around this problem, you can adopt the significantly more confusing approach of using the DepthManager class, created for managing depths of Version 2 Components, generally making things more difficult.

Line 14 swaps the depths of the text field and background image, making the background image the bottom-most asset. The text field and background were added in reverse order to demonstrate this feature.

Variable Declaration

ActionScript 2.0 allows sloppy variable use such as not declaring or typing the variable bg in line 12.

Image Loading

Lines 12 and 13 display a background image. Line 12 creates an empty movie clip, and sets its depth to level 2. Line 13 loads the image.

Sound

Lines 16 through 23 play a background sound. Line 16 creates an instance of the Sound class. Line 17 loads the sound.

Handling Events

Lines 18 through 23 create an event handler to process, in this case, a load complete event. Upon load completion, it sets the volume of the sound to 10 percent, so you can clearly hear other sounds atop this one, and plays the sound from the beginning, looping 100 times for longer play time. Another event handler appears in lines 34 through 36.

Void

Line 18 uses Void to tell the compiler that no data’s returned from the function. This action occurs again on lines 34 and 40.

Percent Values Scale

Line 20 manipulates a percent scale, and uses values between 0 and 100.

Dynamic Creation of Movie Clip and Instantiation of Custom Class

Line 25 creates an instance of a Library-based movie clip with a linkage name of Particles. It gives the clip an instance name of particles, and sets its depth to level 3. Note here that the Particles class responsible for particle control can only easily be integrated into the project by associating the class with a movie clip. This quality means that you have to have at least an empty movie clip in your Library, already set up with the appropriate class name.

Alternatives to this approach include manipulating the movie clip prototype, which is a bit messy and very difficult to bring forward into ActionScript 3.0, or switching to object-oriented techniques and using composition. Both approaches are significantly more involved than relying on a Library symbol.

Lines 27 and 31 also dynamically create movie clip instances. Line 27 creates an empty container (positioned in line 28) to hold buttons, and line 31 creates the first of two buttons, the functionally of which is discussed next. Both lines hard code depths, to 4 and 5, respectively.

Finally, line 38 also dynamically creates a movie clip equivalent, in this case a component. This step is relevant because, in the space of a dozen or so lines of code, you see three separate ways, each with unique characteristics, to place visible content on the stage.

Property Underscores

Line 28 demonstrates that the movie clip’s _y property, like most properties in ActionScript 2.0, is preceded by an underscore.

Custom Button Instantiation

Lines 31 through 36 add a Library-based custom button with a linkage name of BtnLink to the project. Line 31 places it into the controls movie clip, gives it an instance name of link, and sets its depth to level 5.

Line 32 positions the x location of the button. The y location remains 0, and appears to be 360 because the button is in the controls movie clip—which, itself, appears at a y location of 360.

Lines 34 through 36 add a mouse release event handler to the button.

Dynamic versus Sealed Classes

Line 33 dynamically creates a property called siteLink, and then populates it with a string. This step’s really nothing more than a variable, but here it’s an example of dynamic versus sealed classes. In ActionScript 2.0, you could add properties to instances of most classes, even though this practice wasn’t recommended. In ActionScript 3.0, however, most classes are sealed, meaning you can’t dynamically alter them in this way. You can use this approach only with select dynamic classes in ActionScript 3.0.

The siteLink property is being added to the button, which you can’t do in ActionScript 3.0. The the section called “ActionScript 3.0” discusses why this example was included, and also discusses another more directly analogous example.

Opening a URL

Line 35 opens a URL in a new window, getting the URL from the siteLink property of the button to which the event handler is attached.

Dynamically Instantiating a Component

Lines 38 through 48 add and empower a Button component. (As with a custom asset, a Button component must be in your Library.) Two different kinds of user-clickable objects demonstrate both the use of movie clips and the use of components.

Line 38 adds the button to the controls container movie clip, gives it an instance name of chng, sets it depth to level 6, and gives it a label of “Change.” Line 39 uses the button’s move() method to set it to an x position of 120, leaving the y position at 0, to be affected by the position of the parent container. The extraneous use of the x property (rather than setting the value to 120 directly) is to show that ActionScript 2.0 v2 components use properties without underscores, contrary to other properties.

Lines 40 through 48 apply an event listener to the button. Lines 40 through 47 define the function triggered by the button’s click event, set in line 48.

Lines 41 through 45 are discussed in the following paragraphs, and line 46 triggers the particleSound() method of the selected particle in the Particles class.

Accessing Objects by Instance Name

Line 41 creates a reference to the previously created particle by accessing the movie clips within the particles movie clip and finding the particle by instance name. The instance name is built with the string "particle" and the number of the current particle minus 1.

Using the Drawing API

Lines 42 through 45 clear the contents of the particle, create a red fill, call a function that draws a centered, 40 40 pixel rectangle in the selected particle, and close the fill.

Lines 50 through 56 use the lineTo() and moveTo() methods to draw a rectangle, as the drawRect() method doesn’t exist in ActionScript 2.0.

Particles Class

The Particles class creates each particle, establishes its behavior, and ultimately removes it from the project.

1 import mx.utils.Delegate;
2
3 class Particles extends MovieClip {
4
5         private var _count:Number;
6         private var _soundNum:Number = 0;
7         private var _tempSound:Sound;
8
9         public function Particles() {
10              _x = Stage.width / 2;
11              _y = Stage.height / 2;
12
13              _tempSound = new Sound();
14              _tempSound.loadSound("../audio/note0.mp3");
15              _tempSound.onLoad = Delegate.create(this, 
     onSoundPreloaded);
16          }
17
18          private function onSoundPreloaded(success:Boolean):Void {
19              if (success) {
20                  if (_soundNum < 7) {
21                      _soundNum++;
22                      _tempSound.loadSound("../audio/note" + _
     soundNum + ".mp3");
23                  }
24              }
25          }
26
27          private function onEnterFrame():Void {
28              makeParticle(0x0066CC, Math.random() * 10 + 10);
29          }
30
31          private function makeParticle(col:Number, 
     size:Number):Void {
32              if (!col){ col = 0x003366; }
33              if (!size){ size = 20; }
34
35              if (Math.random() * 10 <= 2) {
36                  if (_count == undefined) { _count = 0; }
37
38                  var p:MovieClip = this.createEmptyMovieClip("particle" + _
                     count, this.getNextHighestDepth());
39                  _count++;
40                  p.beginFill(col);
41                  _parent.makeRect(p, -size/2, -size/2, size, size);
42                  p.endFill();
43
44                  p.xVel = Math.random() * 10 - 5;
45                  p.yVel = Math.random() * 2 - 1;
46                  p.onEnterFrame = onRunParticle;
47
48                  _parent.txtFld.text += p._name + "\n"
49                  _parent.txtFld.scroll = _parent.txtFld.maxscroll;
50              }
51          }
52
53          public function particleSound(p:MovieClip):Void {
54              if (!p.snd && _soundNum > 0){
55                  var num:Number = int(Math.random() * _soundNum);
56                  p.snd = new Sound();
57                  p.snd.loadSound("../audio/note" + num + ".mp3");
58                  p.snd.onLoad = function(success:Boolean):Void {
59                      p.snd.start();
60                  }
61              }
62          }
63
64          private function onRunParticle():Void {
65              var p:MovieClip = this;
66              p._x += p.xVel;
67              p._y += p.yVel;
68              p._rotation += 5;
69              p._alpha -= 2;
70
71              if (p.snd) {
72                  p.snd.setVolume(p._alpha / 10);
73                  p.snd.setPan(p._x / this._parent._x * 200)
74              }
75
76              if (p._alpha <= 0) {
77                  p.removeMovieClip();
78              }
79          }
80
81          public function get count():Number {
82              return _count;
83          }
84  }

The following features a brief explanation of particle behavior. Where appropriate, comments have been added to address ActionScript 2.0-specific concepts and, occasionally, to explain decisions made to demonstrate migration issues. Basic syntax issues discussed in the main timeline aren’t mentioned again.

Import

Line 1 imports the Delegate class to make it accessible to the compiler.

Class Structure

Lines 3 and 9 make up the key elements of the ActionScript 2.0 class structure. You’ll see later that ActionScript 3.0 begins a class with the package identifier. Line 3 shows that this class extends MovieClip. (It’s linked to a Library movie clip.) The class constructor beginning on line 9 centers the particle system on the stage, and creates and preloads the first particle-specific sound.

Class Properties

Lines 5 through 7 create class properties but only initialize one. This step factors later into the use of default values.

Number Data Types

Lines 5 and 6 use the Number data type for integer counters because no other number data types are available. You can also see this property in lines 31 and 55. The value assigned in line 55, as a good example, is always an integer, but must still be typed as Number.

Access to the Stage

Lines 10 and 11 show that Stage is a global object.

Method Closure

Line 15 assigns the onLoad() event handler for the sound created and loaded in lines 13 and 14, respectively. Delegate is used here, however, to demonstrate that ActionScript 2.0 does not have method closures. Due to this setup, the Delegate class must pass the relevant scope to the event handler for it to access the needed properties.

Preloading Sounds

To prevent delays when triggering sounds later, lines 18 through 25 load seven additional sounds, but don’t play them. The name of the audio file contains indices 0 through 7. The first sound, note0.mp3, was loaded in the class constructor, so the soundNum property is incremented before the load.

Class Enter Frame Method

Lines 27 through 29 demonstrate that, because this class extends MovieClip, ActionScript 2.0 lets you create a method for a movie clip event handler, without any further assignment. That is, because the method has the same name as a MovieClip event handler, it’s executed upon every movie clip enter frame event. This method attempts to create a blue particle that’s between 10 and 20 pixels square.

Particle Creation

Lines 31 through 51 create each particle. Individual aspects of this function will be discussed in separate headers, but the basic creation process is as follows. Line 35 checks to see if a newly created random number between 0 and 10 is less than or equal to 2. If so, it creates the particle. This action both prevents a particle from being created on every enter frame, and adds a nice feeling of randomness to the process.

Each particle is drawn into an empty movie clip, with its depth set to the next highest available level. It’s given an instance name of particleN, where N is an integer from the _count variable, incremented each time a particle’s created. A fill of the color passed into the method is created, a rectangle is drawn using the makeRect() function discussed in the main timeline (using the size passed into the function), and the fill’s closed.

Next, random x and y velocities are chosen for each particle, providing movement between 5 and −5 for x and between 1 and −1 for y. The onRunParticle() method is then assigned as the enter frame event handler for each particle. (This step’s in contrast to the enter frame event handler assigned at the class level that creates the particles.)

Finally, the name of the particle, and a subsequent new line, are added to the text field in the main timeline (the particle’s parent). This step is discussed in detail in the upcoming note, “Manipulating Text Fields.”

Default Values

Lines 32 and 33 validate the argument values of col and size, assigning values if none are found. ActionScript 2.0 has no built-in mechanism for assigning default values in functions. As such, you must assign them manually.

Further, line 36 checks for a value of undefined in _count and, if found, initializes the property to 0. This demonstrates a change in the way ActionScript 3.0 handles default values, and this is also why _count wasn’t initialized in line 5.

Accessing Objects in the Parent

Lines 41, 48, and 49 all access objects in the parent, in this case the main timeline.

Manipulating Text Fields

The name of the particle, and a subsequent new line, are added to the text field in the main timeline (the particle’s parent). The text field is then scrolled to the bottom line so you can always see the newly added name.

Particle Sound

Lines 53 through 62 create and play particle-specific sound. A validation first tests to be sure a sound for this particle doesn’t already exist, and that at least one sound has preloaded (via the incremented counter in line 21). If so, a random number is chosen from the current number of preloaded sounds (line 57) and a new sound is created and stored in the snd property within the current particle. The random sound is then loaded and played upon load completion.

(Many people consider it a best practice to group private and public methods (and properties). However, this method’s optional, and has been neglected in order to arrange this example in a slightly more linear fashion for easier explanation.

Particle Behavior

Lines 64 through 79 establish the independent behavior for each particle. For each enter frame event, lines 66 and 67 add the x and y velocity values to the particle’s location, line 68 rotates the particle 5 degrees, and line 69 reduces the alpha by 2 percent.

Lines 71 through 74 controls particle-specific audio. The volume and pan of the sound are set according to the particle’s alpha and x coordinate, respectively.

Finally, lines 76 through 78 remove the particle when its alpha is less than or equal to 0.

Getter

The last three lines of the class create a getter that returns the value of the _count property when requested, as seen in line 41 of the main timeline frame script.

Pages: 1, 2

Next Pagearrow