- Home
- Tutorials
- Flash
- Intermediate
- tweening

Page 4 of 4
Sean O'Shell
This user is yet to take control of their account and provide a biography. If you are the author of this article, please contact us via [email:support@actionscript.org].
View all articles by Sean O'ShellDIFFERENT WAYS TO APPLY EASING FUNCTIONS
Now that we have the core easing functions in their final state...
//____________________________________________
//
Math.easeIn = function (r, p, f){
if (p == undefined) p = 2;
if (f == undefined) f = Math.pow;
return f (r, p);
}
Math.easeOut = function(r, p, f){
return 1-Math.easeIn(1-r, p, f);
}
Math.easeInOut = function (r, p, f){
if(r<.5)return Math.easeIn(2*r, p, f)/2;
return Math.easeOut(2*(r-.5), p, f)/2+.5;
}
Math.ezExpo = function (r, p) {
if(r==0 || r==1) return r;
if(p<2)p = 2;
return Math.pow(p, 10*(r-1));
}
Math.ezCirc = function (r, p) {
r = -(Math.sqrt(1-r*r)-1);
if(p>1) return Math.easeIn(r, --p, Math.ezCirc);
return r;
}
Math.ezSine = function (r, p){
r = 1-Math.cos(r*Math.PI/2);
if(p>1) return Math.easeIn(r, --p, Math.ezSine);
return r;
}
//____________________________________________
...I'd like to take a little time to elaborate on a few different ways to apply them. All the following code samples will assume you have either pasted or included the above easing functions into your Flash file. With that said, let's move on to our first example.
So far, for the sake of simplicity, all our previous examples have dealt with tweening the "_x" property of a clip yet it shouldn't be too hard to imagine using the easing functions to adjust any other property of a movieclip. For example we can fade-in a clip's alpha like this:
//____________________________________________
//
var currentFrame = 0;
RedBall_mc.onEnterFrame = function () {
currentFrame++;
this._alpha = Math.easeIn(currentFrame/50)*100;
if (currentFrame>50) delete this.onEnterFrame;
}
//____________________________________________
You don't necessarily need to ease a clip's property either. For example, you might want to ease the scoring of a game. Imagine you have a game with a bunch of bad guys and each time you press the mouse a bad guy dies. Killing one bad guy is super easy but killing all 20 is very difficult therefore you don't just want to give out a set amount of points for every guy killed. Instead, you can ease the amount of points for each guy killed with code similar to the following:
//____________________________________________
//
var score = 0;
var deadGuys = 0;
var totalBadGuys = 20;
var pointsForLevel = 5000;
onMouseDown = function(){
if (deadGuys < totalBadGuys){
deadGuys++;
score = Math.easeIn(deadGuys/totalBadGuys)*pointsForLevel ;
trace(Math.floor(score));
}
}
//____________________________________________
All our previous examples involved the use of a variable ("currentFrame") to track the passage of time using frames as a unit of measure but you can use other units of time if you wish. For example you can use the values returned by the "GetTimer" function to create a delayed tween which will start and stop at a set time regardless of the SWF's frame rate like this:
//____________________________________________
//
var startTime = 3000; // What time the tween will start (3 seconds into the movie)
var endTime = 5000; // What time the tween will end (5 seconds into the movie)
var timeDifference = endTime - startTime; // How much time the tween will take to complete once started (2 seconds)
var startX = 50; // Where the ball will start
var endX = 500; // Where the ball will end
var xDifference = endX - startX; // How far the ball will travel to reach it's final position
//
RedBall_mc.onEnterFrame = function () {
var nowTime = getTimer(); // Determine the current time
if (nowTime > startTime) { // If it's past the time to start the tween
if (nowTime < endTime) { // If the tween is not complete
// Determine the ratio of completion
var ratio = (nowTime-startTime) / timeDifference;
// Do the tween
this._x = startX + Math.easeInOut( ratio ) * xDifference;
}else{ // If it is time to end the tween
this._x = endX; // Put the ball at its final position
delete this.onEnterFrame; // Kill the enterFrame event
}
}
}
//____________________________________________
The last topic I'd like to discuss is that of "Asymmetrical Easing". So far whenever we've eased our ball using the "Math.easeInOut" function it has moved in a symmetrical fashion. That is to say the ball takes the same amount of time to ease out as it does to ease in, in effect one side of the tween is a mirror image of the other side. But this isn't always the desired result. For example let's say you'd like to tween a car across the stage, and let's say this car has poor acceleration but excellent brakes. To create a convincing tween the car should start off slowly but come to a stop rather abruptly by comparison. This means we need heavy easing in and light easing out. We can achieve this effect with code similar to the following:
//____________________________________________
//
var startX = 50;
var endX = 500;
var currentFrame = 0;
var totalFrames = 50;
RedBall_mc.onEnterFrame = function () {
currentFrame++;
var initialRatio = currentFrame / totalFrames;
var ratio2 = Math.easeIn(initialRatio, 4);
var ratio3 = Math.easeOut(ratio2, 2);
this._x = startX + ratio3 * (endX-startX);
if(currentFrame >= totalFrames) delete this.onEnterFrame;
}
//____________________________________________
The concept of easing a value then easing the returned value again (as shown above) can produce such a wide variety of results I thought I'd use our last code sample to illustrate some of the possibilities.
//____________________________________________
//
// Variables
var totalFrames = 100;
var startX = 70;
var endX = 535;
var changeX = endX-startX;
//
// Create Text Fields
for(var i=0; i<8; i++){
createTextField("TF"+i, i+1, 4, 8+i*50, 65, 50);
this["TF"+i].multiline = true;
}
TF0.text = "InOutSine1";
TF1.text = "InSine1\rOutSine1";
TF2.text = "OutSine1\rInSine1";
TF3.text = "InSine2\rOutSine1";
TF4.text = "InSine1\rOutSine2";
TF5.text = "InSine1\rOutExpo2";
TF6.text = "InExpo2\rOutSine3";
TF7.text = "InCube3\rOutQuad2";
//
// Create Diamonds
for(var i=0; i<8; i++){
var dot = createEmptyMovieClip("Dot"+i, i+10);
with(dot){
beginFill(0, 50);
moveTo(0, -20);
lineTo(5, 0);
lineTo(0, 20);
lineTo(-5, 0);
endFill();
_x = startX;
_y = 25+i*50;
}
}
//
// Duplicate And Move All Diamonds
var Depth = 20;
onMouseDown = function(){
for(var i=20; i<20+depth; i++){
this["Dot"+i].removeMovieClip();
}
currentFrame = 0;
depth = 20;
onEnterFrame = function(){
var ratio = currentFrame/totalFrames;
// 1) InOutSine1
var dot = Dot0.duplicatemovieclip("Dot"+depth, depth++);
dot._x = startX + Math.easeInOut(ratio, 1, Math.ezSine)*changeX;
// 2) InSine1 OutSine1
var dot = Dot1.duplicatemovieclip("Dot"+depth, depth++);
var r = Math.easeIn(ratio, 1, Math.ezSine);
dot._x = startX + Math.easeOut(r, 1, Math.ezSine)*changeX;
// 3) OutSine1 InSine1
var dot = Dot2.duplicatemovieclip("Dot"+depth, depth++);
var r = Math.easeOut(ratio, 1, Math.ezSine);
dot._x = startX + Math.easeIn(r, 1, Math.ezSine)*changeX;
// 4) InSine2 OutSine1
var dot = Dot3.duplicatemovieclip("Dot"+depth, depth++);
var r = Math.easeIn(ratio, 2, Math.ezSine);
dot._x = startX + Math.easeOut(r, 1, Math.ezSine)*changeX;
// 5) InSine1 OutSine2
var dot = Dot4.duplicatemovieclip("Dot"+depth, depth++);
var r = Math.easeIn(ratio, 1, Math.ezSine);
dot._x = startX + Math.easeOut(r, 2, Math.ezSine)*changeX;
// 6) InSine1 OutExpo2
var dot = Dot5.duplicatemovieclip("Dot"+depth, depth++);
var r = Math.easeIn(ratio, 1, Math.ezSine);
dot._x = startX + Math.easeOut(r, 2, Math.ezExpo)*changeX;
// 7) InExpo2 OutSine3
var dot = Dot6.duplicatemovieclip("Dot"+depth, depth++);
var r = Math.easeIn(ratio, 2, Math.ezExpo);
dot._x = startX + Math.easeOut(r, 3, Math.ezSine)*changeX;
// 8) InCube3 OutQuad2
var dot = Dot7.duplicatemovieclip("Dot"+depth, depth++);
var r = Math.easeIn(ratio, 3);
dot._x = startX + Math.easeOut(r)*changeX;
if(currentFrame == totalFrames)delete onEnterFrame;
currentFrame++;
}
}
onMouseDown();
//____________________________________________
That's it. This tutorial has finally come to an end. I hope you find the easing functions to be as useful as I have and more importantly, I hope you've gained a good deal of insight regarding the concepts of tweening and easing.
One final thing before I go, I don't have Flash MX2004 yet, but for those of you who do, you might find the following class definitions useful:
//____________________________________________
//
class com.pixelwit.ease{
static function easeIn (r:Number, p:Number, f:function):Number{
if(p == undefined) p = 2;
if(f == undefined)f = Math.pow;
return f(r, p);
}
static function easeOut (r:Number, p:Number, f:function):Number{
return 1-easeIn(1-r, p, f);
}
static function easeInOut (r:Number, p:Number, f:function):Number{
if(r<.5)return easeIn(r*2, p, f)/2;
return .5+easeOut((r-.5)*2, p, f)/2;
}
static function ezExpo (r:Number, p:Number):Number{
if(r==0 || r==1) return r;
if(p<2)p = 2;
return Math.pow(p, 10*(r-1));
}
static function ezCirc (r:Number, p:Number):Number{
r = -(Math.sqrt(1-r*r)-1);
if(p>1) return easeIn(r, --p, ezCirc);
return r;
}
static function ezSine (r:Number, p:Number):Number{
r = 1-Math.cos(r*Math.PI/2);
if(p>1) return easeIn(r, --p, ezSine);
return r;
}
}
//____________________________________________
For more information or for general discussion of this topic you can check out this thread.
Cheers,
-Sean O'Shell (a.k.a. PiXELWiT)http://www.pixelwit.com
Spread The Word
Article Series
-
tweening

