By David Stiller
David Stiller
2 February 2009


Prerequisite knowledge

A cursory understanding of ActionScript.

User level


Required products

Sample files

Note: Debugging ActionScript 3.0 code takes advantage of a new workspace in Adobe Flash CS4 Professional that is unavailable for ActionScript 2.0 documents. This article is specifically aimed at Flash CS4 development in ActionScript 2.0.
Programming can be a bit like navigating blindfolded in a petting zoo. Sure, you may know the general layout (which pens are where, which animals are in each pen) but the fact remains that waddling, hopping, frolicking creatures are about—and they like to wander!
During playback of a SWF file, variables and properties may change over time or in response to user input. Often enough, such changes occur in unexpected ways. A dynamic text field may inexplicably display the wrong information or nothing at all. The cause of this trouble is hidden, of course, because the SWF file is already compiled—so who knows where those variables have waddled, hopped, or frolicked?
Fortunately, Adobe Flash provides a number of tools to unearth important information normally under wraps. This article discusses ways to bring this information to light when your FLA file is configured for ActionScript 2.0.

Meet the Output panel

Your first stop is the Output panel, which displays text that is output either by the Flash authoring tool or by you. To view the Output panel, open an existing Flash File (ActionScript 2.0) document or create a new one, and then select Window > Output or press the F2 key. (Doing so again will close this panel.)
In the default Essentials workspace, this panel is grouped with the Timeline and Motion Editor panels at the bottom of the authoring tool, but you may move it wherever you like by dragging its tab elsewhere in the workspace. This panel begins empty; however, you may choose to fill it with informative messages at any point during the playback of your SWF file. In certain cases, such as ActionScript syntax errors, Flash will send messages to the Output panel on its own.
The Output panel is configurable through the Options menu in its upper right corner (see Figure 1). These options enable you to apply word wrap, copy, and clear the panel's contents, find keywords or phrases, save to a text file, print, and more.
Options menu in the Output panel
Figure 1. Options menu in the Output panel
Note: The Filter Level option enables you to suppress output by selecting the None setting; the Verbose setting permits output and is the default. If you fail to see expected text in the Output panel, double-check your Filter Level setting. If you still don't see output, select File > Publish Settings, click the Flash tab, and verify that the Omit trace actions check box (in the Advanced area) is cleared.
There are basically two scenarios in which the Output panel displays text: Either Flash is warning you about an error in your ActionScript, or you have chosen to send yourself a message in order to see the inner workings of a SWF file.
Messages sent by you are only output from a SWF file, so in order to put the Output panel to work, you'll have to generate one. One of the ways to do this is by selecting Control > Test Movie or by pressing Control+Enter (Windows) or Command+Return (Macintosh). You'll learn how to output our own messages in a moment; first, let Flash have a go.
Messages sent by Flash may be output both from SWF files and FLA files. To see such a message, open a new Flash document and select Window > Actions or press F9 (Windows) or Option+F9 (Macintosh) to open the Actions panel.
Type the following purposefully incorrect ActionScript code into the Actions panel:
var example:Number = "this string should be a number";
Now click the Check Syntax button at the top of the Actions panel (see Figure 2). The Output panel will open automatically if it is not already open.
Check Syntax button in the Actions panel
Figure 2. Check Syntax button in the Actions panel
Flash sends an error message to the Output panel because of an erroneous attempt to set the value of a number variable to a string. This sort of information is terrific for correcting invalid ActionScript code before a file is published. If invalid ActionScript code makes it to the SWF file after all, similar error messages may appear during SWF file playback as errors are encountered.
Now, how can you send your own messages? And why would you want to? Well, that depends on your needs, of course. Perhaps your goal is to loop a Flash banner three times and then stop. You've created a variable to keep track of these loops, but for some reason the SWF file plays through only once. What could be wrong? Get ready to embark on your troubleshooting jaunt—with the global trace() function.
trace() function
The ActionScript trace() function is your direct conduit to the Output panel. This function is a no-frills, easy-to-use, and very helpful tool. It accepts only one parameter, which is basically whatever information you'd like to see.
Open loop_3_times.fla from the ZIP file that accompanies this article to look at an example of the above scenario. In this example, the SWF file is supposed to loop three times, but doesn't loop at all.
Before you proceed, however, a historical note is in order. The ActionScript language has matured considerably in recent versions of Flash. The code presented in loop_3_times.fla is a legacy solution that works only in SWF files published for Adobe Flash Player 4, 5, or 6. (These version choices are available under File > Publish Settings, Flash tab.) If you want to take advantage of newer Flash Player features, you will obviously have to publish your SWF file for something later than Flash Player 6. In so doing, you may find that older, seemingly correct code samples no longer behave. It's good to be aware of this because it is simply a fact of life that plenty of third-party online Flash tutorials are outdated. Now, don't get me wrong, they're often still useful—but you'll have an easier time bringing them up to speed when you understand the built-in debugging tools at your disposal. In this case, the FLA file is configured for Flash Player 8 because your theoretical project requires features introduced in that version of Flash Player.
Take a look at how the trace() function can show you what's wrong with loop_3_times.fla. Open the Actions panel and use the Timeline to select frame 25 of the Scripts layer:
loopCount++; if (loopCount >= 3) { stop(); }
A variable, loopCount, is incremented using the increment operator (++). If the loopCount value is greater than or equal to 3, the Timeline is stopped; otherwise, the Timeline naturally loops again from the beginning. Short and sweet. So why doesn't this work in Flash Player 8?
Clearly, the success of this particular script hinges on the value of the loopCount variable. Presumably its value begins as 0. It increments to 1. Because 1 is not equal to or greater than 3, the SWF file repeats. Next time, the loopCount value increments to 2, and so on.
As it turns out, the value of loopCount does not begin at 0. The problem lies in the fact that the variable is never formally declared and initialized. You're missing a line early on that reads var loopCount:Number = 0; to state specifically what your default value should be. In ActionScript 1.0 and 2.0, Flash automatically declares a variable for you if you do not. In Macromedia Flash MX and earlier, such automatically declared variables could be incremented. In Flash MX 2004 and later, in ActionScript 1.0 and 2.0, they cannot. For this reason, the value of loopCount immediately following the increment operator is a special number value called NaN (Not a Number), which happens to evaluate as equal to or greater than any other number in ActionScript.
Tracing variables
You can bring such knowledge to light with the trace() function. Add the following highlighted code to the existing ActionScript code:
loopCount++; trace(loopCount); if (loopCount >= 3) { stop(); }
Test the SWF file to see that it still only plays through once—but the message NaN appears in the Output panel. This sort of discovery is often the first step toward a solution. Because the loopCount value is not an incremental number, you ought to declare the variable formally and initialize it to 0. You will do this only if the variable does not already exist (again, new code is highlighted):
if (loopCount == undefined) { var loopCount:Number = 0; } loopCount++; trace(loopCount); if (loopCount >= 3) { stop(); }
Tip: If you make several trace() statements in a row, you may find that you quickly lose track of what your output refers to. To remedy this, use the addition operator (+) to concatenate a string with your messages. In the code sample above, for example, you might amend the trace() statement as follows:
if (loopCount == undefined) { var loopCount:Number = 0; } loopCount++; trace("The value of loopCount is currently: " + loopCount); if (loopCount >= 3) { stop(); }
Thanks to this concatenation, the Output panel shows a more descriptive message than provided by a number on its own.
Tracing confirmations
The trace() function is useful with more than just variables. Any object that can be referenced by ActionScript can be traced. This includes movie clips, dynamic text fields, buttons, and even nonvisual objects like strings, arrays, dates, sounds, and more. If an object doesn't implicitly contain textual content, trace() outputs a text description of it.
Often it's helpful simply to trace a literal string in order to confirm that an object is behaving as expected. This bit of troubleshooting has come to the rescue in countless posts on the Flash support forums. Typically, a developer has coded a button to invoke the global getURL() function so that the button will open a new web page when clicked. For some reason, the button doesn't work. Could this be due to incorrect use of getURL()? Possibly. But just as likely, the developer has merely mistyped the button's instance name. Adding trace() to one of the button's event handlers allows this possibility to be confirmed or denied.
Open button_events.fla and click frame 1 of the Scripts layer to see an example. Only one of these functions actually does something (line 8 in the script below); the rest are just traces. If this function fails for some reason, you'll know that the problem lies with this function alone. You know it because the button's events are clearly being handled otherwise, thanks to your troubleshooting messages:
myButton.onRollOver = function() { trace(this + " has been rolled over"); }; myButton.onPress = function() { trace(this + " has been pressed"); }; myButton.onRelease = function() { myMovieClip._visible = !myMovieClip._visible; trace(this + " has been released"); }; myButton.onRollOut = function() { trace(this + " has been rolled out"); };
Test this SWF file and keep an eye on the Output panel as you move your mouse to the circular button, press and release, then move it away.
Tracing object properties
Even the most seemingly clear ActionScript can sometimes pull a few surprises. Consider the following example, in which a button manipulates the opacity of a movie clip. Open movieclip_alpha.fla and click frame 1 of the Scripts layer to follow along:
var changeAmount:Number = −10; myButton.onRelease = function() { myMovieClip._alpha += changeAmount; if (myMovieClip._alpha == 50 || myMovieClip._alpha == 100) { changeAmount *= −1; } };
Two symbols exist in this FLA file: a button with the instance name myButton and a movie clip with the instance name myMovieClip. A variable, changeAmount, is declared and its value is initialized to –10. The button uses this variable to update the MovieClip._alpha property of myMovieClip, whose original _alpha value is 100. Because the current value of changeAmount is –10, one would expect the opacity of myMovieClip to be reduced to 90 when the button is clicked, then 80, and so on. When the opacity reaches either 50 or 100, a multiplication converts the value of changeAmount to a negative number if it is positive, and vice versa. Repeated clicking alternately fades myMovieClip out and in, again and again. The only problem is that this is not what actually occurs. Test it and see! For some reason, repeated clicking of the button fades out myMovieClip altogether. So what's going on?
Let's lift the blindfold. Add the following highlighted code to the existing ActionScript:
var changeAmount:Number = −10; myButton.onRelease = function() { myMovieClip._alpha += changeAmount; trace("the value of myMovieClip._alpha is: " + myMovieClip._alpha); if (myMovieClip._alpha == 50 || myMovieClip._alpha == 100) { changeAmount *= -1; } };
Test the SWF file again and keep an eye on the Output panel while you repeatedly click the button. Surprisingly enough, the value of myMovieClip._alpha does not actually change by increments of 10. This means it never hits exactly 50 and is consequently never converted to a positive number.
The answer to this perplexity is that the MovieClip._alpha property actually refers to 256 levels of transparency, but can be adjusted only in terms of percentage. Without the trace() function, you might have been stumped by this, but one solution already presents itself. Because the anticipated 50-mark is actually closer to 49.21875, you can change the pair of equality operators (==) to "less than or equal to" (<=) and "greater than or equal to" (>=), respectively. In this way, you can account for the decimal places—again, thanks to trace():
var changeAmount:Number = -10; myButton.onRelease = function() { myMovieClip._alpha += changeAmount; trace("the value of myMovieClip._alpha is: " + myMovieClip._alpha); if (myMovieClip._alpha <= 50 || myMovieClip._alpha >= 100) { changeAmount *= -1; } };
Tracing object properties recursively
While objects can be a convenient way to organize data—consider the Array and XML classes—they can also become overwhelmingly complex. In fact, with XML especially, you may not even be aware at first what an object's properties are. This makes the prospect of tracing any particular property a daunting one.
In cases like this, a combination of the trace() function, the statement, and recursion becomes a powerful tool. A recursive function is one that invokes itself until certain conditions are met, at which point it stops. Unless you're familiar with this concept, it may seem a little strange but it's a great way to step through nested hierarchies to find every last branch.
After making sure that trace_xml.fla and xml_demo.xml are in the same folder, open trace_xml.fla and test the SWF file to see a recursive trace of all the nodes of the dynamically loaded XML file. The custom traceXML() function is what pulls this off. A step-by-step discussion of how it works is beyond the scope of this article, but you're welcome to paste this function into your own projects in order to view the contents of unfamiliar XML objects.
When the function is defined, simply invoke it and pass in an XML object's XML.firstChild property as the parameter:
function traceXML(node:XMLNode, tab:String):Void { if (tab == null) tab = ""; if (node.nodeName != null) { var prop:String; var str:String = "<" + node.nodeName; var child:XMLNode = node.firstChild; for (prop in node.attributes) { str += " " + prop + "="" + node.attributes[prop] + """; } if (child) { trace(tab + str + ">"); while (child) { traceXML(child, tab + " "); child = child.nextSibling; } trace(tab + "</" + node.nodeName + ">"); } else { trace(tab + str + " />"); } } else { trace(tab + node.nodeValue); } } traceXML(yourXml.firstChild);
Special thanks to Branden Hall, who gave me kind permission to put an ActionScript 2.0 gloss on his original printXML() function.
Open trace_movieclip.fla to see a similar approach to tracing movie clip hierarchies:
function traceMovieClip(target:MovieClip):Void { var clip:String; for (clip in target) { if (target[clip] instanceof MovieClip) { trace(target[clip]); traceMovieClip(target[clip]); } } } traceMovieClip(yourMovieClipInstance);
Test the SWF file to see a recursive trace of all the movie clips nested inside the main Timeline. Some have been placed on the Stage by hand; others are created through ActionScript. The traceMovieClip() function accepts any movie clip reference as a parameter. In the sample file, the parameter's value is the global this property, which in this context refers to the main Timeline. Change this to mc1parent (one of the dynamically created movie clips) to see how the output changes.
Open trace_object.fla to see the same concept used to trace hierarchical properties of a generic Object instance—even when those properties include an array that contains another object!
Tracing "nothing at all"
Sometimes the trace() function outputs undefined, which means you've hit a variable that has not yet had a value assigned to it. Learning this can be very useful, especially if you expect the variable to have a value. Often it may lead you straight to the solution ("Hey, I forgot to initialize my variable here..."). The trace() function may also output null, which means you've hit a variable that earlier contained a value but currently does not—potentially just as useful to know.
Note: Both ActionScript 1.0 and 2.0 create a variable on the spot if a referenced one doesn't exist, so make sure to watch for spelling mistakes. You might be checking on a variable named cost but tracing the typo cosst. If so, a cosst variable will be created whose value is undefined.
typeof operator
You may want to know more about a given object than its current value. The typeof operator returns an object's data type in lowercase. Use this operator in conjunction with the trace() function to find out, for example, if the property you thought was a number is actually a string, or some other inappropriate data type.
Open typeof_sum.fla and click frame 1 of the Scripts layer to follow along. The ActionScript seems straightforward enough. Two input text fields enable the user to supply a couple of numbers. Clicking the button adds the values of these numbers and places their sum into a third dynamic text field:
myButton.onRelease = function() { tfSum.text = tfNumber1.text + tfNumber2.text; };
The problem is that these numbers don't add up correctly. The default 2 plus 2, for example, shows up as 22. Why? As it turns out, the TextField.text property always returns a string and the addition operator (+) concatenates strings. What the user thinks are numbers aren't numbers at all: the words 2 and 2 combine to make the word 22, just like cat and astrophe combine to make the word catastrophe. A traced typeof operation makes this clear. Change the preceding ActionScript code to read as follows (new code highlighted):
myButton.onRelease = function() { trace("the value " + tfNumber1.text + " is a " + typeof(tfNumber1.text)); trace("the value " + tfNumber2.text + " is a " + typeof(tfNumber2.text)); tfSum.text = tfNumber1.text + tfNumber2.text; };
When the button is clicked, the Output panel shows that the global parseInt() function is a good idea here because parseInt() converts strings into numbers:
myButton.onRelease = function() { tfSum.text = parseInt(tfNumber1.text) + parseInt(tfNumber2.text); };
Be aware that the typeof operator has its limitations. There are two kinds of data types in ActionScript: primitive and composite. The typeof operator is really only useful with primitives, which are among the elemental units of a language. In ActionScript, these include string, number, Boolean, null, and undefined. Composite data types represent a unique combination of these. The typeof operator simply returns object when tested against a composite.
While this assessment is certainly true, it is not especially specific. Open typeof_primitive_composite.fla to test the following ActionScript 2.0 code in a SWF file:
// Primitives // Boolean var myBoolean:Boolean = true; trace("typeof Boolean: " + typeof(myBoolean)); // output: typeof Boolean: boolean // Number var myNumber:Number = 5; trace("typeof Number: " + typeof(myNumber)); // output: typeof Number: number // String var myString:String = "sample"; trace("typeof String: " + typeof(myString)); // output: typeof String: string // Composites // Array var myArray:Array = new Array(); trace("typeof Array: " + typeof(myArray)); // output: typeof Array: object // Date var myDate:Date = new Date(); trace("typeof Date: " + typeof(myDate)); // output: typeof Date: object // Sound var mySound:Sound = new Sound(); trace("typeof Sound: " + typeof(mySound)); // output: typeof Sound: object
Note: Variables that represent primitives may either be declared directly or as the result of a constructor. It is worth noting that typeof does not return the specific primitive for variables whose values are set by a constructor; instead, it returns object:
// String (constructor) var myString:String = new String("sample"); trace("typeof String (constructor): " + typeof(myString)); // output: typeof String: object
instanceof operator
The instanceof operator makes up for the shortcoming of typeof because it tests whether an object is an instance of a given constructor. In terms of debugging, this means you may use instanceof as a finer-toothed comb than typeof. Notice the different manner in which this operator is employed. The tested expression must be arranged in the format objectToCheck instanceof ClassName, which returns either true or false. Open instanceof.fla to test the following ActionScript code in a SWF file:
// Array var myArray:Array = new Array(); trace("instanceof Array: " + (myArray instanceof Array)); // output: instanceof Array: true // Date var myDate:Date = new Date(); trace("instanceof Date: " + (myDate instanceof Date)); // output: instanceof Date: true // Sound var mySound:Sound = new Sound(); trace("instanceof Sound: " + (mySound instanceof Sound)); // output: instanceof Sound: true
Note: Tested against a primitive, instanceof returns true only when a variable's value is compared to the right class and set by a constructor:
var myString:String = "This goat is nibbling my hat."; trace("instanceof String: " + (myString instanceof String)); // output: instanceof String: false var myString:String = new String("After all, it is a straw hat."); trace("instanceof String (constructor): " + (myString instanceof String)); // output: instanceof String (constructor): true
Of course, everything comes at a price. The disadvantage of instanceof is that it forces you to decide on your own what data type an object might be and then check whether you're right, while typeof simply tells you the answer, albeit in less detail.
Object and variable dumps
Sooner or later, you may be faced with a misbehaving FLA file built by someone else. Until you take the time to locate every last shred of ActionScript, you may not even know where to begin inserting any troubleshooting trace() functions. In a situation like this, you may simply want a dump of all the current values of a SWF file's objects and variables. Consider this an ad hoc "table of contents" for a given snapshot of a SWF file.
Open dump.fla for a file that's prepopulated with a few objects. Test this SWF file and select Debug > List Objects or Debug > List Variables from the File menu of the SWF file itself (not the File menu in the Flash authoring program). Regardless of the occurrence (or absence) of trace() in your code, these commands send a list of the chosen data to the Output panel. Notice that List Objects displays the movie clips, text field, and button but omits the variables declared in frame 1 of the main Timeline. List Variables shows all of these, including detailed property information on the text field and button.
Depending on the complexity of your document, either one of these dumps might be huge, so you may want to send contents to the printer or save to a text file for easier inspection.
Note: Using List Objects or List Variables clears the Output panel of any existing trace() output.

