gTween beta 2: ActionScript 3 Tweening Library

Having returned from a whirlwind of conferences and client meetings, I finally carved out a bit of time to work on gTween, my AS3 tweening engine. I’ve tweaked the API, added feature enhancements, fixed a couple of minor bugs, and am happy to announce gTween beta 2.

Here’s a list of the specific changes:

  • still under 5kb
  • renamed .transitionFunction property to .ease (for consistency with other engines – thanks to Marcus Stade for the feedback)
  • renamed GTween.paused static property to .pauseAll (for clarity, and to fix a problem with ASDoc)
  • fixed a typing conflict for progress points (data was mistakenly typed as String instead of * – thanks to Thomas Rudin for the feedback)
  • changed .removeProgressPoint() to accept a position instead of data (thanks again to Thomas Rudin)
  • added additional checking for bad values for delay, duration, and position
  • default .timingMode changed to HYBRID (better default choice)
  • added .roundValues property, which rounds the tweened values before they are set on the target (thanks to Vaclav Vancura for the feedback)
  • added .clone() method, with options to clone progress points and children
  • added a CHANGE event that fires whenever tweened properties are updated (thanks to Elliot Geno for the feedback)
  • added support in setTweenProperties for setting up event listeners with special eventListener properties (ex. progressListener, completeListener). This also applies to the tweenProperties parameter of the constructor. (thanks to thienhaflash for the feedback)
  • added a .data property for associating arbitrary data with a tween instance

The last two options allow you to easily set up a tween and it’s listeners in a single line, and associate arbitrary data that you can use to respond to those events. For example:

var tween:GTween = new GTween(mySprite, 2, {x:200, y:200}, {completeListener:handleComplete, data:"joy"});
function handleComplete(evt:Event):void {
trace("complete: "+evt.target.data);
}

For more information on any of the features above, please look them up in the API documentation.

I also worked with Jack to fix the banding issue in his tween performance demo – his implementation simply wasn’t setting delay properties on gTween properly. gTween is sitting nicely as the second fastest engine (behind Jack’s TweenLite / TweenMax). I’m not particularly worried about meeting or exceeding the performance of TweenLite (raw performance is not the driving consideration behind gTween), however I do hope to narrow the gap in beta 3, which will be mostly focused on optimization and clean up.

To download the latest beta, view demos, or access the API documentation, please visit gskinner.com/libraries/gtween/. If you’re new to gTween, you might also want to check out the introduction and feature overview.

As always, I welcome any feedback or suggestions in the comments below.

Grant Skinner

The "g" in gskinner. Also the "skinner".

@gskinner

