Home Tutorials Forums Articles Blogs Movies Library Employment Press Buy templates

Go Back   ActionScript.org Forums > ActionScript Forums Group > ActionScript 1.0 (and below)

Reply
 
Thread Tools Rating: Thread Rating: 2 votes, 5.00 average. Display Modes
Old 03-05-2004, 10:59 AM   #1
pixelwit
village halfwit
 
pixelwit's Avatar
 
Join Date: Jul 2001
Location: USA, PA
Posts: 3,196
Default RATIO-nal Easing

I've been tinkering with Robert Penner's easing equations and here's what I came up with so far...


This:
PHP Code:
Math.easeIn = function(rexpo){
    return 
Math.pow(rexpo);
};
Math.easeOut = function(rexpo){
    return 
1-Math.easeIn(1-rexpo);
};
Math.easeInOut = function(rexpo){
    if(
r<.5)return Math.easeIn(r*2expo)/2;
     return 
.5+Math.easeOut((r-.5)*2expo)/2;
}; 
Replaces this:
PHP Code:
Math.linearTween = function (tbcd) {
    return 
c*t/b;
};
Math.easeInQuad = function (tbcd) {
    return 
c*(t/=d)*b;
};
Math.easeOutQuad = function (tbcd) {
    return -
*(t/=d)*(t-2) + b;
};
Math.easeInOutQuad = function (tbcd) {
    if ((
t/=d/2) < 1) return c/2*t*b;
    return -
c/* ((--t)*(t-2) - 1) + b;
};
Math.easeInCubic = function (tbcd) {
    return 
c*(t/=d)*t*b;
};
Math.easeOutCubic = function (tbcd) {
    return 
c*((t=t/d-1)*t*1) + b;
};
Math.easeInOutCubic = function (tbcd) {
    if ((
t/=d/2) < 1) return c/2*t*t*b;
    return 
c/2*((t-=2)*t*2) + b;
};
Math.easeInQuart = function (tbcd) {
    return 
c*(t/=d)*t*t*b;
};
Math.easeOutQuart = function (tbcd) {
    return -
* ((t=t/d-1)*t*t*1) + b;
};
Math.easeInOutQuart = function (tbcd) {
    if ((
t/=d/2) < 1) return c/2*t*t*t*b;
    return -
c/* ((t-=2)*t*t*2) + b;
};
Math.easeInQuint = function (tbcd) {
    return 
c*(t/=d)*t*t*t*b;
};
Math.easeOutQuint = function (tbcd) {
    return 
c*((t=t/d-1)*t*t*t*1) + b;
};
Math.easeInOutQuint = function (tbcd) {
    if ((
t/=d/2) < 1) return c/2*t*t*t*t*b;
    return 
c/2*((t-=2)*t*t*t*2) + b;
}; 
Using Robert Penner's Easing Equations

Robert Penner's equations accept 4 arguments:
t = time
b = beginning value
c = change in value
d = duration

Let's suppose we'd like to tween a clip across the stage. Our clip currently has an _x of 50 and we want it to move across the stage and stop at an _x of 500 within the time span of 10 seconds.

From this scenario we can easily produce the following variables:
startX = 50;
endX = 500;
duration = 10;

To make R.Penner's equations work we need to supply our variables like so:
t = ?
b = 50; // startX;
c = 450; // endX-startX;
d = 10; // duration;

As you can see "t" hasn't been determined yet. That's because "t" is dependant upon the amount of time to have passed since the tween was started. The "t" argument represents a number from 0 to "duration" (10) which will always be changing and essentially driving the clip across the stage to its goal position.

Okay, so our clip is supposed to take 10 seconds to move across the stage, where will the clip be 3 seconds after we start a linear tween?

The linear easing function looks like this:

Math.linear = function(t, b, c, d){
return b+t/d*c;
}

The linear easing function is called like this:

Clip._x = Math.linear(3, 50, 450, 10);

Which would translate to:

Clip._x = 50+3/10*450

Which would make Clip._x equal 185.

Now that you (hopefully) have a grasp of how to use R.Penner's easing equations, let's compare using his to using mine.



Comparing Easing Equations


PHP Code:
// R. Penner equation
Math.easeInQuad = function (tbcd) {
    return 
c*(t/=d)*b;
};
// PiXELWiT equation
Math.easeIn = function(rexpo){
    return 
this.pow(rexpo);
};
//
//
var startX 50;
var 
endX 500;
var 
duration 10;
var 
elapsedTime 3;
//
// Penner Quadratic Easing
clip._x Math.easeInQuad(elapsedTimestartXendX-startXduration);
// PiXELWiT Quadratic Easing
clip._x startX+Math.easeIn(elapsedTime/duration2)*(endX-startX);
//                                                 ^
// The "2" argument sets the easing type to "quadratic" 
As you can see my technique doesn't require any more input or effort than the Penner technique, in fact if you're not familiar with the Penner approach you might find my way a little easier. Consider the following. When tweening a clip the only variable that changes is the "ratio" of completion, that is to say, the amount of your tween which has already taken place compared to the amount of your tween which is still remaining. In the above examples the tween took place during the third out of ten seconds. That's three tenths or 3/10 or .3 or 30% and that relationship can be described as a ~RATIO~. The ~RATIO~ of completion is the only thing that really changes during a tween, all other variables (startX, endX, duration) stay the same. For tweening purposes, our ratio will be a number from 0 to 1. A ratio of 0 would mean you're still at your initial value (50 in the previous example), a ratio of 1 would mean you're at your final destination (500 in the previous example) and a ratio of .5 would mean you're at a point half way between your start and end values (275 in the previous example).

When you're "EASING" (notice I didn't say tweening but said "EASING")... When you're easing between two values, you feed the easing equation a series of evenly spaced numbers and it returns a series of warped (unevenly spaced) numbers. Keeping your input values between 0 and 1 assures your output will always be a number between 0 and 1. This increases standardization and furthers abstraction since the function is less intimately entwined with its application (startX, endX, duration are no longer integral to the easing equation). Accepting and returning numbers within the same range has some other benefits which we'll discuss later.
PHP Code:
//
// copy and paste the following code into a new FLA document and test
//
// Penner tween
Math.linear = function(tbcd){
    return 
b+t/d*c;
}
// PiXELWiT tween
Math.easeIn = function(rexpo){
    return 
this.pow(rexpo);
};
// How to make dots
function makeDot(namedepthcolorxy){
    var 
dot this.createEmptyMovieClip(namedepth);
    
with(dot){
        
lineStyle(20color);
        
lineTo(.50);
        
_y y;
     }
    return 
dot;
}
// Make some dots to tween
red makeDot("Dot1"100xFF00005050);
orange makeDot("Dot2"200xFF8000200150);
blue makeDot("Dot3"300x0000FF50250);
green makeDot("Dot4"400x00FF00200350);
// Tween the dots
onEnterFrame = function(){
    
i++;
    if(
i>=100)delete onEnterFrame;
    
// Penner way
    
red._x Math.linear(i50450100);
    
orange._x Math.linear(i200300100);
    
// PiXELWiT way
    // To see actual "easing" simply change the 1 in the line below to a 2 
    
var ez Math.easeIn(i/1001);
    
blue._x 50+ez*450;
    
green._x 200+ez*300;

Abstraction makes it easier to apply the same easing to different clips. In the above code the "easeIn" function is only called once but is applied to both the blue and green clips.





Code:
                         E Q U I V A L E N C E

                 __Penner______        ______PiXELWiT__

   Math.linearTween(3, 0, 1, 10)   =      Math.easeIn(.3, 1)    >Linear = 1

    Math.easeInQuad(3, 0, 1, 10)   =      Math.easeIn(.3, 2)    \
   Math.easeOutQuad(3, 0, 1, 10)   =     Math.easeOut(.3, 2)     Quadratic = 2
 Math.easeInOutQuad(3, 0, 1, 10)   =   Math.easeInOut(.3, 2)    /

   Math.easeInCubic(3, 0, 1, 10)   =      Math.easeIn(.3, 3)    \
  Math.easeOutCubic(3, 0, 1, 10)   =     Math.easeOut(.3, 3)     Cubic = 3 
Math.easeInOutCubic(3, 0, 1, 10)   =   Math.easeInOut(.3, 3)    / 

   Math.easeInQuart(3, 0, 1, 10)   =      Math.easeIn(.3, 4)    \
  Math.easeOutQuart(3, 0, 1, 10)   =     Math.easeOut(.3, 4)     Quartic = 4
Math.easeInOutQuart(3, 0, 1, 10)   =   Math.easeInOut(.3, 4)    /

   Math.easeInQuint(3, 0, 1, 10)   =      Math.easeIn(.3, 5)    \
  Math.easeOutQuint(3, 0, 1, 10)   =     Math.easeOut(.3, 5)     Quintic = 5
Math.easeInOutQuint(3, 0, 1, 10)   =   Math.easeInOut(.3, 5)    /

      *function not yet written*   =      Math.easeIn(.3, 6)    >Sentic? and beyond...
Standardization helps reduce 13 functions to 3 and allows those 3 functions to do much more.



Earlier I mentioned that there are benefits to functions which accept and return numbers within the same range (i.e. a ratio from 0 to 1). If you look at the following code you'll notice I've modified one of my standard easing equation to use recursion as a way to "amplify" the easing results.

PHP Code:
// standard version
function easeOutSin(ratio){
    return 
Math.sin(ratio*Math.PI/2);
};
// Amplified version
function easeOutSin(ratioamplifier){
    
ratio Math.sin(ratio*Math.PI/2);
    return 
amplifier>easeOutSin(ratio, --amplifier) : ratio;
};
for(var 
i=0i<1i+=.1){
    
trace(easeOutSin(i1));
    
trace(easeOutSin(i2));
    
trace("");


If you're on your toes you might notice that the "easeOutSin" function's arguments are similar to the previously discussed (easeIn, easeOut, easeInOut) function's arguments in that they all accept a ratio followed by a whole number and increasing that whole number significantly increases the easing effect. Pretty handy huh? Yay for standards.

While this doesn't cover every one of Robert Penner's easing equations it does cover some of the most popular ones. If you have any further comments please feel free to add them.

-PiXELWiT
http://www.pixelwit.com
__________________
There are no answers, only choices.

Last edited by pixelwit; 03-07-2004 at 09:43 PM..
pixelwit is offline   Reply With Quote
Old 03-05-2004, 11:12 AM   #2
Timmee_3Styler
Canadian Flasher
 
Join Date: May 2002
Location: T dot O dot
Posts: 1,651
Default

GREAT JOB
Timmee_3Styler is offline   Reply With Quote
Old 03-05-2004, 04:30 PM   #3
thaumaturgy
Macromedia Mercenary
 
thaumaturgy's Avatar
 
Join Date: Feb 2004
Location: Rose Bowl Country
Posts: 300
Send a message via Yahoo to thaumaturgy
Default



Color me impressed. Good stuff, PiXeLWiT.
thaumaturgy is offline   Reply With Quote
Old 03-05-2004, 05:04 PM   #4
oldnewbie
Banned by AS.org Staff
 
Join Date: Mar 2002
Posts: 10,534
Default

Like he said!

Couldn't resist!

Now if Pixelwit could only address all the latest threads on his plageFlip bit, guess everybody would have a happy weekend!
oldnewbie is offline   Reply With Quote
Old 03-05-2004, 05:12 PM   #5
thaumaturgy
Macromedia Mercenary
 
thaumaturgy's Avatar
 
Join Date: Feb 2004
Location: Rose Bowl Country
Posts: 300
Send a message via Yahoo to thaumaturgy
Default

Quote:
Originally posted by oldnewbie
Like he said!

Couldn't resist!

Now if Pixelwit could only address all the latest threads on his plageFlip bit, guess everybody would have a happy weekend! [/B]
thaumaturgy is offline   Reply With Quote
Old 03-06-2004, 01:25 AM   #6
tg
done
 
Join Date: Jun 2001
Location: portland, or
Posts: 8,048
Default

*picks up blo-horn*
STEP AWAY FROM THE KEYBOARD AND COME OUTSIDE WITH YOUR HANDS ABOVE YOUR HEAD.

pixelwit, obviously you've been staring into your monitor for way to long... get out and get some fresh air.


btw. nice.
__________________
tg
---
what the hell was i thinking?
tg is offline   Reply With Quote
Old 03-06-2004, 03:51 AM   #7
boyzdynasty
Senior Member
 
boyzdynasty's Avatar
 
Join Date: Aug 2002
Location: Philly
Posts: 2,580
Default

wow. How long did it take you to figure that out?

very impressive.
__________________
I need a new signature!
boyzdynasty is offline   Reply With Quote
Old 03-07-2004, 06:19 PM   #8
pixelwit
village halfwit
 
pixelwit's Avatar
 
Join Date: Jul 2001
Location: USA, PA
Posts: 3,196
Default

I've updated the code a little bit to facilitate the addition of a wider variety of easing equations. Exponential, sinusoidal and circular are included as examples.

PHP Code:
Math.easeIn = function(rpf){
    if(
== undefined2;
    if(
== undefined)Math.pow;
    return 
f(rp);
};
Math.easeOut = function(rpf){
    return 
1-Math.easeIn(1-rpf);
};
Math.easeInOut = function(rpf){
    if(
r<.5)return Math.easeIn(r*2pf)/2;
    return 
.5+Math.easeOut((r-.5)*2pf)/2;
};
///////////////////////////////////
Math.ezExpo = function (rp) {
    if(
r==|| r==1) return r;
    if(
p<2)2;
    return 
Math.pow(p10*(r-1));
};
Math.ezCirc = function (rp) {
    
= -(Math.sqrt(1-r*r)-1);
    return 
p>Math.easeIn(r, --pMath.ezCirc) : r;
};
Math.ezSine = function (rp){
    
1-Math.cos(r*Math.PI/2);
    return 
p>Math.easeIn(r, --pMath.ezSine) : r;
};
//
//
// Usage
//////////////////////////////////////////////////////////////////////////
function test(){
    for(var 
i=0i<11i++){
        
trace("_______"+i/10+"_________________");
        
trace("Quad = "+Math.easeInOut(i/10));
        
trace("Cubi = "+Math.easeInOut(i/103));
        
trace("Sin1 = "+Math.easeInOut(i/101Math.ezSine));
        
trace("Sin2 = "+Math.easeInOut(i/102Math.ezSine));
        
trace("Exp2 = "+Math.easeInOut(i/102Math.ezExpo));
        
trace("Exp3 = "+Math.easeInOut(i/103Math.ezExpo));
        
trace("Cir1 = "+Math.easeInOut(i/101Math.ezCirc));
        
trace("Cir2 = "+Math.easeInOut(i/102Math.ezCirc));
    }
}
test(); 
The only required argument is "r" which is the completion Ratio.

The second argument "p" should be a whole number greater than 0. Numbers greater than 1 increase the easing effect.

The third argument "f" should be a reference to an easing Function.

-PiXELWiT
http://www.pixelwit.com
__________________
There are no answers, only choices.
pixelwit is offline   Reply With Quote
Old 03-07-2004, 06:30 PM   #9
thaumaturgy
Macromedia Mercenary
 
thaumaturgy's Avatar
 
Join Date: Feb 2004
Location: Rose Bowl Country
Posts: 300
Send a message via Yahoo to thaumaturgy
Default

Dope.
thaumaturgy is offline   Reply With Quote
Old 03-11-2004, 12:01 AM   #10
pixelwit
village halfwit
 
pixelwit's Avatar
 
Join Date: Jul 2001
Location: USA, PA
Posts: 3,196
Default

I discovered you can ease in and out using 2 different types of easing techniques at the same time. Typical easing in and out produces a "symmetrical" pattern, equally slow toward the ends and equally fast toward the middle. However this new approach lets you do a slow ease-in with a fast ease-out and the other way around. That might not be real easy to visualize so I provided some code for clarification. Just copy and paste it into a new file and run it to see what's going on.
PHP Code:
//
// Easing Functions
Math.easeIn = function(rpf){
    if(
== undefined2;
    if(
== undefined)Math.pow;
    return 
f(rp);
};
Math.easeOut = function(rpf){
    return 
1-Math.easeIn(1-rpf);
};
Math.easeInOut = function(rpf){
    if(
r<.5)return Math.easeIn(r*2pf)/2;
    return 
.5+Math.easeOut((r-.5)*2pf)/2;
};
//////////////
Math.ezExpo = function (rp) {
    if(
r==|| r==1) return r;
    if(
p<2)2;
    return 
Math.pow(p10*(r-1));
};
Math.ezCirc = function (rp) {
    
= -(Math.sqrt(1-r*r)-1);
    if(
p>1) return Math.easeIn(r, --pMath.ezCirc);
    return 
r;
};
Math.ezSine = function (rp){
    
1-Math.cos(r*Math.PI/2);
    if(
p>1) return Math.easeIn(r, --pMath.ezSine);
    return 
r;
};
/////////////////////////////////////////////////////
//
// Variables
var frames 100;
var 
startX 70;
var 
endX 535;
var 
changeX endX-startX;
//
// Create Text Fields
for(var i=0i<8i++){
    
createTextField("TF"+ii+148+i*506550);
    
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=0i<8i++){
    var 
dot createEmptyMovieClip("Dot"+ii+10);
    
with(dot){
        
beginFill(050);
        
moveTo(0, -20);
        
lineTo(50);
        
lineTo(020);
        
lineTo(-50);
        
endFill();
        
_x startX;
        
_y 25+i*50;
    }
}
//
// Duplicate And Move All Diamonds
var Depth 20;
onMouseDown = function(){
    for(var 
i=20i<20+depthi++){
        
this["Dot"+i].removeMovieClip();
    }
    
frame 0;
    
depth 20;
    
onEnterFrame = function(){
        var 
ratio frame/frames;
        
// 1 InOutSine1
        
var dot Dot0.duplicateMovieClip("Dot"+depthdepth++);
        
dot._x startX Math.easeInOut(ratio1Math.ezSine)*changeX;
        
// 2 InSine1  OutSine1
        
var dot Dot1.duplicateMovieClip("Dot"+depthdepth++);
        var 
Math.easeIn(ratio1Math.ezSine);
        
dot._x startX Math.easeOut(r1Math.ezSine)*changeX;
        
// 3 OutSine1  InSine1
        
var dot Dot2.duplicateMovieClip("Dot"+depthdepth++);
        var 
Math.easeOut(ratio1Math.ezSine);
        
dot._x startX Math.easeIn(r1Math.ezSine)*changeX;
        
// 4 InSine2   OutSine1
        
var dot Dot3.duplicateMovieClip("Dot"+depthdepth++);
        var 
Math.easeIn(ratio2Math.ezSine);
        
dot._x startX Math.easeOut(r1Math.ezSine)*changeX;
        
// 5 InSine1   OutSine2
        
var dot Dot4.duplicateMovieClip("Dot"+depthdepth++);
        var 
Math.easeIn(ratio1Math.ezSine);
        
dot._x startX Math.easeOut(r2Math.ezSine)*changeX;
        
// 6 InSine1   OutExpo2
        
var dot Dot5.duplicateMovieClip("Dot"+depthdepth++);
        var 
Math.easeIn(ratio1Math.ezSine);
        
dot._x startX Math.easeOut(r2Math.ezExpo)*changeX;
        
// 7 InExpo2  OutSine3
        
var dot Dot6.duplicateMovieClip("Dot"+depthdepth++);
        var 
Math.easeIn(ratio2Math.ezExpo);
        
dot._x startX Math.easeOut(r3Math.ezSine)*changeX;
        
// 8 InCube3    OutQuad2
        
var dot Dot7.duplicateMovieClip("Dot"+depthdepth++);
        var 
Math.easeIn(ratio3);
        
dot._x startX Math.easeOut(r)*changeX;
        if(
frame == frames)delete onEnterFrame;
        
frame++;
    }
}
onMouseDown(); 
-PiXELWiT
http://www.pixelwit.com
__________________
There are no answers, only choices.
pixelwit is offline   Reply With Quote
Reply


Thread Tools
Display Modes Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump


All times are GMT. The time now is 10:42 AM.


Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
Ad Management plugin by RedTyger
Copyright 2000-2009 ActionScript.org. All Rights Reserved.
Your use of this site is subject to our Privacy Policy and Terms of Use.
You Rated this Thread: