13.3. Creating Movie Clips
We usually treat movie clips just like data objects -- we set their properties with the dot operator; we invoke their methods with the function-call operator (parentheses); and we store them in variables, array elements, and object properties. We do not, however, create movie clips in the same way we create objects. We cannot literally describe a movie clip in our code as we might describe an object with an object literal. And we cannot generate a movie clip with a movie clip constructor function, like this:
myClip = new MovieClip( ); // Nice try buddy, but it won't work
Instead, we create movie clips directly in the authoring tool, by hand. Once a clip is created, we can use commands such as duplicateMovieClip( ) and attachMovie( ) to make new, independent duplicates of it.
13.3.1. Movie Clip Symbols and Instances
Just as all object instances are based on one class or another, all movie clip instances are based on a template movie clip, called a symbol (sometimes called a definition). A movie clip's symbol acts as a model for the clip's content and structure. We must always have a movie clip symbol before we may generate a specific clip object. Using a symbol, we can both manually and programmatically create clips to be rendered in a movie.
A movie clip that is rendered on the Stage is called an instance. Instances are the individual clip objects that can be manipulated with ActionScript; a symbol is the mold from which all instances of a specific movie clip are derived. Movie clip symbols are created in the Flash authoring tool. To make a new, blank symbol, we follow these steps:
Normally, the next step is to fill in the symbol's canvas and timeline with the content of our movie clip. Once a symbol has been created, it resides in the Library, waiting for us to use it to fashion an actual movie clip instance. It is, however, also possible to convert a group of shapes and objects that already exist on stage into a movie clip symbol. To do so, we follow these steps:
The shapes and objects we selected to create the new movie clip symbol will be replaced by an unnamed instance of that new clip. The corresponding movie clip symbol will appear in the Library, ready to be used to create further instances.
13.3.2. Creating Instances
There are three ways to create a new instance based on a movie clip symbol. Two of these are programmatic; the other is strictly manual and is undertaken in the Flash authoring tool.
220.127.116.11. Manually creating instances
We can create movie clip instances manually using the Library in the Flash authoring environment. By physically dragging a movie clip symbol out of the Library and onto the Stage, we generate a new instance. An instance thus created should be named manually via the Instance panel. (We'll learn more about instance names later.) Refer to "Using Symbols and Instances" in the Macromedia Flash Help if you've never worked with movie clips in Flash.
18.104.22.168. Creating instances with duplicateMovieClip( )
Any instance that already resides on the Stage of a Flash movie can be duplicated with ActionScript. We can then treat that independent copy as a completely separate clip. Both manually created and programmatically created clip instances may be duplicated. In other words, it's legal to duplicate a duplicate.
In practice, there are two ways to duplicate an instance using duplicateMovieClip( ):
When created via duplicateMovieClip( ), an instance is initially positioned directly on top of its seed clip. Our first post-duplication task, therefore, is usually moving the duplicated clip to a new position. For example:
ball.duplicateMovieClip("ball2", 0); ball2._x += 100; ball2._ y += 50;
Duplicated instances whose seed clips have been transformed (e.g., colored, rotated, or resized) via ActionScript or manually in the Flash authoring tool inherit the initial transformation of their seed clips. Subsequent transformations to the seed clip do not affect duplicated instances. Likewise, each instance can be transformed separately. For example, if a seed clip is rotated 45 degrees and then an instance is duplicated, the instance's initial rotation is 45 degrees:
seed._rotation = 45; seed.duplicateMovieClip("newClip", 0); trace(newClip._rotation); // Displays: 45
If we then rotate the instance by 10 degrees, its rotation is 55 degrees, but the seed clip's rotation is still 45 degrees:
newClip._rotation += 10; trace(newClip._rotation); // Displays: 55 trace(seed._rotation); // Displays: 45
By duplicating many instances in a row and adjusting the transformation of each duplicate slightly, we can achieve interesting compound transformations (the technique is shown under the load event in Example 10-2).
Using duplicateMovieClip( ) to duplicate clips via ActionScript offers other advantages over placing clips manually in a movie, such as the ability to:
These abilities give us advanced programmatic control over the content in a movie. A salient example is that of a spaceship game in which a missile movie clip might be duplicated when the ship's fire button is pressed. That missile clip might be moved programmatically, then placed behind an obstacle in the movie, and finally, be removed after colliding with an enemy craft. Manual clips do not offer that kind of flexibility. With a manually created clip, we must preordain the birth and death of the clip using the timeline and, in Flash 4, we couldn't change the clip's layer.
22.214.171.124. Creating instances with attachMovie( )
Like duplicateMovieClip( ), the attachMovie( ) method lets us create a movie clip instance; however, unlike duplicateMovieClip( ) it does not require a previously created instance -- it creates a new instance directly from a symbol in a movie's Library. In order to use attachMovie( ) to create an instance of a symbol, we must first export that symbol from the Library. Here's how:
Once a clip symbol has been exported, we may attach new instances of that symbol to an existing clip by invoking attachMovie( ) with the following syntax:
myClip.attachMovie(symbolIdentifier, newName, depth);
where myClip is the name of the clip to which we want to attach the new instance. If myClip is omitted, attachMovie( ) attaches the new instance to the current clip (the clip on which the attachMovie( ) statement resides). The symbolIdentifier parameter is a string containing the name of the symbol we're using to generate our instance, as specified in the Identifier field of the Linkage options in the Library; newName is a string that specifies the identifier for the new instance we're creating; and depth is an integer that designates where in the host clip's layered stack to place the new instance.
When we attach an instance to another clip, that instance is positioned in the center of the clip, among the clip's layered stack (we'll discuss clip stacks soon). When we attach an instance to the main movie of a document, that instance is positioned in the upper-left corner of the Stage, at coordinates (0, 0).
13.3.3. Instance Names
When we create instances, we assign them identifiers, or instance names, that allow us to refer to them later. Notice how this differs from regular objects. When we create a normal data object (not a movie clip), we must assign that object to a variable or other data container in order for the object to persist and in order for us to refer to it by name in the future. For example:
new Object( ); // Object dies immediately after it's created, // and we can't refer to it var thing = new Object( ); // Object reference is stored in thing, // and can later be referred to as thing
Movie clip instances need not be stored in variables in order for us to refer to them. Unlike normal data objects, clip instances are accessible in ActionScript via their instance names as soon as they are created. For example:
ball._ y = 200;
Each clip's instance name is stored in its built-in property, _name, which can be both retrieved and set:
ball._name = "circle"; // Change ball's name to circle
When we change an instance's _name property, all future references to the instance must use the new name. For example, after the previous code executes, the ball reference ceases to exist, and we'd subsequently use circle to refer to the instance.
The manner in which an instance initially gets its instance name depends on how it was created. Programmatically generated instances are named by the function that creates them. Manually created instances are normally assigned explicit instance names in the authoring tool through the Instance panel, as follows:
If a manually created clip is not given an instance name, it is assigned one automatically by the Flash Player at runtime. Automatic instance names fall in the sequence instance1, instance2, instance3...instancen, but these names don't meaningfully describe our clip's content (and we must guess at the automatic name that was generated).
13.3.4. Importing External Movies
We've discussed creating movie clip instances within a single document, but the Flash Player can also display multiple .swf documents simultaneously. We can use loadMovie( ) (as either a global function or a movie clip method) to import an external .swf file into the Player and place it either in a clip instance or on a numbered level above the base movie (i.e., in the foreground relative to the base movie). By managing content in separate files, we gain precise control over the download process. Suppose, for example, we have a movie containing a main navigation menu and five subsections. Before the user can navigate to section five, sections one through four must have finished downloading. But if we place each section in a separate .swf file, the sections can be loaded in an arbitrary order, giving the user direct access to each section.
When an external .swf is loaded into a level, its main movie timeline becomes the root timeline of that level, and it replaces any prior movie loaded in that level. Similarly when an external movie is loaded into a clip, the main timeline of the loaded movie replaces that clip's timeline, unloading the existing graphics, sounds, and scripts in that clip.
Like duplicateMovieClip( ), loadMovie( ) may be used both as a standalone function and an instance method. The standalone syntax of loadMovie( ) is as follows:
where URL specifies the address of the external .swf file to load. The location parameter is a string indicating the path to an existing clip or a document level that should host the new .swf file (i.e., where the loaded movie should be placed). For example:
loadMovie("circle.swf", "_level1"); loadMovie("photos.swf", "viewClip");
Because a movie clip reference is converted to a path when used as a string, location may also be supplied as a movie clip reference, such as _level1 instead of "_level1". Take care when using references, however. If the reference supplied does not point to a valid clip, the loadMovie( ) function has unexpected behavior -- it loads the external .swf into the current timeline. See Chapter 20, "ActionScript Language Reference" for more details, or see Section 126.96.36.199, "Method versus global function overlap issues", later in this chapter.
The clip method version of loadMovie( ) has the following syntax:
When used as a method, loadMovie( ) assumes we're loading the external .swf into myClip, so the location parameter required by the standalone loadMovie( ) function is not needed. We, therefore, supply only the path to the .swf to load via the URL parameter. Naturally, URL can be a local filename, such as:
When placed into a clip instance, a loaded movie adopts the properties of that clip (e.g., the clip's scale, rotation, color transformation, etc.).
Note that myClip must exist in order for loadMovie( ) to be used in its method form. For example, the following attempt to load circle.swf will fail if _level1 is empty:
188.8.131.52. Load movie execution order
The loadMovie( ) function is not immediately executed when it appears in a statement block. In fact, it is not executed until all other statements in the block have finished executing.
Because loadMovie( ) loads an external file (usually over a network), its execution is asynchronous. That is, loadMovie( ) may finish at any time, depending on the speed of the file transfer. Therefore, before we access a loaded movie, we should always check that the movie has finished transferring to the Player. We do so with what's commonly called a preloader -- a simple bit of code that checks how much of a file has loaded before allowing some action to take place. Preloaders can be built with the _totalframes and _framesloaded movie clip properties and the getBytesLoaded( ) and getBytesTotal( ) movie clip methods. See the appropriate entries in Part III, "Language Reference" for sample code. See also Example 10-4, which shows how to build a preloader using the data clip event.
Copyright © 2002 O'Reilly & Associates. All rights reserved.