Meet the ActionScript 2.0 Debugger panel

Ready to step up? The ActionScript 2.0 Debugger panel provides a much more comprehensive, interactive view than trace() of the inner workings of a SWF file. It enables you to see movie clips and nested movie clip hierarchies, text fields, object properties, variables, and more. It also enables you to pause individual lines of ActionScript code and step through them at your pace.
Rather than merely reacting to output in the Output panel, you can watch as an if statement evaluates its condition. You can witness the values of variables and properties change over time. In some cases, you can even alter their values yourself. In loop_3_times.fla, for example, you could have recognized the NaN error, made a note of it, and then manually changed NaN to 0 in order to verify the rest of the code.
To open the ActionScript 2.0 Debugger panel, select Window > Debugger Panels > ActionScript 2.0 Debugger or press Shift+F4 (Windows) or Option+F4 (Macintosh). Although you may open this panel at any time, it won't actually do anything until you debug your SWF file by selecting Debug > Debug Movie or by pressing Control+Shift+Enter (Windows) or Command+Shift+Return (Macintosh).
Like the Output panel, the ActionScript 2.0 Debugger panel is configurable through the Options menu, which you can access through the Options button in the upper right corner (see Figure 3). Options include zooming, quality settings, printing, and more.
Options menu in the ActionScript 2.0 Debugger panel
Figure 3. Options menu in the ActionScript 2.0 Debugger panel
To see the debugger in action, follow these steps:
  1. Open debugger_1.fla and select Debug > Debug Movie. The first thing you'll notice is that the SWF file begins in a paused state, waiting for you to click the green Continue button at the top of the ActionScript 2.0 Debugger panel (see Figure 4). The reason Flash waits is so that you may optionally set breakpoints in your ActionScript code. Don't click Continue yet!
