There are three ways to create new movieclips on stage while a movie is running:
The attachMovie method (built in to all movieclips) allows any movieclip in the library which has been given a linkage id to be attached to an existing movieclip (or the main timeline) in the movie while it is running. The format for doing so is:

where the last line is gray to show that it is optional. When you attach a movieclip from the library, you must specify what you are attaching it to, what is its name (linkageId) in the library, what will be its instance name, and what depth (0 to some ridiculously big number that I don't remember) it will be within the timeline it is being attached to. Note that if you attach a movieclip at the same depth as something that already exists in the timeline at that depth, the previous thing will be deleted.
If you want to specify anything in particular about the movieclip being attached, like its position (within the timeline it is being attached to), its xscale or height or width, or a property that you assign and will use later, the place to do that is in the last parameter of the attachMovie.
To attach a one-frame snowflake movieclip to the stage at 100, 100, for example, you would first create a snowflake movieclip with symbol name flake, delete it from the stage (it's still in the library), open the library and right-click on the snowflake movieclip, check Export For Actionscript, and make sure "flake" (without the quotes) appears in the Identifier box. If you want to use an identifier other than the symbol's name, you can type in a new one. Then in frame 1 of the main movie, put this code:
this.attachMovie("flake", "f", 0, {_x:100, _y:100});
That will cause the flake movieclip to be attached to the main timeline ("this", because your code is on the main timeline) at depth 0 (ie, physically behind anything that might be added later at a higher depth) and named f. It will be positioned at 100, 100 as soon as it appears.
If you look in the Help documents, you'll see that attachMovie returns a value of type MovieClip -- that is, it returns a reference to the movieclip that has just been attached. This can be useful if you want to do anything further to the clip after attaching it, like assigning an event handler to it. This code in frame 1 will allow you to create a variable to hold that pointer and assign a value to it:
var flake:MovieClip;
flake = this.attachMovie("flake", "f", 0, {_x:100, _y:100});
You can now refer to the clip you added in a number of ways -- either by its instance name (this.f or this["f"]) or by the reference you created (flake). Say you now want this flake to float down the screen until it reaches the bottom (of a 300-pixel high screen) and then delete itself. You can create a fallAndDelete function and use the reference you created to assign an event handler to the flake:
var flake:MovieClip;
function fallAndDelete() {
this._y += 2;
// assume flake has center registration point
if (this._y > 300 + this._height/2) {
this.removeMovieClip();
}
}
flake = this.attachMovie("flake", "f", 0, {_x:100, _y:100});
flake.onEnterFrame = fallAndDelete;
The example above sends the flake drifting downward at 2 pixels per frame. If you want to tell each movieclip its own speed, you can assign a property to the clip when it is attached so it will know its own speed:
var flake:MovieClip;
function fallAndDelete() {
this._y += this.speed;
if (this._y > 300 + this._height/2) {
this.removeMovieClip();
}
}
flake = this.attachMovie("flake", "f", 0, {_x:100, _y:100, speed:2});
flake.onEnterFrame = fallAndDelete;
Let's add a rotation property also, and change the example to attach three copies of flake to the stage at even intervals, causing them all to drift downward and spin a bit as they go:
var flake:MovieClip;
function fallAndDelete() {
this._y += this.speed;
this._rotation += this.rdegrees;
if (this._y > 300 + this._height/2) {
this.removeMovieClip();
}
}
for (var i=0; i < 3; i++) {
flake = this.attachMovie("flake", "f"+i, i, {
_x:100+i*100,
_y:100,
speed:2,
rdegrees:2
});
flake.onEnterFrame = fallAndDelete;
}
Notice the places where strings and number values were replaced with expressions involving i, which is incremented from 0 to 1 to 2 as each clip is added. That code produced a line of three movieclips all drifting down and turning at exactly the same rate: a perfect little snowflake drill team.
It would probably be nicer to have each flake added with some randomness about it, so here is an example of making a little 100-flake snowstorm instead, where the size, position, rotation and transparency of each snowflake is a little different from its neighbor. Notice that also, instead of deleting each movieclip as it hits the bottom of the stage, we have it move itself back up to the top of the stage, somewhere between 0 and 3 pixels above the top of the stage (and renamed the function accordingly):
var flake:MovieClip;
// returns a real number between a and b
function randomBetween(a:Number, b:Number):Number {
return a + Math.random()*(b-a+1);
}
function fallAndRestart() {
this._y += this.speed;
this._rotation += this.rdegrees;
if (this._y > 300 + this._height/2) {
// don't delete it; start it again above the stage
this._y = randomBetween(0-this._height/2, 3-this._height/2);
}
}
for (var i=0; i < 100; i++) {
flake = this.attachMovie("flake", "f"+i, i, {
_x:randomBetween(0, 400),
_y:randomBetween(0, 300),
_alpha:randomBetween(50, 100),
speed:randomBetween(1, 3),
rdegrees:randomBetween(1, 4)
});
flake.onEnterFrame = fallAndRestart;
}
But there's still something not right about that snowstorm. To make it more realistic (a bit anyway), the snowflakes in the foreground should be bigger, brighter and slower moving than those in the background. We'll make an array called ranges with 3 elements, each of which describes the range of values to apply for a foreground flake, an intermediate flake, and a background flake. Every time a flake is created, a random element of ranges will be selected to define which type of new snowflake is to be created, and to specify the range of values from which a random number will be selected for each of its attributes. Here is that code:
var flake:MovieClip;
var ranges:Array = [
// big foreground flakes
{size1:80, size2:100, alpha1:95, alpha2:100, speed1:1, speed2:2},
// medium flakes
{size1:70, size2:80, alpha1:80, alpha2:95, speed1:2, speed2:3},
// small background flakes
{size1:40, size2:70, alpha1:60, alpha2:80, speed1:3, speed2:4}
];
function randomBetween(a:Number, b:Number):Number {
return a + Math.random()*(b-a+1);
}
function fallAndRestart() {
this._y += this.speed;
this._rotation += this.rdegrees;
if (this._y > 300 + this._height/2) {
this._y = randomBetween(0-this._height/2, 3-this._height/2);
}
}
for (var i=0; i < 100; i++) {
// pick a random element of ranges
var r:Number = randomBetween(0, 2);
// find a scale to apply horizontally and vertically
var newscale:Number = randomBetween(ranges[r].size1, ranges[r].size2);
// find and apply all properties, using ranges array
flake = this.attachMovie("flake", "f"+i, i, {
_x:randomBetween(0, 400),
_y:randomBetween(0, 300),
_xscale:newscale,
_yscale:newscale,
_alpha:randomBetween(ranges[r].alpha1, ranges[r].alpha2),
speed:randomBetween(ranges[r].speed1, ranges[r].speed2),
rdegrees:randomBetween(ranges[r].speed1, ranges[r].speed2)
});
flake.onEnterFrame = fallAndRestart;
}
As a final embellishment, you can change the x position of the flakes in FallAndRestart so that they drift in the direction of the mouse, as in the example at the top of this page. That code is in the fla available by subscription in the link at right. In the final movie, I used a frame rate of 15 fps, and small ranges like 0.5 - 0.7 for the speed property to make the snowflakes drift.
last update: 18 Mar 2006
Discussed on this page:
use attachMovie to attach snowflake movieclips from the library, apply random position, alpha, rotation, speed
Files:
snowflakes.fla
In snowflakes.zip, password required
Subscription:
A password may be obtained by subscription ($20 for one month)
An access password will be emailed to the address you specify within 24 hours of receipt of payment, and will remain active for 30 days thereafter. A list of all files currently available at the site may be viewed here.