home about | services artwork blog

"from_" values in Tweener

Thursday, May 01, 2008

The following is in response to some emails on the Tweener mailing list that asked about using "from" values, similarly to how TweenLite has to() and from() methods. I'll start by saying that I'm a huge fan of "from" values (or methods...) for one main reason. First of all, I don't ever have assets on the stage in my .FLAs, I attach everything to the stage at runtime from the library (or libraries from swfs I load). So if I have a display object that is going to be at x:100 & y:200, but it's going to tween in from off-stage I have two options. I can place it off-stage and then tween it to (100,200). OR, I can place it at (100,200) and then tween it from off-stage. I prefer the second option for two reasons.

First, I often build my screens at one stage of development, then do all of the animation later. Placing everything where it's supposed to go allows me to see everything in place and know that the screen looks as it should. Second, I find that it's much clearer later when I come back to my code to have the separation between the placement coordinates and animation coordinates.

SO.

I've been working for a while on an animation class that "pre-packages" animations that I can use out of the box -- stuff that I use a lot like fadeBlurIn(), flickerOut(), swooshIn() (bezier tween...), and ones that I like a lot -- popAndGlow() and tvOut(). While my animation class uses Tweener, I've built "from" values into this class by making very small tweaks to Tweener allowing me to interface with it. I'll point out those changes at the end of this post.

The way it works is quite simple. When I create an animation, I can prepend "from_" to (just about) any value for that value to be set before the animation begins: from_x, from_y, from_alpha, from__Blur_blurX... I know that there are some properties that this will not work with, though I can't say that I've tried everything yet. I do know that from__color does not work, so I'm making the assumption that there will be others.

This is where things get really messy. This is the code I'm using in my animation class to make all of this work:


public static function createAnim(mc:DisplayObject, base:Object, tweenProps:Object = null):void {
trace("create Anim with " + mc);

var allProps:Object = new Object();

if(tweenProps != null){
// create one object with all tween properties
for(var prop in base){ allProps[prop] = base[prop]; } // set base properties first
for(prop in tweenProps) { allProps[prop] = tweenProps[prop]; } // then the properties the user passed in, giving them priority
} else {
allProps = base;
}

// set property values of "from_" properties in allProps
setInitProps(mc, allProps);
allProps = removeProps(allProps, ["from_"]);

// and do the tween (not quite like o/` do the hustle)
Tweener.addTween(mc,allProps);
}


/*
* used to set all "from_" properties before any Tweening starts
*/
private static function setInitProps(mc:DisplayObject,tweenProps:Object):void{
for(var prop in tweenProps){
var propStr = prop.toString();
if(propStr.indexOf("from_") != -1){
// remove "from_" from property name
// ie "from__Blur_blurX" becomes "_Blur_blurX"
var p = propStr.substr(propStr.indexOf("_") + 1);

if (Tweener._specialPropertyList[p] != undefined) {
//previously Tweener.setPropertyValue(mc,p,tweenProps[prop]);
Tweener._specialPropertyList[p].setValue(mc, tweenProps[prop], Tweener._specialPropertyList[p].parameters);
} else {
trace("from_" + p + ": " + tweenProps[prop]);
mc[p] = tweenProps[prop];
}
}
}
}


/*
* removeProps allows you to remove any property or set of properties from an object.
* properties to delete should be passed in as an array.
*
* examples:
* to remove all properties containing "from_", pass in ["from_"] as your propNames array (as in createAnim())
*
* to remove all properties containing all scale and alpha properties, pass in ["scale","alpha"].
* this would remove alpha, from_alpha, scaleX, scaleY, from_scaleX, from_scaleY...
*/
private static function removeProps(tweenProps:Object, propNames:Array) {
for (var i = 0; i < propNames.length; i++ ) {
for (var props in tweenProps) {
if (props.toString().indexOf(propNames[i]) != -1) {
trace("propNames[i]: " + propNames[i]);

// hmmm... will this require a list of exclusions?
if(propNames[i] == "y" && props.toString() == "delay"){
break;
} else {
delete tweenProps[props];
}
}
}
}

return tweenProps;
}




To walk through the way this works, let's say I create a new movieclip from the library:

var bla_mc = new Bla();
bla_mc.x = 100;
bla_mc.y = 200;
bla_mc.alpha = 1;
this.addChild(bla_mc);

If I publish the swf now, I will see the bla_mc on the stage. So I add:

Animator3.createAnim(bla_mc, { from_x:-200, x:bla_mc.x, from_alpha:0, alpha:1, from__Blur_blurX:30, _Blur_blurX:0});

Now if I publish I will see the swf fade, blur and slide in from the left. You'll note that I have to pass the values in pairs, which is a little tedious, but otherwise I'd have to check for "to" values for every "from" value and create them where there are none. Perhaps I will even do that in the future, but for now passing values in pairs works fine for me.

My Animator3 class (the original for AS2 was Animator, so this one is Animator3 for AS3 -- which avoids confusion with Adobe's new Animator class as well) uses setInitProps() to find all of the "from_" properties and set them using Tweener's _specialPropertyList. After the values are set, the "from_" properties are removed from the list of properties being sent to Tweener.


Ok, finally, here are the changes to Tweener that I have noted -- there are only two: in Tweener.as _specialPropertyList must be public and not private; and in ColorShortcuts.as, replace

var cfm:ColorTransform = new ColorTransform(mc, mc, mc, 0, co, co, co, 0);

with

var cfm:ColorTransform = new ColorTransform(mc, mc, mc, p_obj.alpha, co, co, co, 0);

One final disclaimer is that this is tested and working for me in use thus far, but testing is not 100% complete by any means. I'm not sure which properties will join from__color in not working -- but this is a start!

posted by j. Permanent Link