Continue button in the ActionScript 2.0 Debugger panel
Figure 4. Continue button in the ActionScript 2.0 Debugger panel
Breakpoints are stop signs that cause the debugger to halt during playback while you examine various aspects of the SWF file. In the ActionScript 2.0 Debugger panel, they appear as red bullets next to individual lines of code (look ahead to Figure 6). Flash conveniently remembers breakpoints even after you close the FLA file. As of Flash 8—and continued in Flash CS3 and Flash CS4—breakpoints are also remembered for external ActionScript files, thanks to an automatically generated XML file, AsBreakpoints.xml.
  1. A SWF file's ActionScript code may exist in a variety of places, including Timeline frames, direct attachment to buttons or movie clips, and even external files brought in through the #include directive or import statement. In order to select which frame, object, or external file to inspect, click the pop-up menu below the Continue button (see Figure 5). You'll notice that ActionScript code exists in two places in this file: attached to a button and in frame 1 of the Scripts layer.
Script selection pop-up menu in the ActionScript 2.0 Debugger panel
Figure 5. Script selection pop-up menu in the ActionScript 2.0 Debugger panel
  1. Choose the code in frame 1 and set a breakpoint on line 34. To do so, you may either click in the gutter near line 34 or position your cursor in that line and click the Toggle Breakpoint button (see Figure 6).
Setting a breakpoint in the ActionScript 2.0 Debugger panel
Figure 6. Setting a breakpoint in the ActionScript 2.0 Debugger panel
Note: You may also set breakpoints in a FLA file by clicking in the gutter of the Actions panel. In fact, as of Flash 8 you can even set breakpoints in external AS files by clicking in the gutter of the Script window. Breakpoints make sense only when they appear next to executable lines of ActionScript. If a breakpoint is set on a commented or empty line, it will be ignored.
  1. After you set your breakpoint, click the Continue button. The SWF file will proceed as usual and stop cold at line 34, enabling you to investigate the current value of any variables and properties in the file at that moment.
  2. Look to the left side of the ActionScript 2.0 Debugger panel. At this point, ActionScript has already created a new movie clip with the instance name mcSquare (see Figure 7). Because this movie clip doesn't yet contain artwork, it cannot be seen on the Stage, but it does exist and appears as an item in this tree view. Both movie clips and text fields can appear in this area. Text fields appear only if they're set as dynamic or input because they must have an instance name to belong to this list. Nested movie clips appear in hierarchical fashion.
Movie clip in the ActionScript 2.0 Debugger panel
Figure 7. Movie clip in the ActionScript 2.0 Debugger panel
Properties and variables
Click the _level0.mcSquare branch of this tree view to focus on the mcSquare movie clip. Notice the Properties tab (see Figure 8); this location displays movie clip properties of the currently selected object.
Movie clip properties in the ActionScript 2.0 Debugger panel
Figure 8. Movie clip properties in the ActionScript 2.0 Debugger panel
Note: Only movie clip properties are displayed in this area, even if the selected object is a text field. In the case of text fields, the displayed properties are those that text fields happen to share with movie clips.
If the selected movie clip has any variables declared in its Timeline, these will appear under the Variables tab. As it turns out, there are indeed a few declared in debugger_1.fla, so click the Variables tab to see them.
Select the _level0 branch to see properties or variables located in the main Timeline. The _global branch represents the special _global object in ActionScript 2.0, which can be used to store global variables available to any Timeline. Select this branch and look at the Variables tab to see variables located in this object.
Script navigation
It's time to put some artwork into this visually empty movie clip. Three buttons at the top of the ActionScript 2.0 Debugger panel enable you to pilot your breakpoints: Step Over, Step In, and Step Out (see Figure 9).
Script navigation buttons in the ActionScript 2.0 Debugger panel
Figure 9. Script navigation buttons in the ActionScript 2.0 Debugger panel
The breakpoint on line 34 happens to sit next to a function. In order to step into this function, follow these steps:
  1. Click the Step In button. This causes the ActionScript 2.0 Debugger panel to stop at each line of ActionScript code inside the function. The line under current review is indicated by a small yellow arrow (see Figure 10).
