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
*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));
3 Comments
great stuff – been working on a similar thing – the relative option is a favourite
Thank you very much for this great idea! We will try it in the next few days…
thanks for the example.. but can we use to read image in specific directory?