Tutorial details:
Written by: Sean O'Shell | PiXELWiT Productions
Difficulty Level: intermediate About this tutorial: A wise man once said it's better to teach a man how to fish than it is to give him a free fish. This tutorial is not a free fish. You'll probably have to work for your meal but when it's all said and done you'll be a little wiser plus you'll get to keep the rod, the reel and a few "flashy" lures. I hope you find it beneficial.

TWEENING


Do you remember the very first time you animated something in Flash? If you're like me, you probably started with a blank stage, made a ball symbol, added some frames, chose "create motion tween", turned the last frame into a keyframe then moved the ball to the other side of the stage and VOILA! You could export the SWF and watch your ball roll across the stage like magic. All you did was specify the starting point of the ball, the number of frames and the end point of the ball while Flash undertook the mind-numbingly tedious task of moving the ball in all the other "inbetween" frames for you. Very handy and powerful. But not quite handy and powerful enough. Kids today aren't satisfied with something which is "merely convenient". No no no. They need something "super-duper-way-fantastico-convenient" and that's where the scripted tween comes in.

While the process of creating a manual tween described above is fairly straightforward, it isn't very flexible. Once your SWF is published all your settings (starting point, ending point, number of frames) are pretty much carved in stone. Not only that but every frame you add between your starting point and ending point increases the size of your SWF and FLA files. Fortunately ActionScript allows you to overcome these limitations with a few lines of code. But before we get too far ahead let's take a quick Math refresher course.

Rate of speed equals the distance traveled divided by the amount of time traveling. Huh? Say what? All this means is that if you've been driving down the road for 50 hours and you've driven 550 miles then you can determine your average rate of speed with the following formula:

//______________________________________________
//
rateOfSpeed = distanceTraveled / timePassed;
//
// or in this example
//
rateOfSpeed = 550 miles / 50 hours;
rateOfSpeed = 550 / 50;
rateOfSpeed = 11 Miles Per Hour;
//____________________________________________

That's well and good for cars, but how does that apply to Flash? For starters rather than driving a car down the road in our imaginations, we'll actually be moving a ball across the stage. All we need to get the ball rolling (so to speak), is to convert our units of measure to ones more relevant to Flash. This means instead of tracking time by counting the number of "hours" to pass, we'll be counting the number of "frames" to pass and instead of measuring distance by counting "miles" we'll be counting "pixels". And finally since we'll be using pixels and frames as units of measure, our rate will be in PPF or (Pixels Per Frame) rather than MPH (Miles Per Hour). In short, it means our previous example would look like this:

//_____________________________________________
//
rateOfSpeed = distanceTraveled / framesPassed;
//
// or in this example
//
rateOfSpeed = 550 pixels / 50 frames;
rateOfSpeed = 550 / 50;
rateOfSpeed = 11 Pixels Per Frame;
//__________________________________________

But I can hear some of you saying, "We may have our measurements in units which Flash can handle but how does that get my ball across the stage?" Suppose our goal is to get the ball to move from an _x of 0 to an _x of 550 in a time span of 50 frames. Plugging those variables into the above formula shows that we need to move our ball 11 pixels every time it enters a frame (11 PPF). Once we know the "PPF" all we have to do is multiply our currentFrame times our PPF to determine how far the ball has moved. It's just like in our previous driving example, if you're driving 11 MPH for 50 hours then you can determine how far you've driven by multiplying your rate of speed by the length of time you've been driving (11 MPH * 50 Hours = 550 Miles). So essentially what we're going to do is make a ball, move it 11 pixels every time it enters a frame for 50 frames and it's going to end up at a final _x position of 550.

//____________________________________________
//
// Make a red ball 40 pixels in diameter
createEmptyMovieClip("Ball_mc", 10);
with(Ball_mc){
        lineStyle(40, 0xFF0000);
        lineTo(.5, 0);
        _y = 35;
}
//
// Create a variable to track how many frames have passed
var currentFrame = 0;
//
// Every time the ball enters a frame do the following
Ball_mc.onEnterFrame = function(){
        //
        // Note that we have entered another frame
        // by adding one to our currentFrame variable.
        currentFrame++;
        //
        // Move the ball to the right 11 Pixels Per Frame
        this._x  = currentFrame * 11;
        //
        // If 50 frames have passed, stop moving the ball
        if (currentFrame>50) delete this.onEnterFrame;
}
//____________________________________________





We could also express the key line in the above code:

//____________________________________________
//
this._x = currentFrame * 11;
//____________________________________________

as:

//____________________________________________
//
this._x  = currentFrame * (550 / 50);
//____________________________________________

or as:

//____________________________________________
//
this._x  = (currentFrame / 50) * 550;
//____________________________________________

The arrangement of the code above is probably the most "convenient" (*see footnote) way to illustrate the "Ratio" which exists between distance and time. A "Ratio"is little more than a fraction or percentage as it relates to another fraction or percentage. Consider that you have a set distance (550) and a set amount of time (50). If you travel half way down one of them you will travel half way down the other one. That is to say, if you view frame 25 out of 50, your ball will be at pixel 225 out of 550 or conversely, if your ball is at pixel 225 out of 550 then you would know you were viewing frame 25 of a 50 frame tween. A fraction of one (1/2 in this example) equals the same fraction of the other so they are said to be "proportional". This is a handy thing to know and it can be expressed mathematically like this:

