All movie clip instances and externally loaded movies displayed in the Player reside in a visual stacking order akin to a deck of cards. When instances or externally loaded .swf files overlap in the Player, one clip (the "higher" of the two) obscures the other clip (the "lower" of the two). This appears simple enough in principle, but the main content stack, which contains all the instances and .swf files, is actually divided into many smaller substacks. We'll first look at these substacks individually first, and then we'll see how they combine to form the main stack. (The content stack in this discussion has no direct relation to the LIFO and FIFO stacks discussed in Chapter 11.)
Each movie clip instance, including the main timeline of a movie, places its various contents (movie clips, text fields, and buttons) on one of two stacks: the internal layer stack (for author-time assets) or the programmatically generated content stack (for runtime assets). The items in these stacks (known collectively as the clip's content stack) are given an integer depth position that governs how they overlap on screen. Depth positions range from -16384 to 1048575. Depths from 0 to 1048575 are reserved for dynamically generated content; depths from -16383 to -1 are reserved for author-time content; and depth -16384 is reserved for dynamic content that appears beneath all author-time content in each clip. To retrieve the depth position of an item, we use the getDepth( ) method. To change the depth position of two movie clips, we use the swapDepths( ) method.
Instances created manually in the Flash authoring tool reside in the internal layer stack. This stack's order is governed by the actual layers in a movie's timeline; when two manually created instances on separate timeline layers overlap, the instance on the uppermost layer obscures the instance on the lowermost layer. (Here, "uppermost" means that a layer appears at the top of the timeline panel in the Flash authoring tool).
Furthermore, because multiple clips can reside on a single timeline layer, each layer in the internal layer stack actually maintains its own ministack. Overlapping clips that reside on the same layer of a timeline are stacked in the authoring tool via the Modify Arrange commands.
We can swap the position of two instances in the internal layer stack using the swapDepths( ) method, provided they reside on the same timeline (that is, the value of the two clips' _parent property must be the same). Prior to Flash 5, there was no way to alter the internal layer stack via ActionScript.
The depth position of author-time assets can be unpredictable and is considered reserved for use by the authoring tool. Therefore, when swapping the depths of an author-time movie clip and a dynamically created clip, always use the target parameter of swapDepths( ) — not an integer depth level — as described in the ActionScript Language Reference entry for MovieClip.swapDepths( ).
Programmatically generated instances are normally stacked separately from the manually created instances held in the internal layer stack. Each movie clip has its own programmatically generated content stack that holds:
Movie clip instances created via duplicateMovieClip( ), attachMovie( ), and createEmptyMovieClip( )
Text field instances created via createTextField( )
The stacking order for movie clips in the programmatically generated content stack varies, depending on how they were created.
A new instance generated via attachMovie( ) or createEmptyMovieClip( ) is always stacked above (i.e., in the foreground relative to) the clip to which it was attached. For example, suppose that we have two clips—X and Y—in the internal layer stack of a movie and that X resides on a layer above Y. Now further suppose we attach a new clip, A, to X and a new clip, B, to Y:
x.attachMovie("A", "A", 0); y.attachMovie("B", "B", 0);
In our scenario, the clips appear from top to bottom in this order: A, X, B, Y, as shown in Figure 13-1.
Once a clip is generated, it too provides a separate space above its internal layer stack for more programmatically generated clips. That is, we can attach clips to attached clips.
Clips attached to the _root movie of a Flash document are placed in the _root movie's programmatically generated content stack, which appears in front of all clips in the _root movie, even those that contain programmatically generated content.
Let's extend our example. If we attach clip C to the _root of the movie that contains clips X, Y, A, and B, then clip C appears in front of all the other clips. Figure 13-2 shows the extended structure.
Each instance duplicated via duplicateMovieClip( ) is assigned to the programmatic stack of its seed clip's parent (the movie clip upon whose timeline the seed clip resides). Let's return to our example to see how this works.
If we create clip D by duplicating clip X (which was created manually), then clip D is placed in the stack above _root, with clip C. A seed clip and its duplicate always share the same parent (in this example, _root). Similarly, if we create clip E by duplicating clip D, then E is also placed in the stack above _root, with C and D. But if we create clip F by duplicating clip A — which was created with attachMovie( ) — then F is placed in the programmatic stack above X, with clip A. Again, F and its seed clip, A, share the same parent: X. Figure 13-3 is worth a thousand words.
You may be wondering what determines the stacking order of clips C, D, and E, or of clips A and F, in Figure 13-3. The stacking order of a programmatically generated clip is determined by the depth argument passed to the attachMovie( ), createEmptyMovieClip( ), or duplicateMovieClip( ) methods, and can be changed at any time using the swapDepths( ) function. Each programmatically generated clip's depth (sometimes called its z-index) determines its position within a particular stack of programmatically generated clips.
The depth of a clip can be any integer and is measured from the bottom up — so, depth 5 is lower than depth 6, depth 7 is higher than (i.e., in front of) depth 6, depth 8 is higher still, and so on. When two programmatically generated clips occupy the same position on screen, the one with the greater depth value is rendered in front of the other.
Although multiple clips can occupy a single author-time timeline layer, all depth positions are single-occupant dwellings. Only one clip can occupy a depth position at a time—placing a clip into an occupied position displaces (and deletes) the layer's previous occupant.
It's okay for there to be gaps in the depths of clips; you can have a clip at depth 0, another at depth 500, and a third one at depth 1000. No performance hit or increase in memory consumption results from having gaps in your depth assignments.
In addition to the internal layer stack and the programmatically generated content stack, there's a third (and final) kind of stack, the document stack (or level stack), which governs the overlapping not of instances, but of entire .swf files loaded into the Player via loadMovie( ).
The first .swf file loaded into the Flash Player is placed in the lowest level of the document stack (represented by the global property _level0). If we load any additional .swf files into the Player after that first document, we can optionally place them in front of the original document by assigning them to a level above _level0 in the document stack. All of the content in the higher-level documents in the level stack appears in front of lower-level documents, regardless of the movie clip stacking order within each document.
Just as the programmatically generated content stack allows only one clip per layer, the document stack allows only one document per level. If we load a .swf file into an occupied level, the level's previous occupant is replaced by the newly loaded document. For example, you can supplant the original document by loading a new .swf file into _level0. Loading a new .swf file into _level1 visually obscures the movie in _level0, but it does not remove it from the Player.
Figure 13-4 summarizes the relationships of the various stacks maintained by the Flash Player.
The layering of movie clips and timeline layers affects code execution order. The rules are as follows:
Code on frames in different timeline layers always executes from top to bottom (relative to the timeline panel).
When manually created instances are initially loaded, code in their timeline and onLoad( ) event handlers executes according to the Load Order set in the Publish Settings of a Flash document—either Bottom Up, which is the default, or Top Down.
For example, suppose we have a timeline with two layers, top and bottom, where top is above bottom in the layer stack. We place clip X on layer top and clip Y on layer bottom. If the Load Order of the document is set to Bottom Up, then the code in clip Y will execute before the code in clip X. If, on the other hand, the Load Order of the document is set to Top Down, then the code in clip X will execute before the code in clip Y. This execution order applies only to the frame on which X and Y appear for the first time.
Once loaded, all instances of a movie are added to an execution order, which is the reverse of the load order; the last instance added to the movie is always the first to have its code executed.
Use caution when relying on these rules. Layers are mutable, so you should avoid producing code that relies on their relative position. Strive to create code that executes safely without relying on the execution order of the clips in the stack. We can avoid some of the issues presented by the execution stack by keeping all our code on a scripts layer at the top of each code-bearing timeline.