04th Sep 2008

Tween Sequencer

Many of the projects I have done have included creating some sort of repeating sequence of tweens. In my early projects I would trigger the next tween using the finished event for each tween. This sucked.

So recently I had some time and decided to take a crack at creating a tween sequencing class. Basic idea being that I add a sequence of tweens to a object and then just call a start function to trigger the sequence.

My first idea was to create a collection of tween objects and store references to them in an array. This led me to com up with this:

package com.vfd.animation.tweens{
import fl.transitions.TweenEvent;
import fl.transitions.Tween;
public class TweenSequencer {
private var _tweens:Array=new Array ;

private var index:Number=0;
public var loop:Boolean=false;
public function TweenSequencer() {
trace(“New Tween Sequencer”);
}
public function addTween(tween:Tween):void {
tween.stop();
tween.addEventListener(TweenEvent.MOTION_FINISH,nextTween);
this._tweens.push(tween);
}
public function removeTween(tween:Tween):void {
for (var i:Number=0; i < this._tweens.length; i++) {
if (this._tweens[i] == tween) {
this._tweens[i].removeEventListener(TweenEvent.MOTION_FINISH,nextTween);
this._tweens.splice(i,1);
break;
}
}
}
public function start():void {
this.startTween();
}
public function stop():void {
this.pause();
this.reset();
}
public function pause():void {
if (this._tweens[this.index]) {
this._tweens[this.index].stop();
}
}
private function nextTween(event:TweenEvent):void {
trace(“Index before ” + this.index);
trace(“Loop : ” + this.loop);
this.index++;
if (this.loop && this.index >= this._tweens.length) {
this.reset();
}
trace(“Index after ” + this.index);
this.startTween();

}
private function startTween() {
if (this._tweens[this.index]) {
this._tweens[this.index].play();
} else {
this.reset();
}
}
private function reset():void {
this.index=0;
}
}//end class
}//end package

The basic idea worked, but I ran into a couple of problems. I was testing this with a basic ball. I placed the ball in the top right corner of the screen. Every time I ran the thing it would play the tweens in the correct sequence, but the ball always started in the bottom right corner of the screen making the first run through the sequence incorrect. However, after the first run through it played as expected.

This took me a while to figure out, but as it turns out that when I created the tweens, even though I immediately stopped them, it was setting the properties of the ball to the start values of the second set of tweens that were applied to the x and y coordinates.

I tried all sorts of variations including writing my own tween class that overrode the starting behaviors of the standard tween class and I still ended up with the same results (though it is entirely possible that I missed something simple).

I did turn out that if I explicitly set the x and y coordinates of the clip after creating the tweens, it worked as expected. However, I was only testing with many tweens applied to one object. If I was applying tweens to multiple objects I would have to reset all of them and having to explicitly set the coordinates defeated the purposes of placing them on the stage where I wanted them to begin with. Additionally, I ran into this problem with tweens applied to x and y, but if there are other properties that behaved the same way, I would have to reset those as well. This class was intended to make this process sequencing tweens easier, not simply introduce a new set of headaches.

After some time I came up with the idea of using a single tween inside of the sequencer class. Instead of storing multiple tween instances, I would just store sequence of properties and values that I wanted to tween an update the single tween instance. this would keep the tweens property settings from conflicting with one another and throwing the sequence off. This lead to:

package com.vfd.animation.tweens{
import fl.transitions.TweenEvent;
import fl.transitions.Tween;
import flash.display.Sprite;
public class TweenSequencer {
private var _tweens:Array=new Array();
private var tween:Tween;
private var index:Number=0;
public var loop:Boolean=false;
private var placeHolderSprite:Sprite = new Sprite();
public function TweenSequencer() {
trace(“New Tween Sequencer”);
this.tween = new fl.transitions.Tween(this.placeHolderSprite,”alpha”,null,1,1,1,true);
this.tween.stop();
this.tween.addEventListener(TweenEvent.MOTION_FINISH,nextTween);
}
public function addTween(obj:Object, prop:String, easing:Function, begin:Number, end:Number, duration:Number, useSeconds:Boolean = false):void {
this._tweens.push(arguments);
}
public function start():void {
this.startTween();
}
public function stop():void {
this.tween.rewind();
this.reset();
}
public function pause():void {
this.tween.stop();
}
private function nextTween(event:TweenEvent):void {
this.index++;
if (this.loop && this.index >= this._tweens.length) {
this.reset();
}
this.startTween();

}
private function startTween() {
this.tween.stop();
if (this._tweens[this.index]) {
this.tween.obj = this._tweens[this.index][0];
this.tween.prop = this._tweens[this.index][1];
if (this._tweens[this.index][2] is Function) {
this.tween.func = this._tweens[this.index][2];
}
this.tween.begin = this._tweens[this.index][3];
this.tween.finish = this._tweens[this.index][4];
this.tween.duration = this._tweens[this.index][5];
this.tween.useSeconds = this._tweens[this.index][6];
this.tween.start();
} else {
this.reset();
}
}
private function reset():void {
this.index=0;
}
public function reverse() {
this._tweens.reverse();
}
}//end class
}//end package

So now this:

import com.vfd.animation.tweens.TweenSequencer;
var ts:TweenSequencer = new TweenSequencer();
ts.loop = true;
ts.addTween(ball, “alpha”, null, 0,1,2,true);
ts.addTween(ball, “x”, null, 130,300,2,true);
ts.addTween(ball, “y”, null, 130,300,2,true);
ts.addTween(ball, “x”, null, 300,130,2,true);
ts.addTween(ball, “y”, null, 300,130,2,true);
ts.addTween(ball, “alpha”, null, 1,0,2,true);
ts.start();

Produces this:

5 Responses to “Tween Sequencer”

  1. Websites tagged "tweens" on Postsaver Says:

    […] – Tween Squencer saved by SSBSmashBrosBrawl2008-09-22 – CTIA Wireless I.T. & Entertainment Roundup All Days […]

  2. Miranda Says:

    This was most helpful in my work today, thanks!

  3. Jeremy Wischusen Says:

    Glad you found it useful. Thanks for commenting.

  4. simon Says:

    What’s wrong with the sequence/parallel classes within flex?

  5. Jeremy Wischusen Says:

    Noting. But what if I want to do this in the Flash IDE? Far as I know, those are Flex only.