Vixiom Axioms

January 12, 2007

Scripting animation in ActionScript

Filed under: ActionScript, Flash Alastair @ 10:45 am

Scripting animation has many benfits including improved performance, more control, and most importantly it saves time. There’s a great animation library called Fuse which let’s you animate everything from a MovieClip’s position to the anmount of blur. While a complete animation library it’s also pretty complicated with pages and pages of documentation and I - being a lazy programmer - like to keep things simple so I wrote my own very basic Tweener class.

It let’s you animate any property (or multiple properties) that isn’t controlled by a filter. It also has simple ‘onStart’ and ‘onComplete’ callbacks for letting you know when it starts and finishes animating. Here’s a FLA with an example, and the code…

In your FLA file (the only confusing bit is that I shortened the easeStrengths and easeTypes ‘r’ = ‘Regular’ and ‘eio’ = ‘easeInOut’ see the class for the details)…

import com.vixiom.animation.Tweener;

tweener = new Tweener();
// event listeners
tweener.addEventListener(“onStart”, this.onStart);
tweener.addEventListener(“onComplete”, this.onComplete);
// this tween is relative to it’s start position 
// addTween (movieClip, property, easeStrength, easeType, beginValue, finsihValue, seconds, delay, relative?)
tweener.addTween(circle, “_x”, “r”, “eio”, circle._x, 400, 2, 0, true);
// these tweens use fixed values
tweener.addTween(circle2, “_x”, “r”, “eio”, 50, 450, 1, 2);
tweener.addTween(circle2, “_alpha”, “r”, “eio”, 0, 100, 1, 2);
// start the animation
tweener.start();

// the onStart method
function onStart ()
{
    trace(“// on start!”);
}

// the onComplete method
function onComplete ()
{
    trace(“// on complete!”);
}

The Tweener class…

/**
   @class Tweener
   @author Alastair Dawson
   @copyright 2007 Vixiom Communcations, LLC
*/

import mx.transitions.*;
import mx.transitions.easing.*;
import mx.utils.Delegate;

class com.vixiom.animation.Tweener
{
    private var tweens:Array;
    private var tweenerFinished:Function;
    private var runTime:Number;

    private var delayID:Number;
    private var callBackID:Number;

    private var i = 0;

    // event dispatching
    function dispatchEvent() {};
    function addEventListener() {};
    function removeEventListener() {};

    /**
    * Constructor
    */
    public function Tweener ()
    {
        // initialize as a broadcaster
        mx.events.EventDispatcher.initialize(this);

        // tweens array
        tweens = [];

        // runtime
        runTime = 0;
    }

    /**
    * Add Tween
    *
    *   @param      mc      movieClip
    *   @param      p       property
    *   @param      es      easeStrength
    *   @param      et      easeType
    *   @param      b       begin value
    *   @param      f       finish value
    *   @param      s       seconds (duration)
    *   @param      d       delay (duration in seconds)
    *   @param      r       relative (move relative to current position, false by default)
    *
    */

    // add properties
    public function addTween (mc:MovieClip, p:String, es:String, et:String, b:Number, f:Number, s:Number, d:Number, r:Boolean)
    {
        tweens[i] = new Tween();

        tweens[i].obj = mc;
        tweens[i].prop = p;

        if (r == true) {
            tweens[i].begin = tweens[i].obj[tweens[i].prop] + b;
            tweens[i].finish = tweens[i].obj[tweens[i].prop] + f;
        } else {
            tweens[i].begin = b;
            tweens[i].finish = f;
        }

        tweens[i].duration = s;
        tweens[i].useSeconds = true;
        tweens[i].func = convertEase(es,et);

        // set delay
        tweens[i].delay = d;

        // set this tween’s runTime
        tweens[i].runTime = s + d;

        // increment
        i++;
    }

    // start
    public function start ()
    {
        for (var j = 0; j < i; j++)
        {
            // does it have a delay if so set interval
            if (tweens[j].delay != undefined && tweens[j].delay != 0) {
                tweens[j].delayID = setInterval (this, “startTween”, (tweens[j].delay * 1000), tweens[j]);
            } else {
                startTween(tweens[j])
            }

            // check if it’s the longest running tween
            if (tweens[j].runTime > runTime) {
                runTime = tweens[j].runTime;
            }
        }

        // onStart
        var eventObj:Object={target:this,type:“onStart”}
        dispatchEvent(eventObj);

        // onComplete
        callBackID = setInterval (this, “onComplete”, (runTime * 1000));
    }

    // startTween
    private function startTween(t:Object)
    {
        t.start();
        clearInterval(t.delayID);
    }

    // stop
    private function stop()
    {
        for (var j = 0; j < i; j++) {
            tweens[j].stop();
        }
    }

    // resume
    private function resume()
    {
        for (var j = 0; j < i; j++) {
            tweens[j].resume();
        }
    }

    // rewind
    private function rewind()
    {
        for (var j = 0; j < i; j++) {
            tweens[j].rewind();
        }
    }

    // fforward
    private function fforward()
    {
        for (var j = 0; j < i; j++) {
            tweens[j].fforward();
        }
    }

    // callBack
    private function onComplete()
    {
        // broadcast message
        var eventObj:Object={target:this,type:“onComplete”}
        dispatchEvent(eventObj);

        // clear interval
        clearInterval(callBackID);
    }

    // convert easeStrenght
    private function convertEase (es:String, et:String):Object
    {
        var easeStrength:String = es;
        var easeType:String = es;
        var esObj:Object;

        switch (es) {
            case “b”:
                esObj = Bounce;
                break;
            case “k”:
                esObj = Back;
                break;
            case “e”:
                esObj = Elastic;
                break;
            case “n”:
                esObj = None;
                break;
            case “r”:
                esObj = Regular;
                break;
            case “s”:
                esObj = Strong;
                break;
            default:
                esObj = None;
        }

        switch (et) {
            case “e”:
                et = “easeNone”;
                break;
            case “ei”:
                et = “easeIn”;
                break;
            case “eo”:
                et = “easeOut”;
                break;
            case “eio”:
                et = “easeInOut”;
                break;
            default:
                et = “easeNone”;
        }

        return esObj[et];

    }

    /**
    * Event dispatcher
    *
    *   @param      d       data
    *   @param      et      eventType
    *
    */
    function dispatch(et)
    {
        // broadcast message
        var eventObj:Object={target:this,type:et}
        dispatchEvent(eventObj);
    }

}

That’s it! no too heavy man :P

*UPDATE*

If you’re using this in a class it’s best to use Delegate to access the onComplete or onStart methods so you don’t lose scope

tweener.addEventListener(“onComplete”, Delegate.create (this, this.onComplete));
Digg! submit Scripting animation in ActionScript to stumbleupon.com submit Scripting animation in ActionScript to del.icio.us submit Scripting animation in ActionScript to reddit.com Like this post? subscribe to the feed.

2 Comments »

  1. great stuff - been working on a similar thing - the relative option is a favourite

    Comment by John — March 2, 2007 @ 3:58 pm

  2. Thank you very much for this great idea! We will try it in the next few days…

    Comment by professionelle Suchmaschinenoptimierung — July 7, 2007 @ 4:03 am

RSS feed for comments on this post. TrackBack URL

Leave a comment

*
To prove you're a person (not a spam script), type the security word shown in the picture.
Anti-Spam Image

Powered by WordPress