Stepping through ActionScript code in the ActionScript 2.0 Debugger panel
Figure 10. Stepping through ActionScript code in the ActionScript 2.0 Debugger panel
  1. Click the Step In button repeatedly to advance from line to line, keeping an eye on the Stage as you do so. You will see a square being drawn, getting resized, and then being centered horizontally and vertically.
    The useful part about watching these steps in slow motion is that if something goes wrong, you'll know exactly which line caused the error.
  2. Close the SWF file for debugger_1.fla and select Debug > Debug Movie to start again. This time, after clicking the Step In button a few times, click the Step Out button to leave the function. In a real-world debugging session, you'll appreciate this ability to cancel a potentially tedious Step In procedure in the event you change your mind. Stepping Out takes you to the next breakpoint, if there is one.
  3. Close the SWF file again and select Debug > Debug Movie one more time. When the SWF file stops at line 34, click the Step Over button to bypass the breakpoint altogether. This also takes you to the next breakpoint, if there is one.

Additional information

The ActionScript 2.0 Debugger panel provides a few additional tools whose usage may not be immediately apparent.
Locals tab
Variables in ActionScript are affected by scope, a kind of point of view that determines the availability of a variable to other parts of the code. If a variable is declared in the Timeline of a movie clip, that variable is available to any code in the rest of that movie clip's Timeline. The variable is also available to other timelines, provided that they specify the instance name of the movie clip as a path to the variable.
Not all variables are so accessible. When a variable is declared inside a function, it is available only to other code inside the same function. Such a variable is said to be local to that function and is visible in the ActionScript 2.0 Debugger panel only in the Locals tab.
To see what I'm talking about, follow these steps:
  1. Open debugger_2.fla and select Debug > Debug Movie.
  2. Use the pop-up menu to select the script in frame 1, set a breakpoint at line 12, and then click the Continue button to begin.
  3. Select the _level0 branch on the left side of the ActionScript 2.0 Debugger panel and click the Variables tab to note the existence of the loopThisManyTimes variable.
  4. Click the Step In button to enter the demoLocalVariable() function.
  5. Click the Step In button again to execute line 8. At this point, the local variable i has been declared.
  6. Click the Locals tab to see it and continue clicking the Step In button to watch the value of i update (see Figure 11).
