The Display List: Chapter 4 - Learning ActionScript 3.0
Pages: 1, 2, 3, 4

The showChildren() function in action

Take a look at the function in action. Figure 4-4 shows a sample file that will be analyzed. The rectangle and circle movie clips, with their instance names, are indicated in the figure. Within the rectangles, a shape gives the fill and stroke appearance. Inside the circles, a shape provides the fill and stroke as well as a static text element.

Example
Figure 4-4: A look at the stage of trace_display_list.fla

When the function runs, the following is traced to the output window, showing all children of the stage. It lists display containers by name and object reference, and display objects by object reference alone.

root1 [object MainTimeline]
largeContainer [object largeContainer_1]
[object Shape]
smallContainer [object smallContainer_2]
[object Shape]
child2 [object MovieClip]
[object Shape]
[object StaticText]
child0 [object MovieClip]
[object Shape]
[object StaticText]
child1 [object MovieClip]
[object Shape]
[object StaticText]

You can improve the readability of the trace by adding indents to show the parent-child relationship of the traced objects. The following is seen in trace_display_list2.fla (bold lines are new or changed).

1   function showChildren(dispObj:*, indentLevel:Number):
                             void {
2     for (var i:int = 0; i < dispObj.numChildren; i++) {
3         var obj:DisplayObject = dispObj.getChildAt(i);
4         if (obj is DisplayObjectContainer) {
5             trace(padIndent(indentLevel), obj.name, obj);
6             showChildren(obj, indentLevel + 1);
7         } else {
8             trace(padIndent(indentLevel) + obj);
9         }
10     }
11 }
12
13 showChildren(stage, 0);
14
15 function padIndent(indents:int):String {
16     var indent:String = "";
17     for (var i:Number = 0; i < indents; i++) {
18         indent += "   ";
19     }
20     return indent;
21 }

The function in lines 15 through 21 takes a desired indent level and returns four spaces for each indent specified. For example, the first child will have no indent, or an indent level of 0. Therefore, it will return four spaces zero times, for no indent effect. The first nested child will have an indent level of 1, so the function will return four spaces of indent. A child at a second tier of nesting will have an indent level of 2, so the function will return eight spaces of indent, and so on.

We can indicate the number of indents by passing a value into a second parameter in the main function, in the form of indentLevel, as seen in line 1. Now that this second parameter exists, we've changed the calls to the function, at lines 6 and 13, to add the indent value. The process begins at line 13 with an indent level of zero. Each recursive call, however, must be indented one more level, so line 6 adds 1 to the indentLevel argument each time the function is called.

Finally, lines 5 and 8 add the new spaces, for each level of indent, that are returned by the padIndent() function. The result, shown here, is a more human-readable output with the indents representing nested children.

root1 [object MainTimeline]
     largeContainer [object largeContainer_1]
        [object Shape]
         smallContainer [object smallContainer_2]
            [object Shape]
             child2 [object MovieClip]
                [object Shape]
                [object StaticText]
         child0 [object MovieClip]
            [object Shape]
            [object StaticText]
        child1 [object MovieClip]
           [object Shape]
           [object StaticText]

If you wish, you may also change the string returned from the padIndent() function to another number of spaces, or even another character such as a period.

Section 4.2: Adding and Removing Children

The previous section described the parts of the display list, and how to analyze an existing list. But you'll also need to know how to add to and remove from the display list at runtime. In previous versions of ActionScript, you needed to rely on varying methods to add items to the stage. For example, you needed to use separate methods for creating a movie clip, placing a library movie clip on stage, or duplicating a movie clip. Using the ActionScript 3.0 display list, you only need one approach to create a movie clip. You will use new MovieClip(). Even adding a precreated movie clip from the library is consistent with this syntax, as you'll soon see.

Using addChild()

Adding a display object to the display list requires just two simple steps. The first is to create the object—in this case, an empty movie clip (that is, a movie clip created dynamically, but that currently has no content):

var mc:MovieClip = new MovieClip();

This literally creates the movie clip but does not display it. In order for the movie clip to display, you must add it to the display list using the addChild() method:

addChild(mc);