37 Comments

  1. This is getting seriously cool. I’m definately going to try and evaluate your library in a real world project very soon instead of just jerking around. Good stuff, thanks!

    I’ve been meaning to ask (since I haven’t had the time to dwelve into the code for real). How accurate are the progress points? If I set one at 1.5 seconds into a 3 second tween and there is some serious frame dropping going on, will the event still be fired (at some point) or will the tweening engine figure that the three seconds are up already and we missed the halfway point?

  2. Thanks Marcus. Actually you raise a good point. The current model will always trigger the last progress point passed, but does not currently queue them.

    For example:

    1s tween, progress point at 0.5s, massive CPU utilization to the point that update only occurs once, at the end of the tween.

    In this case, the middle progress point would fire before the complete event, because gTween would evaluate it as the most recently passed progress point on the update before it evaluates for completion.

    However, if you added another progress point at 0.4s, it would not be triggered, because gTween would only evaluate the last progress it passed when it updated (in this extreme example, only once at the end of the tween).

    Queuing progress points should be easy to add – I’ll look into it for beta 3.

  3. Have I told you lately that I love you? I ask a question, on the blog no less, and get an excellent answer not even 10 minutes later! =)

    Are you going to Flash On The Beach btw? If you are, I owe you a beer.

  4. Do you happen to have this on google code to allow us to update easily from an SVN?

  5. Marcus – ๐Ÿ™‚ Yes, I will be at FotB. Hope to see you there.

    Corban – Not yet. Once I get past beta 3 I will put it on google code. I want to closely control distribution and modifications until I think the API and codebase is reasonably stable.

  6. Thanks, Grant, another spectacular contribution to the AS3 community.

  7. Hi everyone,

    Sorry a bit off-topic…

    Is there any Grant SVN for all these wonderful classes? (not only the tweener) Or at least, any way to browse what has been written and release here over the years? (even small classes).

    Sorry for the interruption.

    Romu

  8. I’ve been using GTween in a project I’m working on. After upgrading my code with the new beta there’s been a very noticable speed increase. The tweens seem to be much smoother than before. Nice work ๐Ÿ™‚

  9. Hi Grant,

    I am not sure if I am not stupid, but I’ve got a problem with transient calls. I’d like to have a simple delayed call, but something is broken. Sure I can handle it through Timer or setTimeout, but I am just curious why it’s not working for me:

    This is not working:

    new GTween((new Object()), .05, null, {completeListener:function():void { /* do something */ }});

    (even when I use {} instead of null in properties Object, just to be sure).

    And wow, this works:

    new GTween((new Object()), .05, {x:1}, {completeListener:function():void { /* do something */ }});

    (right, an Object with GTween applied is not a DisplayObject, that’s just a test – but in this case it just works.

    I tried to find the bug, but I was completely lost in your source code. Maybe this issue isn’t really important to solve, as probably nobody will use GTween as setTimeout replacement, but maybe it’s a trace of some other bug…

    Have a good weekend,

    Vaclav

  10. Vaclav – gTween instances do not autoplay until a property is changed. Do you mind me asking why you’re doing this? It looks as though you’re just using gTween as a delay timer – is that the case?

    If so, I think that if you specify paused:false in your tweenProperties parameter, that should work.

    new GTween((new Object()), .05, null, {paused:false, completeListener:function():void { /* do something */ }});

  11. Hi.

    I got a feature request: what about timescaling? It’s really helpful when you want to precisely fine tune animations. Tweener does it this way: http://hosted.zeh.com.br/tweener/docs/en-us/methods/Tweener_setTimeScale.html

    Vaclav

  12. Grant, thanks for the reply. It works now! I completely forgot about the paused flag.

  13. Some code tips:

    – variable ticker is defined two times (ln 192, 289), once as protected, once as static.

    – function callProperty (ln 886) should be void – does not have a return statement

    – import Shape is not used (ln 37)

    – missing ending semicolon (ln 363,378,394,961,984)

    Thanks for this great class!!!

  14. ooops, the shape import is used…

  15. Romu – no, but I recognize the need for one. One day, when I have some spare time, I’ll try to set up a repository. Or perhaps I’ll make an intern do it. ๐Ÿ™‚

    Matus – Thanks for the feedback! The ticker property is used in both locations, though I’ll consider renaming one for clarity. Good catch on callProperty – that method should actually return the value from the apply call, I’ve fixed it locally. I’ve also added the missing semicolons. ๐Ÿ™‚

  16. Hi,

    it would be nice to have an onprogress event on every frame or a progress point * that gets triggered every time the target gets moved/animated. I have a lot of situations where i need to update some other stuff during an animation this would just be very handy.

    cheers and thanks for the nice Class

  17. Patrick,

    Beta 2 “added a CHANGE event that fires whenever tweened properties are updated)”

    Does that meet your needs?

  18. afraid i’m struggling with tweening filters (eg. BlurFilter). is there an easy way!?

  19. Hi there,

    Thought I’d check out this new GTween that peeps are talking about – very nice indeed…

    I second the fact that I an struggling with tweening filters – I will make do with updating on the new ‘CHANGE’ event for now, but is there an easier way?

    I am trying the following as a test… but no joy!

    var glow:GlowFilter = new GlowFilter(0xff00ff,0.8,10,10,2,BitmapFilterQuality.HIGH,false,false);

    var mf:Array = new Array();

    mf.push(glow);

    fooFilter.filters = mf;

    var gtFilter:GTween = new GTween( GlowFilter(fooFilter.filters[0]), 3, { blurX:200, blurY:200 }, {ease:Circular.easeOut, delay:0} );

    Any help would be much appreciated.

    Cheers

    Dan

  20. i really think you should change “completeListener” to “onComplete”. Several of the other motion frameworks use onComplete and I think it’s a bit more intuitive. completeListener would prompt the use of a function a little more clearly.

  21. re-examining it, i do understand why you’ve chosen “completeListener”, but maybe theres a more intuitive way to do this?

  22. Hey,

    I have been meaning to try out this class, and finally got around to putting into a project. However, there is some weird behavior that has been frustrating.

    Here is the code I am using:

    private function showSegment (index:uint):void {

    for (var i:uint = 0; i

  23. Oh, wow. I really have been missing too much sleep lately.

    I changed “alpha: 100” to “alpha: 1” and it worked just like expected.

  24. I like the structure of gTween when it comes to creating and using event handlers, but I miss Tweener’s ability to overwrite previous tweens when you create new ones.

    For example, if I begin tweening an object to an alpha of zero, yet create a new tween for that same object to an alpha of one, I want to be able to overwrite the original tween so that the behavior doesn’t get strange.

    Is there a simple way to handle this (other than saving a reference to each tween I create, which I would rather not do) or would this require the creation of some kind of “gTweenManager” to leverage some of the global features Tweener has?

    Thanks :o)

  25. Joshua,

    I simply maintain a reference to the tween. In your example I would just instantiate all of the tweens when I set things up and save them to an array, then access them when I need to make an update. You can then just either use setProperty or the proxy property to change the value:

    contentTweens[i].proxy.alpha = (i==index) ? 1 : 0;

    I have been considering exposing a method to look up whether there is an active tween on an object, however this requires that I maintain that reference, and has a bit of an impact on garbage collection. It also becomes quite complicated in that there are often occasions that I would want multiple tweens on a single target. I’m interested to hear thoughts on this one.

    Cheers.

  26. Thanks for sharing GTween; I’m a happy user. Two remarks

    – I’ve got the following use case:

    parentTween.duration = 5

    childTween.duration = 1

    parentTween.addChild(childTween, false)

    When it plays forward, childTween starts at the beginning. But when I run parentTween.reverse(), childTween also plays right at the beginning even though I expect it to play after 4 seconds. Is this a feature or a bug?

    – Maybe you are willing to share your opinion about coding style in an other blog. For instance, are there any performance benefits that you squeeze two assignments on one line? e.g.

    positionOffset = ticker.position-(_position = _duration-_position);

    I think there are none. So if it’s only for compact code in terms of characters, why do have any ending semicolon?

  27. At its simplest, it would be great to be able to clear any tweens that are affecting a certain object.

    Perhaps tweens can register themselves with some kind of global class instance that keeps track of tweens by object. Tweens could probably unregister themselves when their delay is over and they have already played. In this way, one could keep tabs on all the tweens which affect one object. If these tweens could be returned, by object, in an array, then a developer could understand for themselves which tweens they want to remove or proxy.

    If adding this sort of global management takes a toll on performance, I might consider breaking it out into a seperate management class. Many users may not expect this sort of global control, and would gladly trade it for a performance boost. Other users, like those which are familiar with Tweener, may welcome the extra control and care little about a slight performance loss.

  28. Grant,

    I am have trouble with tweening to alpha 0 then tweening back to 1 as in the case of roll-over fade-in; roll-out fade-out. If I set the fade out value to 0 then it never fades back in. If I set the fade out value to 0.01 then it fades back in as expected. Really like the proxy functionality. So clean!

  29. Randy,

    Sounds like there’s an issue with the autoHide functionality. Try setting autoHide=false for now. I’ll take a look at it in the next day or two.

  30. Hi, I trying to do a tweener with no success. The problem is that I am trying to do a tween from the value true to false. What is wrong?

  31. Olandim,

    You can’t tween boolean (true/false) values – there are no values between true and false to tween to (ie. there are no “kind of true” values). You can only tween numeric values.

  32. Hey,

    Great class, finding it really useful.

    Just found something that may/may not be a bug:

    {completeListener:handleComplete, data:”joy”}

    If I leave out the data property completely then the handleComplete function doesn’t appear to get called.

    It’s not an issue really, I can leave data as empty but just thought i’d mention it.

    Thanks again!

    Toby

  33. Toby,

    I’m unable to reproduce that issue. The following code fires the complete event as expected:

    gTween = new GTween(foo,1,{y:200},{completeListener:handleComplete});

    function handleComplete(evt:Event):void {

    trace(“complete”);

    }

  34. Heya,

    Yeah I can see that’s doing what is expected now, thanks, actually I have no idea why that wasn’t working since i can’t replicate the issue now either and all afternoon it was broken, or maybe I was broken, never can tell.

    Anyway, thanks again.

    Toby

  35. Hi, I’ve used GTween heavily on a recent project (http://toki-woki.net/p/FFFFOUND-Desktop/) and I thought that being able to specify a default tween ease function would be awesome, via a static property or such… This way if your project uses the same tween function for all its tweens, everyhthing would be much simpler!

    GTween.defaultEaseFunction=myEaseFunc;

    What do you think?

  36. Hi Grant.

    Wanted to recommend a change to your code based on a RTE I encountered. Inside your protected updateProperties function you have made the assumption that if the target object has a “setSize” method then it probably takes only two parameters. Though this may be the norm in 99% of cases, you aren’t accounting for data objects that might represent a visual assets which can take on more than two “size” properties. Case in point are isometric objects. I would defer to the normalized logic using:

    _target[n] = initProperties[n]+(destProperties[n]-initProperties[n])*value;

    Just an FYI. Thanks again for your contribution. It is an awesome project.

    J

  37. Hey Grant–

    I’m using setTweenProperties to add a completeListener to a tween, but can’t figure out how to remove that listener. What am I missing?

Leave a Reply

Your email address will not be published. Required fields are marked *