Locals tab in the ActionScript 2.0 Debugger panel
Figure 11. Locals tab in the ActionScript 2.0 Debugger panel
Watch tab
In an especially complex SWF file, the number of variables may be so high that the tab listings under Variables and Locals become unwieldy. In order to make your view less cluttered, you may want to handpick a collection of only those variables that interest you. You can add and remove these variables to the Watch tab for this very purpose. Right-click (Windows) or Control-click (Macintosh) a given variable to send it to the Watch tab. Repeat this process from the Watch tab to remove a variable from this listing.
Call stack
The bottommost pane of the ActionScript 2.0 Debugger panel, Call Stack, shows each function currently in execution. As a function begins, its name is added to the stack in this area and is removed again when the function concludes. In lengthy or complex SWF files, the Call Stack is a useful reminder of which function you've stepped into. It's also good for keeping an eye on recursive functions, which can get out of control when written incorrectly.
Follow these steps:
  1. Open trace_xml.fla and select Debug > Debug Movie.
  2. Use the pop-up menu to select the script in frame 1.
  3. Set a breakpoint at line 19 and click Continue to begin.
  4. Use the Step In button to enter the recursive function and watch while the Call Stack grows as the function is repeatedly invoked. If the stack grows to 256 items (this one doesn't), the SWF file will output an error to the Output panel.

Debugging SWF files in a browser

Debugging a SWF file from the comfort of Flash is one thing; debugging from the confines of a browser is another thing altogether! Fortunately, Flash offers a feature called remote debugging that makes browser-embedded SWF files available to the ActionScript 2.0 Debugger panel.
Remote debugging
To debug a SWF file remotely, you must first take care of a minor prerequisite:
  1. Open remote_debugging.fla.
  2. Select File > Publish Settings, click the Flash tab, and place a check mark in the Debugging Permitted check box. You may provide an optional password here. If you do, you will be prompted for this password when the remote debugging session begins.
  3. Generate a debug version of your SWF file by performing a nominal debug. In other words, select Debug > Debug Movie and then close the SWF file. The debug version of a SWF file will weigh slightly more than a normal version of the same SWF file because the debug version contains additional information used by the debugger.
  4. Upload the debug version of your SWF to your server.
You must have Flash running in order to debug a browser-embedded SWF file, but it is not necessary to have the corresponding FLA file open:
  1. Select Debug > Begin Remote Debug Session > ActionScript 2.0 (see Figure 12). The Output panel will indicate that it's waiting to make a connection. Direct your browser to the web page that contains the SWF file you want to debug.
    In your browser, you'll see a dialog box that asks you to identify yourself as localhost or another IP address. In most cases, localhost will do just fine (you would know if you needed to specify a particular IP address because you would have written your ActionScript code to expect one).
  2. Respond to this dialog box with localhost and then bring Flash to the forefront. You'll see another dialog box in Flash—this time a password prompt. If you supplied a password earlier, enter it now and then click OK. If not, leave the password field blank and simply click OK.
  3. In the ActionScript 2.0 Debugger panel, select the script in frame 1, set a break point at line 3, and then press the Continue button to begin. You may now alternate between your browser and Flash to provide user interaction and debug as usual.
  4. If you're using the remote_debugging.fla file, click the Click Me button in the SWF file to watch your ActionScript 2.0 Debugger panel react.
Launching an ActionScript 2.0 remote debugging session
Figure 12. Launching an ActionScript 2.0 remote debugging session
Homemade Output panel
Unless you use remote debugging, trace() output simply isn't visible from a browser-embedded SWF file. It is possible, however, to build a lightweight, makeshift Output panel out of a dynamic text field. To see one approach, open the homemade_output_panel.fla sample file that is part of the sample ZIP file that accompanies this article.
This FLA file contains one layer devoted just to the necessary dynamic text field. It's positioned above all other visual content so that its output is always in sight. The dynamic text field is set to Multiline in the Property inspector and has Selectable and Show Border Around Text turned on. Finally, the text field is given the instance name tfOutput.
A function in frame 1 of the Scripts layer sets the TextField.text property of tfOutput to the incoming message. It also keeps the latest message on top by following the incoming message with a line break and then concatenating that with the previous content:
function traceOutput(msg:String):Void { tfOutput.text = msg + newline + tfOutput.text; }
In this particular FLA file, you may now replace trace() with traceOutput() and use this new function in basically the same way. Sure, the homemade version isn't as powerful but it works in a pinch when remote debugging is not an option.

Where to go from here

Programming and debugging are constant companions. If you're anything like me, you'll avoid a ton of frustration with these debugging tools and perhaps wonder how you managed without them.
Best of luck as you experiment! Here's to greater knowledge of your SWF files and better-informed decision making as a result.
Now that you're primed to debug, read Jen deHaan's article, ActionScript 2.0 best practices, which provides valuable advice on how to minimize the need to debug in the first place.
For an alternative to the ActionScript 2.0 Debugger panel, you may want to check out John Grden's Xray (The AdminTool), a free application available from OSFlash.