You can also specify a particular target for the movie clip, as long as that target is a display object container. (Remember, you can't add children to display objects like shapes, videos, text elements, and so on, because they are not display object containers.) So, if you instead wanted to add the mc movie clip nested inside another movie clip called navBar, you would change the second step to:

navBar.addChild(mc);

We've been using movie clips in our examples, but it's also as straightforward to add other display objects. Two simple examples include creating a sprite and a shape:

var sp:Sprite = new Sprite();
addChild(sp);

var sh:Shape = new Shape();
addChild(sh);

You don't even have to specify a depth (visible stacking order), because the display list automatically handles that for you. In fact, you can even use the same addChild() method for changing the depths of existing display objects, but we'll discuss depths in greater detail later in this chapter.

Adding Symbol Instances to the Display List

In the previous, simple examples, we've created display objects without content. In , we'll show you how to draw with code, so you can create content for these movie clips, relying solely on code for small file size and more dynamic control.

However, you will frequently find the need to use custom art in your files, and in those situations code-only solutions will not do. So, in this chapter, we're going to focus on dynamically adding movie clips that already exist in your library. In the accompanying source file, addChild.fla, you will find a unicycle in the library. To add this movie clip to the display list using ActionScript, you must set up the library symbol first.

In prior versions of ActionScript, there were two ways of doing this. The first approach was to assign the symbol a linkage identifier name. This was similar to an instance name for library symbols, in that you could reference the symbol by name using ActionScript. The second way was to assign a class to the movie clip so that it could be created when you created an instance of the class, and also have its own code to execute.

In ActionScript 3.0, these two approaches are unified. Rather than using the linkage identifier, you simply use a class name to reference a symbol in all cases. When you've written a class for the symbol, which we'll do in later chapters, the symbol will behave accordingly. However, when you just want to reference the symbol, Flash will automatically create an internal placeholder class for you, and use the class name to dynamically create the symbol when requested. This approach also allows you to easily add classes later while changing little or nothing in your file.

Example
Figure 4-5: Accessing a symbol's linkage information

Continuing our movie clip example, to add a class name to a symbol, select the movie clip in your library, and then click the Symbol Properties button (it looks like an "i" at the bottom of the library) for access to all the symbol properties. Alternatively, you can focus only on the linkage information by choosing Linkage from the library menu, as seen in Figure 4-5.

In the resulting dialog, seen in 4-6, click to enable the Export for ActionScript option, and add a name to the Class field. When you start working with classes, you will follow a few simple rules and conventions, one of which is to capitalize the first letter of your class name. This is a bit different from naming a variable, where you might choose to use a lowercase first letter, so it's a good idea to get into this practice now. In the addChild.fla source file, we've used the class name Unicycle.

Example
Figure 4-6: Entering a class name for a movie clip in the library Linkage Properties

You will also likely notice that Flash adds the MovieClip class (in this case) to the Base class field for you. This makes it possible to automatically access the properties, methods, and events available to the MovieClip class. For example, you can automatically manipulate the x and y coordinates of your new custom movie clip.

Now that you've given your movie clip a class name, you can create an instance of that custom movie clip class the same way you created an instance of the generic movie clip class. Instead of using MovieClip(), however, you will use Unicycle() to create the movie clip. The same call of the addChild() method is used to add the newly created movie clip to the display list, as seen in the following code. A finished example of this code also exists in the accompanying source file addChild2.fla.

var cycle:MovieClip = new Unicycle();
addChild(cycle);

Using addChildAt()

The addChild() method adds the display object to the end of the display list, which places the object at the top-most z index. This makes it very easy to place items on top of all other items. It's also useful to be able to add a child at a specific position in the display list. For example, you may wish to insert an item into the middle of a vertical stack of display objects.

This example, found in the addChildAt.fla source file, adds a movie clip with the class name Ball to the start of the display list with every mouse click. The ultimate effect is that a new ball is added below the previous balls, and positioned down and to the right 10 pixels, every time the mouse is clicked.

1 var inc:uint = 0;
2
3 stage.addEventListener(MouseEvent.CLICK, onClick, false, 0, true);
4
5 function onClick(evt:MouseEvent):void{
6     var ball:MovieClip = new Ball();
7     ball.x = ball.y = 100 + inc * 10;
8     addChildAt(ball,0);
9     inc++;
10 }

Line 1 initializes a variable that will be incremented with each ball added. Line 3 adds an event listener to the stage, listening for a mouse click, so that any mouse click will trigger the listener's function. The function in lines 5 through 10 performs four basic tasks. In line 6, a new Ball movie clip is created.

Line 7 manipulates the x and y coordinates in a single instruction, setting x equal to y, which is equal to the value of an expression. This is handy when both x and y values are the same. In this case, the expression sets the new ball to x and y of 100 and adds a 10-pixel offset for each ball added. For example, when the first ball is added, inc is 0 so the additional pixel offset is 0*10 or 0. Then inc is incremented at the end of the function, in line 9. The next mouse click that calls the function will update the offset to 1*10 or 10 pixels for the second ball, 2*10 or 20 pixels offset for the third ball, and so on. Most importantly, line 8 adds the ball to the display list, but always at position 0, making sure the newest ball is always on the bottom.

Note: It is possible to manipulate display objects—such as setting properties or invoking methods—both before and after the object has been added to the display list. By doing this, you can create a display object, initialize its properties to your liking, but reserve adding it to the display list until it is needed. See the sidebar "Display Objects and References to Stage and Root" for a notable exception to this rule.

Display Objects and References to Stage and Root

It can be advantageous to manipulate display objects prior to adding them to the display list. For example, you may wish to change properties of an object over time, but prior to that object being visible or being capable of responding to events. If you added the object to the display list immediately, these changes may be seen or experienced by the end user.

Some display object properties or methods, however, may not be valid when the object is not part of the display list. Good examples of this scenario include the root and stage instances of any display object.

Once a display object is added to the display list, its stage and root properties are valid. However, if the object is not part of the display list, its stage property will always return null, and the root property will be valid only if the display object is already a child of another container in a loaded SWF.

Try the following example. You will see that, until the created movie clip is added to the display list, both its stage and root properties are null.

//create display object
var mc:MovieClip= new MovieClip();
// reference to stage and root return null
trace(mc.stage);
trace(mc.root);
//add the object to the display list
addChild(mc);
//references to stage and root return Stage and
    Main Timeline objects respectively
trace(mc.stage);
trace(mc.root);

Invalid stage and root properties can be a common problem if you don't plan ahead. For example, the following code tries to set the location of a movie clip to the center of the stage prior to adding the object to the display list. However, this will fail because querying the stageWidth property of the object's stage reference will not work until after adding the object to the display list.

var mc:MovieClip = new MovieClip();
mc.x = mc.stage.stageWidth/2;
addChild(mc);

This problem can be corrected by transposing the last two lines of the script. It is also possible to work with the stage directly, as its own entry in the display list, as seen in the following snippet:

var mc:MovieClip = new MovieClip();
mc.x = stage.stageWidth/2;
addChild(mc);

However, this is not always possible when using root, because the root of a display object is relative to the object itself. Keep this in mind if you get unexpected results, and check to make sure you are referencing these instance variables only after adding the object to the display list.

Pages: 1, 2, 3, 4

Next Pagearrow