You've made it through the process of exporting an application without a compile-time error. So far, so good. But as you begin to work with the exported application, you discover that it's just not working properly. Perhaps displayed data is not correct, text and graphics onscreen are not positioned correctly, or when you press a button that's supposed to send information to the server, nothing (or the wrong thing) happens. These kinds of bugs are known as run-time bugs because they're not obvious until the application is run and put through the ringer.
Run-time bugs typically result from spelling or logic errors, such as mistakenly referring to a movie clip instance named miMovie_mc instead of myMovie_mc, or using a less-than operator (<) rather than the intended greater-than operator (>) in a conditional statement. Or a function might contain a script that's logically but not syntactically faulty, so that when executed the function has a very bad effect on the rest of the application.
Unfortunately, information about these kinds of bugs doesn't automatically show up in the Output window; a bit of sleuthing and logical deduction is required to find and eliminate such errors.
Fortunately, Flash provides several tools to help you perform various deductive reasoning tasks with your project while it plays. The two most widely used tools are the trace() action and the Debugger. We'll look at both of these tools in the following sections.
The trace() action allows you to output a custom message to the Output panel in response to a script's execution. This is useful to get a behind-the-scenes look at how a script is functioningprimarily to test interactivity and to output custom messages that tell you what's happening with the data in a movie at any point in time. Consider the following simple example.
Imagine you want to place the following script on Frame 10 of your movie:
trace ("The movie is currently on Frame " + _currentframe);
When the movie is played in the testing environment and reaches Frame 10, the Output panel will automatically open and display the following message:
"The movie is currently on Frame 10"
This example is not meant to demonstrate the true power of the trace() action, but simply to illustrate its use. The trace() action can be useful in finding bugs because it allows you to track down the error by means of deduction, as the following exercise shows.
Choose File > New. From the New Document dialog box that appears, select Flash Document to start a new Flash project.
Because the end result of this project is to teach how custom messages are output in the Output panel and not so much to see the onscreen results of ActionScript, we won't use a prebuilt project file. Nevertheless, we'll need a simple movie clip and button instance to work with. Let's create those.Select the Oval tool and draw a small circle anywhere on the stage.
The size and appearance of the circle are not important for this exercise.With the circle selected, press F8 on your keyboard to open the Convert to Symbol dialog box. Give this symbol any name you choose, select the Button behavior, and click OK.
This step converts the circle to a button.With the Property Inspector open, select the button instance and give it an instance name of myButton_btn.
Next we'll create a movie clip instance.Select the Rectangle tool and draw a small square on the stage.
Again, the way it looks is not important.With the square still selected, press F8. Give this symbol any name you choose, but select the Movie Clip behavior. Click OK.
This step converts the square to a movie clip.With the Property Inspector open, select the square movie clip instance and give it an instance name of myClip_mc.
Now we'll do some scripting.With the Actions panel open, select Layer 1 and add the following script:
myButton_btn.onPress = function(){ trace("Activation button is pressed"); myTraceTest(); }
Add the following function definition at the end of the current script:
function myTraceTest(){ trace ("myTraceTest function is executed"); myClop_mc.onMouseDown = function(){ trace("I now have POWER!"); } }
This function uses a trace() action to send a message to the Output panel indicating that the function has been executed. The next few lines are intended to assign an onMouseDown event handler method to the myClip_mc movie clip instance, so that another custom trace message is sent to the Output panel whenever the mouse button is pressed. This event handler is not assigned to the clip until the function has been executed, which occurs only after the myButton_btn instance has been pressed. As we mentioned, that's what this part of the script is intended to do; however, note that there's an error in our script. We've intentionally misspelled myClip_mc as myClop_mc.
Let's test the project.Choose Control > Test Movie.
In the testing environment, click the myButton_btn instance. The Output panel will open and display the following message:
Activation button is pressed myTraceTest function is executed
This message indicates that the button worked, and that the function call the button made to myTraceTest() was executed. So far, so good. Because the function executed, myClip_mc would have been assigned an onMouseDown event handler method, allowing the user to click anywhere on the stage to see the trace message, "I now have POWER!" displayed in the Output panel. When you click, though, nothing happens. Interesting. Using our trace() actions, we can deduce that the script on the button was executed, and the function was executed, but something went wrong with the part of the script that assigns the onMouseDown event handler to myClip_mc. We know where to look for a bug!
Sure, we gave it away in Step 9, when we told you that the event handler method assignment had a spelling error. But even without this help you could have quickly deduced that something was wrong with that section of code by simply realizing that everything leading up to the event handler assignment worked as designed, as indicated by the trace() messages we used. trace() messages are very useful in tracking down bugs.Close the test movie to return to the authoring environment. Select Frame 1, open the Actions panel, and fix the spelling error in the function definition by changing myClop_mc to myClip_mc. Choose Control > Test Movie.
In the testing environment, click the myButton_btn instance. The Output panel will open and display this message:
Activation button is pressed myTraceTest function is executed
This indicates that the button worked, and that the function call the button made to myTraceTest() was executed.
Now click anywhere on the stage. The message "I now have POWER!" will appear in the Output window, indicating that the entire project is now working as it should.Close the test movie, return to the authoring environment, and save this file as Testing1.fla.
We will build on this file in the next section.
This has been a simple demonstration of the trace() action. You can see how strategically placed trace() actions can help you to follow the execution of a script, and thus deduce where an error might exist. This feature lets you focus your bug-sleuthing efforts on a particular section of code.
The trace() action can be used to inform you when a function has been executed:
function myFunction(){ trace("myFunction has been called"); }
or what parameter values were passed to the function when it was called:
function myFunction(name:String, age:Number){ trace("myFunction has been called and passed values of " + name + " and " + age); }
or how conditional statements are evaluated:
if (age < 100){ trace("age is less than 100"); }else if (age > 100){ trace("age is greater than 100"); }else{ trace("age is exactly 100"); }
and so on.
These little hints throughout your code can provide insight into how things are working behind the scenes.TIP
trace() actions can be turned on or off individually by commenting the action, as in the following example:
//trace("Let me speak my peace!")
This strategy can be helpful if you're using several trace() actions in your code, but you only want to focus on the output of an individual trace() action.
Normally, you can't see either the data in variables or the values associated with movie properties while your movie is playing; however, this data plays a crucial role in determining how your interactive movie looks and works. Visual bugs are easy to spot, but bugs in ActionScripts can be trickier to track down and correct. Not only is the data usually invisible; it can also be changing constantly. This is where Flash's Debugger comes in: with the Debugger, you can view the real-time values of variables and properties while a movie is playing, as well as change values at will to see how such alterations will affect the flow of an individual script or the movie as a whole. In addition, the Debugger allows you to control script execution line by line. You can start and pause a script at different points of its execution, which lets you slow to a crawl something that normally takes milliseconds to complete. This functionality enables you to assess how a particular script is affecting the movie as it executes. By taking control of the movie's logic in this manner, you can often quickly pinpoint problems in your scripts.
Before learning how to use the Debugger, it's a good idea to become familiar with its interface, which is made up of the following elements:
Display list. The Display list shows the hierarchical structure of the movies in the movie (Flash player) window, including the main movie, movie clips, and any movies that have been loaded. This list is updated in real time as various clips and loaded movies are added and removed from the Player window as the movie plays. Selecting a movie in the Display list causes the Properties and Variable tabs to reflect that movie's current properties and variables.
Properties tab. Clicking this tab displays the names and current property values of the movie selected in the Display list. Some of the properties here are dimmed, meaning that you can view but not change them. If you double-click a value that's not dimmed, you can change that value and immediately see the effect of that change in the movie while it plays. Because the movie may contain scripts with conditional statements based on the current value of a specific property of a particular movie, you can make sure that these conditional statements are working properly by changing a property value on this tab. Keep in mind, however, that you can't use expressions when entering new property values from the Debugger: New values can be strings (remember to use quotes), numbers, or a Boolean (true or false).
Variables tab. Clicking this tab displays the names and current values of the variables included in the movie that's selected in the Display list. Double-clicking a value allows you to change it and view the immediate results of that change in the movie. Because variables provide the foundation of most ActionScripts, using the Debugger to change individual values can help you track down the problems that might occur when a movie is fed a certain piece of data. Although you can see the values of Object and Array variables on this tab, you can't change them, nor can you use expressions when entering new variable values from the Debugger. New values can be strings (remember to use quotes), numbers, or a Boolean (true or false).
Locals tab. This tab contains a list of local (temporary) variables that are used within a function when that function block is being stepped through using breakpoints. Breakpoints are explained in greater detail in the exercise for this section.
Watch list tab. The Watch list tab contains a list of variables that you've designated to be "watched," meaning that their values are constantly monitored on this tab. You can add variables from multiple movies to this list so that you can manage all of them from a single tab.
Call Stack. When a script calls a functionand even when a function calls another function that may call yet another function (enough already!)this pane displays a hierarchical list of those calls. This list helps you determine the path the project takes to perform a certain task, enabling you to possibly optimize your code a bit so that it requires fewer steps to perform a task, with the end goal of helping it run faster.
Breakpoint controls. These buttons control the execution of scripts when using breakpoints (markers in a script that indicate a pause in the script's execution). These buttons are discussed in more detail in the exercise for this section.
Code window. This window displays individual scripts within your project, similar to the code window in the Actions panel. The window is updated to display a script when a breakpoint is encountered within that script, although you can specifically select a script to display by using the drop-down menu above the code window.
Debugger Options button. Clicking this button displays a menu of commands pertaining to the Debugger. The menu also contains commands for controlling playback and view quality of the movie being debugged.
Because each project is totally unique, it would be impossible to address every conceivable way in which the Debugger could be used to track down and eliminate bugs. In the following exercise, we'll attempt to give you an overall feel for the process, so that you know how to insert and use breakpoints, see and work with your project's invisible data, and understand the usefulness of the Debugger's features.
Open Testing1.fla.
This is the file you created in the preceding exercise. We'll add a movie clip instance as well as a few additional scripts to test the features of the Debugger.While pressing the Control key (Windows) or Command key (Macintosh), click and drag the square movie clip instance (named myClip_mc) to create a duplicate.
Place this duplicate anywhere on the stage.Select the duplicate and give it an instance name of myOtherClip_mc.
Next we'll add event handlers to the two square movie clip instances.With the Actions panel open, select Frame 1 of Layer 1 and add the following script:
myClip_mc.myVariable = 100; myClip_mc.onEnterFrame = function(){ if (this.myVariable < 100){ this._rotation += 1; } }
Add the following script at the end of the current script:
myOtherClip_mc.myOtherVariable = 50; myOtherClip_mc.onEnterFrame = function(){ if (this.myOtherVariable < 50){ this._rotation += 1; } }
This script has similar functionality to the one in Step 4, with a couple of minor exceptions. The name of the variable is myOtherVariable, and the variable is assigned to the myOtherClip_mc timeline with an initial value of 50. When this variable's value drops below 50, myOtherClip_mc will start rotating.
Let's test this new functionality and see how the Debugger can help control these values to affect the movie as it plays.Choose Control > Debug Movie.
This step opens the movie in the testing environment, with the Debugger panel open. Initially, the movie is paused because Flash assumes that you want absolute control over when the movie begins playing and the debugging process beginsespecially when using breakpoints. Click the Continue button on the Debugger.
The Display list contains a hierarchical structure of timelines in the current frame, including the main timeline. Clicking one of the movie clip icons makes that movie's properties and variables the focus of the Properties and Variables tabs, respectively. Let's look at some properties.NOTE
Although _global is shown as a timeline in the Display list, it's actually a global object within the movie, which is available to all timelines. It's shown as a timeline for the sake of congruency.
Click the myClip_mc instance in the Display list; then click the Properties tab to view the various properties of myClip_mc.
Notice that some properties (and their values) are dimmed. This is because they're read-only properties; their values cannot be set, only viewed. All other property values can be set by you as the movie plays. Setting and viewing property values in this manner, while the movie plays, can help you to discover bugs in scripts that use these values in some way. Being able to target and set a specific property value can help you see how a project will react to that change (if the project is scripted to do something in response to that change). Let's change a property value to see how this works.Scroll to the _yscale property at the bottom of the Properties tab. Double-click its value; then enter 150 and press Enter/Return.
The vertical size of myClip_mc changes immediately in the testing environment. This is a simple demonstration of how you can control properties of timelines with the Debugger. Not only do the values change, but you can see the results of the change. Having control over the property values of timelines allows you to test how an application will react to changes in a timeline's position, size, rotation, and so on.
Let's look at variable values next.Click the Variables tab.
Because myClip_mc is still selected in the Display list, the Variables tab displays any variables within that timeline. Remember that we created a variable named myVariable on this timeline. That variable and its initial value of 100 appear on this tab. This value is editable while the movie plays. We created a script that would rotate myClip_mc if this variable's value ever dropped below 100. Let's edit the value to see what happens.Double-click the myVariable value; then enter 99 and press Enter/Return.
myClip_mc immediately begins rotating. Resetting this value to 100 or above stops the movie from rotating. Because variable values are an integral part of how most scripts work (or don't work), being able to view and set values by using the Variables tab will enable you to quickly test the effect of setting different values.In the Display list window, click the myOtherClip_mc icon.
The Variables tab should still be open; it displays the variables inside the newly selected timeline. There is only one variable (myOtherVariable) in this timeline, with an initial value of 50. If you change this value to less than 50, myOtherClip_mc will begin rotating. Do this if you want to test the result.
If you wanted to update values frequently in the Display list for debugging purposes, it could easily become a major hassle to constantly switch among timelines. This is where watches can help, as shown in the following steps.Right-click (Windows) or Control-click (Macintosh) the variable name on the Variables tab and choose Watch from the menu that appears.
This step sets up watching for myOtherVariable; an icon appears next to the variable's name indicating that it's being watched.In the Display list, click the myClip_mc icon. On the Variables tab, right-click (Windows) or Control-click (Macintosh) the variable name and choose Watch from the menu that appears.
This step makes myVariable watched.Click the Watch tab.
This tab shows the two variables from the two different timelines. This demonstrates the main purpose of the Watch tabenabling you to work with variables from multiple timelines without having to constantly switch among them via the Display list. Variable values here can be changed in the same manner as discussed in the previous few steps.
To remove a variable from the Watch list, right-click (Windows) or Control-click (Macintosh) its name on the Watch tab and choose Remove from the menu that appears.Close the test movie to return to the authoring environment. Save this file as Testing2.fla.
We will use this file again in the next exercise.
As this exercise has shown, the Debugger gives you a deep look into an applicationits timelines, variable values, and property values. You can test different scenarios to see how the application reacts to data you input. You can change values as well as watch those values to make sure that the application is manipulating variable and property values correctly under various circumstances.Watching and changing property and variable values are only part of the debugging process. Next, we'll look at how setting breakpoints and stepping through your code using the Breakpoint controls on the Debugger panel can also help you locate problems in scripts.
Open Testing2.fla.
In this exercise, we'll add a single line of script to the file from the preceding exercise, after which we'll begin working with the Debugger again. Make sure that the View Line Numbers option is turned on for the Actions window.With the Actions panel open, select Frame 1 of Layer 1 and add a breakpoint to line 3 by clicking the number 3 in the left margin of the Actions window.
A small red dot appears to the left of the line of script, indicating that a breakpoint has been placed there. When this script is executed (as a result of the button's being clicked), script execution will pause just before line 3, which contains a call to the myTraceTest() function. Line 2, which sends a trace message to the Output panel, will still be executed.Insert the following line of script on line 7, after the line trace ("myTraceTest function is executed");:
var myVariable = 46;
Choose Control > Debug Movie.
This step opens the movie in the testing environment with the Debugger open. As mentioned earlier, the movie will be paused initially.Click the Continue button on the Debugger panel.
This action begins playback of the movie.Click the circle button.
Remember that in Step 2 of this exercise, we placed a breakpoint on line 3 of the script, within the onPress event handler of this button instance. When the button is clicked, the script begins to execute but pauses at line 3. A small arrow appears within the breakpoint dot on line 3 to indicate that the script's execution is paused at that point. Line 2 has a trace() action that sends a message to the Output panel, so that window opens and displays the message. Without the breakpoint, this script would have called the myTraceTest() function, but setting the breakpoint caused the script to pause before calling the function. The break in the script's execution allows you to get a snapshot look at property and variable values before the script continues to executeto make sure that everything looks the way it shouldor to enter property and variable values manually before progressing. Either way, this feature gives you complete control over the testing process, allowing you to test or try to break your program in every way imaginable.
TIP
You can place multiple breakpoints in scripts from the Debugger panel. To set or remove a breakpoint on a particular script, select the script from the drop-down list of scripts above the code window, and click the left margin of the line where you want to place or remove a breakpoint. If you want to remove all breakpoints within your movie at once, click the Remove All Breakpoints button on the Debugger panel.
Now that the script is paused before calling the myTraceTest() function, you can proceed in several ways:
If you click the Continue button, the script continues executing until another breakpoint is encountered or the script has completed execution.
If you click the Step Over button, the script executes the current line but pauses execution again at the next line (unless you're already at the end of the script).
If you click the Step In button, the myTraceTest() function is called but stepped into, meaning that execution pauses on the second line of the function. (The first line contains the opening structure of the function, which simply names the function; there's no reason to pause execution there.)
Click the Step In button on the Debugger panel.
Two actions occur when you click the Step In button: the function is called, but paused at its second line (first line of executable ActionScript), and the name of the functionmyTraceTest()appears in the Call Stack section of the Debugger panel, indicating that the current script has made a call to this function. If myTraceTest() made a call to another function somewhere during its execution (it doesn't), that function's name would appear below the myTraceTest() function in the Call Stack window, indicating the overall path or flow that the script takes to complete its task. As mentioned earlier, observing this flow can provide hints as to where a project's code might be optimized.
NOTE
Anonymous functions called as event handlers appear in this window when executed; therefore, the execution of the onPress event handler on the myButton_btn instance is visible in the Call Stack window.
Click the Locals tab on the Debugger panel.
This tab needs to be open as we proceed.Click the Step Over button twice.
The first use of the Step Over button executes the trace() action within the function. As a result, a message appears in the Output panel.
With the second click of the Step Over button, the next line in the function definition is executed, which creates a local variable named myVariable and assigns it a value of 46. After this variable is created, it appears on the Locals tab. This variable's value can be changed by double-clicking its current value and entering a new one. This feature allows you to control local variable values that a function uses in its execution, providing another means of testing scriptsin this case, functions.Close the test movie and save this file as Testing3.fla.
This completes the debugging session. As you've learned, using breakpoints and stepping through code line by line allows you to follow the execution of the code step by step. If the code contains an error, debugging enables you to see the moment (as well as the code) where things go awry.Our focus to this point has been the debugging of a movie that's played within the testing environment. But Flash allows you to also debug a movie on the Web, a process known as remote debugging.
By default, SWF files on the Web cannot be debuggedthe assumption is that you don't necessarily want people to know how your movie is assembled, which the debugging process completely reveals. To allow your movie to be debugged remotely, you must take three steps:
The following exercise steps you through the process.
NOTE
For remote debugging to work, you must have the Debug version of the Flash player installed. (By default, this player is not installed.) Instructions for installing the Debug version are located in Macromedia\Flash MX 2004\Players\Readme.htm. The Debug version of the player is like the regular (release) version, but a bit larger in size due to extra code that helps facilitate remote debugging. If you're having trouble with remote debugging, double-check that you have the Debug version installed.
Open the Flash document you want to make available for remote debugging.
Use the Testing3.fla file from the preceding exercise, or another FLA of your choice.In the authoring environment, choose File > Publish Settings.
This action opens the Publish Settings dialog box.On the Formats tab in the Publish Settings dialog box, select the Flash and HTML format types; then click the Flash tab.
These settings will cause Flash to create an HTML page and embed the selected Flash movie within the page.On the Flash tab, select the Debugging Permitted option.
This step makes the Password field editable.To set a password that must be entered before debugging the movie, enter a password into the Password box.
If you leave the Password field blank, you can debug the movie without first providing a password; however, you'll probably want to use a password, so that only those you authorize can view the code in the movie.Publish the movie.
Flash creates HTML, SWF, and SWD files. As we mentioned earlier, the SWD file is a special Flash-created file that enables the movie to be debugged.Upload all three of these files to your server.
All three files must be placed in the same directory.In Flash, choose Window > Development Panels > Debugger to open the Debugger panel. Click the Debugger panel's Options button and select Enable Remote Debugging from the menu that appears.
The Debugger is now enabled for remote debugging.Using your browser, navigate to the URL of the HTML file containing your SWF.
This action opens the Remote Debugging dialog box, which asks you to indicate the location where Flash (the authoring tool) is running.Because Flash is most likely running on your own computer, select the Localhost option and then click OK.
If you set the file to require a password before it can be debugged (as described in Step 5), a box will appear asking you for that password.Enter the password, if one is required.
The movie opens, the Debugger becomes active, and you can now debug the movie as discussed in the previous sections.TIP
If you want to disable debugging of the remote file completely so that the SWF file simply plays when opened, either move or delete the associated SWD file that was created and uploaded to the server as described in Steps 6 and 7. This file contains the functionality that enables debugging. Without it, debugging is impossible.
This step completes the exercise and this lesson.