//____________________________________________
//
(currentDistance/totalDistance) = (currentFrame/totalFrames)
//____________________________________________

With this knowledge you can boil a simple tween down to one line of code. Since we want to determine our currentDistance variable (which tracks how far our ball has moved) we need to use a bit of Math to isolate currentDistance on one side of the equation. This can be done by multiplying each side by totalDistance like so:

//____________________________________________
//
totalDistance * (currentDistance/totalDistance) = (currentFrame/totalFrames) * totalDistance
//____________________________________________

Then we can cancel out both totalDistance variables on the left side and we're left with the following:

//____________________________________________
//
currentDistance = (currentFrame/totalFrames) * totalDistance;
//____________________________________________

Let's apply this knowledge to another tween 50 frames in length which moves our ball from an _x of 0 to an _x of 550:

//____________________________________________
//
var totalFrames = 50;     // How many frames our tween will take.
var currentFrame = 0;     // How many frames have passed so far.
var totalDistance = 550;  // The total distance our ball will travel.
Ball_mc.onEnterFrame = function(){
        //
        // Note that we have entered another frame
        // by adding one to our currentFrame variable.
        currentFrame++;
        //
        // Use our formula to determine how far we need to move the ball.
        var currentDistance = (currentFrame/totalFrames) * totalDistance;
        //
        // Move the ball.
        this._x = currentDistance;
        //
        // If 50 frames have passed, stop moving the ball.
        if (currentFrame > totalFrames) delete this.onEnterFrame;
}
//____________________________________________





Everything works fine but what if we want to move our ball from an _x of 50 to an _x of 500? How do we make a tween that doesn't start at zero? Take a look at the following code:

//____________________________________________
//
var totalFrames = 50;              // How many frames our tween will take.
var currentFrame = 0;              // How many frames have passed so far.
var <strong>startX = 50;</strong>                   // The starting position of our ball.
var <strong>endX = 500;</strong>                    // The ending position of our ball.
var <strong>changeInX = endX - startX;</strong>     // The distance our ball will travel (450 pixels).
Ball_mc.onEnterFrame = function(){
        //
        // Note that we have entered another frame
        // by adding one to our currentFrame variable.
        currentFrame++;
        //
        // Use our formula to determine how far we need to move the ball.
        var currentDistance = <strong>startX</strong> +(currentFrame/totalFrames) * <strong>changeInX</strong>;
        //
        // Move the ball.
        this._x = currentDistance;
        //
        // If 10 frames have passed, stop moving the ball.
        if (currentFrame>totalFrames) delete this.onEnterFrame;
}
//____________________________________________





Essentially all we did was create a tween from 0 to 450 and then add 50 to every value which had the effect of shifting the tween 50 pixels to the right.

When looking at the following line of code...

//____________________________________________
//
//
//  This is THE quintessential linear tweening code.
//  Learn it. Live it. Love it.
//
currentDistance = startX +(currentFrame/totalFrames) * changeInX;
//____________________________________________

...it's important to understand two key concepts:

1) The only value which really changes in our tween is the ratio (currentFrame/totalFrames), the other values (startX and changeInX) are constant. It's this change in value which moves our ball across the screen. After all, if (currentFrame/totalFrames) remained a constant number our ball would simply remain stationary.

2) The value of (currentFrame/totalFrames) will always be a number between 0 and 1. When it's 0 the ball will be at its initial position, when its .5 the ball will be half way to its destination and when its 1 the ball will be at its final position. The reason this is so important is that it's going to allow us to do some pretty cool stuff with "easing" which is our next big step in tweening education.

Of course it should almost go without saying that once you know the formula you can plug all your numbers directly into the code if you'd prefer. This can drastically decrease the amount of typing you'll need to do. For example, our previous code sample could be written like this:

//____________________________________________
//
var currentFrame = 0;
Ball_mc.onEnterFrame = function(){
        this._x = 50 + (currentFrame/10) * 450;
        if (++currentFrame > 10) delete this.onEnterFrame;
}
//____________________________________________

*Footnote
Functions which return values between 0 and 1 are "convenient" because the values they return can easily be scaled and shifted to represent a wider range of numbers. Consider the "Math.random" function which returns random values between 0 and 1. Once you have the random number between 0 and 1 it's easy to multiply it, add to it, and obtain a different range of numbers. For example a random number between 0 and 1 can be scaled and shifted to become a random number from 8 to 12 like so:

//____________________________________________
//
var random8to12 = Math.random() * 4 + 8;
//____________________________________________

In the above example values from 8 to 12 are obtained by multiplying our random number (which is between 0 and 1) by 4 and adding 8. We multiply by 4 because the range of numbers between 8 and 12 is 4 (12-8=4) it therefore follows that any number between 0 and 1 multiplied by 4 will "scale" up to a number between 0 and 4. We then add 8 to our number (which is now between 0 and 4) to ensure we get numbers between 8 and 12 because 8+0=8 and 8+4=12.



The next portion of this tutorial deals with the concept of "Easing" a tween.