gTween: A New Tweening Engine for AS3 Developers

gTween: Programmatic Tweening for AS3 Developers

There are a lot of great tweening engines out there. Personally, I’m a huge fan of Jack Doyle’s TweenLite (and he’s been incredibly productive adding new features lately). However, none of these libraries exactly fit the needs of me and my team. I wanted an engine that was small, fast, hugely flexible, and built from the ground up for AS3 and developers.

The result was gTween. gTween is a small (4.5kb), fast (1500 instances, 0.5s duration, ~25fps), instance based tweening class, with a huge number of options and capabilities. You can read about core features of gTween below.

This is certainly not an attempt to displace any of the existing tween engines. Rather, it’s simply an attempt to share another option for managing programmatic tweens with the developer community.

For now, I am releasing this as a public beta. It has been loosely tested, but there is so much capability in gTween that I guarantee there are still bugs and edge cases we haven’t addressed. Likewise, I am soliciting input on additions or modifications to the API (including the names of specific properties or methods), so it is possible that the API may change in the future.

Quick Feature Overview

Developer Oriented Proxy Tweening Interruptible Sequencing Timing Modes Pause All Events Resource Management Etc

Developer Oriented (consistent AS3 experience)

gTween is built for ActionScript 3 developers from the ground up. It uses a more conventional instance-oriented model, rather than a static interface. It also leverages the AS3 event model instead of callbacks (see Events). This provides a familiar, consistent experience for AS3 developers to work with tweens.

Here’s a simple example of setting up a tween, and listening for the complete event.

var myTween:GTween = new GTween(mySprite, 2, {x:200});
myTween.addEventListener(Event.COMPLETE, handleTweenComplete);

Instances can either be referenced or transient. The former allows for changing values and behaviour on the fly (see Sequencing), and the latter works with smart resource management logic to ensure the tween won’t be collected until it is finished running (see Resource Management).

Examples of referenced versus transient instances:.

// hold a reference in myTween, so we can modify it later
var myTween:GTween = new GTween(mySprite, 2, {x:200});
// run once, and then free tween for garbage collection
new GTween(mySprite1, 2, {x:400});

gTween will also work with any numeric property of any object. You can use it to tween the volume of a sound, the size of an AIR window, or the value of “foo” on a custom object type, as easily as you would tween the x property of a Sprite.

Proxy Tweening

gTween provides a unique proxy property that allows you to work with tween destination values the same way you would work with them on the target object. The proxy object effectively “stands in” for your target object.

This simple example shows how you can use the proxy to move the target object 100 pixels to the right.

myTween.proxy.x += 100;

In the above example, the proxy will retrieve the x value from the target object (if it doesn’t already exist as a destination value in the tween), add 100, and set it back as a destination value for the tween.

This is a very powerful feature that takes a little getting used to. Take a look at the proxy listing in the full API documentation for more information and examples.

Interrupting Tweens (make changes on the fly)

With gTween, you can modify your tween while it is playing, and it will attempt to accommodate those changes.

The user closes a panel before its done sliding in? Just reverse() it, and it will slide back closed from its current position. Need to move a sprite to a different location, or add an alpha fade out while the tween is running? Just adjust the values on the fly.

Here’s a simple example showing how you can tween a sprite to the location a user clicks on stage. Note that the user can click at any time, and the tween will adjust itself to smoothly reach the destination.

var myTween:GTween = new GTween(mySprite,1);
stage.addEventListener(MouseEvent.CLICK,handleClick);
function handleClick(evt:MouseEvent):void {
myTween.proxy.x = mouseX;
myTween.proxy.y = mouseY;
}

You can also jump to the end or beginning of a tween instantly with beginning() or end(). Calling end(true) will recursively end sequenced tweens.

Sequencing Tweens (child tweens, and nextTween)

gTween provides three features to allow for sequencing multiple tweens: child tweens, delay, and nextTween.

By using addChild, you can associate multiple tweens to act as children of your tween. These tweens will be synchronized with the parent tween when it runs. You can even choose to synchronize their delay, beginning, ending, or duration.

You can also specify another tween to play when a tween ends using nextTween, and specify a delay period that a tween will wait before playing.

The following example demonstrates playing two tween synchronously, followed by a 2 second delay before a third tween plays.

var myTween1:GTween = new GTween(target1,3,{x:20});
var myTween2:GTween = new GTween(target2,0,{x:200});
myTween1.addChild(myTween2,GTween.DURATION);
var myTween3:GTween = new GTween(target3,3,{y:50});
myTween3.delay = 2;
myTween1.nextTween = myTween3;

Timing Modes (frame, time, or hybrid)

Another unique feature of gTween is support for multiple timing modes. You can use the common time based timing, frame based timing, or a hybrid timing model.

In the “time” timing mode, all durations and positions are specified in seconds, and updates are run at a configurable frequency (ex. every 50ms). This provides tight control over durations, but can use more CPU, and be a bit more choppy in high CPU scenarios.

Using the “frame” timing mode, all durations and positions are specified in frames, and updates are run each frame. This uses a bit less CPU, and allows you to synchronize your tween with timeline animations, but the overall time duration can be unpredictable in high CPU scenarios.

The “hybrid” mode updates each frame, but allows you to specify durations in seconds. Each frame the tween will adjust its position according to the elapsed time since the previous update.

GTween.timingMode = GTween.TIME;

Because it is unlikely developers will change modes during a project, it is specified as a class level property. However, gTween will continue to use the old setting with old tweens, which allows you to change the mode at any time.

Pause All

Being able to pause all tweens can be handy. Pause all of the sprites in your game when the user pauses it, or pause all the active transitions when you open a dialog.

gTween offers a class level pauseAll property that will pause all tweens, without affecting their per instance paused property. Handy!

myTween.paused = false;
GTween.pauseAll = true; // pause ALL tweens.
trace(myTween.paused); // false

Robust Events

gTween offers three built in events: an activate event that lets you know when a tween starts running, an init event that fires when the tween finishes delaying and starts tweening, a change event that fires each time the tween updates, and a complete event that fires when it reaches its end.

Not enough? gTween allows you to dynamically add custom progress points to your tween that will fire when the tween reaches that point.

The following example shows how you can receive an event when a 3 second tween passes the halfway point (1.5 seconds), and get back a “halfway” string:

var myTween:GTween = new GTween(target1, 3, {alpha:1});
myTween.addProgressPoint(1.5,"halfway");
myTween.addEventListener(GTween.PROGRESS,onProgress);
function onProgress(evt:Event):void {
trace(String(myTween.lastProgressPoint));
}

Note that you can associate any type of data with a progress point. A string labelling the point, a function to call when you reach that point, another tween to run, anything you want.

Resource Management

Resource management is important. You don’t want old tweens hanging around using CPU and memory. You also don’t want unreferenced tweens being garbage collected while they are still active.

Besides being developed with the AVM2 garbage collector in mind, gTween also uses a couple of strategies to allow unreferenced tweens to be collected when they are no longer needed, while preventing them from being destroyed when they are needed.


  1. If a tween is targeted at an object that extends EventDispatcher (like Sprite), it will subscribe itself as a listener to that object for a dummy event while its active. This allows the tween to be collected when it ends, or as soon as its target becomes elligible for collection.
  2. If its target is not an EventDispatcher, the tween adds itself to a class level collection while it is active. This keeps it from being collected until it is finished running.

gTween has been tested creating 3000 new tween instances per second with no memory leaks.

Additional Features

gTween has a lot of additional features. I’m not going to write about all of them, but here are a few:


  • autoHide, sets the target’s visible to false when the tweened alpha is 0
  • autoReverse, reverses the tween when it ends (and plays it backwards if autoPlay is true).
  • smartRotate, rotates in shortest direction
  • supports using setSize for tweening height and width on components
  • support for updating properties like matrix and colorTransform automatically during a tween.
  • jump to any point in a tween by setting position.
  • loop a tween by setting nextTween equal to the same tween.
  • determine the state of a tween with the state and paused properties.
  • roundValues makes a tween round all tweened values before setting them on the target.

Download

To access the API documentation, and download the latest build of GTween, visit the GTween page at gskinner.com/libraries/gtween/.

Please provide any feedback or bug reports in the comments below.

Updates:

Sep 3, 2008: Beta 2 has been released. Learn more about it by clicking here.

Nov 4, 2008: Beta 3 has been released. Learn more about it by clicking here.

Dec 15, 2008: Beta 4 has been released. Learn more about it by clicking here.

Grant Skinner

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

@gskinner

110 Comments

  1. This sounds super powerful and all in 4.5k? Insane. I’m definitely taking this thing for a test drive tonight.

  2. Would this API be suited for typed calls, instead of dynamically passing along an {x:60} object? In a scenario where you’d use a lot of tweens in succession, a typo is easily made and sometimes a lot harder to spot at runtime.

    I really like the proxy and progresspoints features, by the way. // ep

  3. A pain I’ve felt using another tweening library was the lack of support for passing in an array of objects to be tweened and having them all be tweened the same way. I haven’t dived into gTween’s code but from the documentation, this doesn’t seem to be an option. I’d love to see that option in a future release.

  4. Wow. Great! This is exactly what I needed!

    But there’s one simple feature which keeps me with Tweener (and which can’t be found even in TweenMax): rounding. For example when you want to tween a Bitmap to a rounded position in each frame, you have to add an ENTER_FRAME handler to round it for you. In Tweener it’s simple: rounded:true.

    Is there any chance to add it please?

  5. Looks good Grant. I like the approach and features. I’ll give’r a whirl one day.

  6. great job!

  7. Awesome Grant!

  8. The API docs appear to be out of date –> In the API docs, the constructor GTween takes 5 params: target, duration, object properties, transition function, and auto play. However, the GTween.as constructor takes 4 params: target, duration, object properties, and tween properties.

  9. No doubt you’ve tested it extensively, it’s quite a fresh approach to tweening with some really nice features. I particularly love the timing modes. Can’t wait to play with it. Great work.

  10. John – thanks for catching this! I had forgotten to copy the latest ASDocs over prior to releasing this. I have updated the ASDocs online and in the distribution.

  11. Looks like some awesome features here. Especially the resource management. Nice work.

    I looked through the docs and did not see a way to specify the type of ease or method to use for the tween, like in TweenLite. Am I missing it? If not, this would be certainly be a must.

  12. Looks sweet – is there any recourse for overwriting tweens? Alternately is there a way to recall an anonymous tween to change it?

  13. Found it – transitionFunction

  14. Welp, so much for convincing anyone to get interested in the idea of collaborating on a community basis to create a base animation library instead of reinventing the wheel. I’ll just go put my head under a rock for a while.

  15. Hey Moses, I agree to a point. Collaboration is a wonderful thing for community driven projects like Go and PPV3D. I had very specific needs for this tweening engine, and none of the existing engines were built in a way that would easily accommodate them, without investing a lot more work than it would take to build a new class from scratch.

    Once GTween was built for our internal use, it made sense to share it with the community, in case it addressed the needs of other developers. GTween absolutely did not arise from a decision to eschew collaboration or to marginalize or exclude existing libraries.

  16. Hi Grant! When autoReverse = true, how do I put a delay in between tweens? I want the animation to start immediately, waits for a few seconds and starts autoreversing.

    Thanks!

    Jon

  17. Nice work! I’m looking forward to playing around with this.

    I’m working off an example from a book named Objected orientated action script which shows how to make a tween framework.

    Hopefully I’ll be able to make something this cool some day πŸ™‚

  18. Looks really good Grant. Gonna try it a bit πŸ™‚

  19. Is there a greater embarrassment for the flash community than tweening? How hard is it to programmatically make an object go from one place to another? For the love of god shut up about tweening and programmatic animation already, it’s not that complicated. Have you ever looked at the source code for Fuse? The horror.

  20. @Flash Bastard: I’m not sure if this is what you meant, but programmatic tweening is one of those things that are so close to the developer and that so much of his/her work end up relying on it that it’s just a given that we’ll always see a good number of different implementations, each doing things slightly different and fitting better into a different work flow method, and always as abstract and separated from actual projects as possible, as a separate kind of package.

    I can’t think of anything as frustrating for a developer as using an animation and event chaining framework that he doesn’t like, or that doesn’t feel natural and transparent, and as such, I’m pretty happy to see a new one around — and in this case, one done by one of the guys who have been around in the Flash community since forever nonetheless.

    And personally, although I haven’t done great changes to my own tweening classes (Tweener) recently due to having a lot of real work and a college thesis to finish first, I’ve been thinking a lot about tweening in AS3 lately and there’s a number of features and, specially, different ways of doing stuff that I’ve kept in mind and on my plans for whenever I have the time to implement it. And surprisingly, most of the stuff I’ve seen above on gTween’s example implementations above follows exactly what I had in mind; I don’t meant to say this as some kind of “durr I thought of it first! but haven’t written it already! BUT I WIN!”, but just that its implementation looks *really* well thought out and matured for our AVM2 needs.

    That is all to say, gTween is looking awesome. Thanks, and keep up the good work, Grant.

  21. Grant,

    This is phenomenal.

    My big question is will gTween allow for custom properties? One of the things that is really nice about Tweener is that if there is not a property for something, I can create & register my own property.

    Also, I have yet to find a Tweening engine that allows me to apply one tween to multiple targets in a single command. Will gTween allow for the target to be an array of objects?

  22. Andy – Yes, one of my requirements for GTween was that it be completely object agnostic. Other than a few cases for special handling of particular properties (autoHide, smartRotate, setSize), it is completely independent of individual property names. Any numeric property on any object can be tweened with GTween.

    Some suggestions that sound like possible additions: multiple targets. Cloneable tweens – this would allow you to set up multiple identical tweens quickly for different targets. Rounded values.

    I also need to remember to rename transitionFunction to tweenFunction – meant to do that before release.

    Can someone post a good use case for tweening multiple targets with the same tween? I’m thinking a better approach might be a simple Composite pattern implementation that works with GTween, but would like to see the use cases first. Thanks.

  23. Flash Bastard, tweening is easy, the issues many times is on a particular project to use a library that makes it common (which ever tweening engine suits your or your own). But mainly this helps to make codebases common and teams able to interchange easily on that project. Yes there are lots of tweening engines but it is more about using frameworks for things so that actionscript isn’t programmer specific. Before AS3 lots of code was only touchable by the developer because it was a complete mess and unusable in any reuse. All that is changing. And you can see the effects in all the better games, apps, ads etc built with flash and specifically AS3.

  24. Looks very interesting Grant, thanks for sharing! About the name transitionFunction, wouldn’t easeFunction work out better than tweenFunction? The latter seems a bit confusing.

    What happens if you have multiple tweens working on the same target at the same time, would that work? What about conflicting Tweens which affect the same target properties?

  25. Regarding when one might have multiple targets with the same tween, say one was storing a list of display objects in an array. The circumstance can occur where such objects cannot be grouped in a DisplayObjectContainer.

    As such I would have to apply the tween to each item individually via a loop through the array. If it was possible to apply the array as the target, it would cut out a hair of code.

  26. Excellent class.I’ve already started using it in my projects. What appeals to me above everything else is the fact it’s AS3 oriented. Good job.

  27. I don’t know, maybe I’m missing something. But where I can find list and documentation of Tween Properties?

  28. So you use transitionFunction to set the easing? Can you post an example of this?

  29. Its performance is great with big amount of particles.

    Now we have three motion script library in the hand;

    1. Fuse Engine

    2. Tweener

    3. GTween

    BTW, Why they all work together for an ultimate one πŸ™‚

    I’ll have a test drive with this one and feedback.

    Thanks for sharing the work.

  30. I have tried to sequence a movie first to a position in x and after to a different in y.

    It doesn’t sequence and goes directly to the final position. Can it be because it has the same target?

    var tween1:GTween = new GTween (movie, 3, {x:500} );

    var tween2:GTween = new GTween (movie, 3, {y:500});

    tween1.nextTween = tween2;

  31. I’m sure this will come in handy when I just need to get something out the door. But I owe Moses my life and am dedicated to Goasap for the long haul.

  32. And – Do you mean that you’d like to be able to get back a list of the properties that you’ve set up to tween? Or, you’d like documentation on what properties GTween works with? If the former, if you give me a use case, I’ll consider adding the capability. If the latter, the answer is any numeric property.

    user – myTween.transitionFunction = Circular.easeInOut;

    Paulo – both of your tweens are autoplay by default, so they will both play at the same time. Try setting up your second tween like so:

    var tween2:GTween = new GTween(movie,3,{y:500},{autoPlay:false});

  33. Excellent ideas in this work. I just tried the custom progress points, and found some strange behaviour.

    1.) in class ProgressPoint:

    public var data:String;

    should be:

    public var data:*;

    I assume?

    2.) Why do you have removeProgressPoint(data); in addProgressPoint? This prevents us from using the same markers (signals) at two different positions, which should be possible, shouldn’t it?

    But thanks again and keep up the good work!

  34. Grant,

    Looks super cool and I can’t wait to try it out (I especially like the use of events rather than callbacks), but I’m partly with Moses on this one.

    I guess the bigger question is why hasn’t Adobe sought more community involvement on this topic? I thought for sure that bringing Robert Penner onto the team would have helped. I suppose it did create some nice new features, yet here we are 3 years later and still making our own animation libraries =/

  35. Flash Bastard: I’ll take your little jab on the chin since yeah, Fuse’s internal code is a bit ugly. πŸ™‚ Ironically, I wrote Fuse after I’d already put together a clean & tidy OO system (called Sequencer) — which to my chagrin crawled like mud in AVM1. I switched to Zigo’s unapologetic, down-and-dirty approach b/c it was massively faster, and very tightly synced. I still feel I beat the odds in AS2 / AVM1 by keeping Fuse fast and efficient while offering tons of features. A lot of the lessons from AVM1 are still applicable. For example, animation processes over twice as fast using a synced list system than a more normal OO approach — it’s a fact.

    So in the end, I don’t think we’re coding Flash or Flex so much as coding for the Flash Player. Working with it in its own way can yield some incredible performance gains.

  36. WOW! All this tween drama! I thought the worst was over.

    Great work Grant! Setting up a tween library is no walk in the park and I’ve come to respect anyone who will give it a try. Competition is fierce, demand for new features is high, and optimizing is like shooting in the dark. If we’re one more step closer to having a solid implementation built into the player, I’m all for it. I’m looking forward to trying it out.

    P.S. KitchenSync r00lz!!!1!

  37. Grant I looked at your library, your proxy idea is interesting.

    (Not really sure why you put all your classes in one file?)

  38. Grant, now I’m using GTween in my current project.

    I make tiny Flash CS3 project with Flash Components from Adobe (yes, I love Flex, but not only Flex components do exist). At some point I decided to animate the TileList scroll. I overrided its “scrollToIndex” method and used GTween there to animate “horizontalScrollPosition” property Ҁ” works like a charm!

    Question: In the comment above, you mentioned the following:

    user – myTween.transitionFunction = Circular.easeInOut;

    The question is, where “Circular.easeInOut” besides? Will you provide the tweening functions later, or will GTween consist only from one class, as in the current download?

    Thank you for great library. I decided to use it even in the beta because of your previous superior developments. It is very easy to start! Maybe it’s just because I was Tweener junkie for year, but I think GTween is really easy to use indeed.

  39. […]Nova Engine de Tween para AS3[…]

  40. Let’ me self-comment my own comment where I’m talking like true LOLCat:

    >> I overrided its “scrollToIndex” method

    I meant ‘I overriden’, I swear πŸ˜‰

    BTW, I get further and animated more components in my app with GTWeen. Great tool!

  41. I tried a sequence tween and it behaved correctly the first time, but every time after that it does both tweens at once.

    var menuHolderTween00:GTween = new GTween(this.catMenu, .2, { alpha:0 } );

    var menuHolderTween01:GTween = new GTween(this.catMenu,.5,{height:0});

    menuHolderTween00.nextTween = menuHolderTween01;

    Am I doing something wrong, or is this a bug?

  42. This is really a nice job.

    I prefer instance-oriented mode to static interface.Thanks Grant.

    But I have a problem of the event mode that cannot pass custom arguments easily to event handler function.

    And if one gtween object add event listener that must be removed explicitly when delete the object.

    That maybe become to a trouble?

  43. Hey Grant! Thank you very much for releasing your new tween engine to the masses, I appreciate it! πŸ™‚

    It looks really powerful (loving the proxy!), but I didn’t see an easy implementation for an ‘on complete execute this function’ method akin to: myTween.onComplete(func:Function);. I will probably just roll my own that listens for the complete event as needed, but it would be great if this was included out of the box. Did I just miss the implementation?

    Thanks again!

  44. @Elliot,

    Check out the events section above

    http://www.gskinner.com/blog/archives/2008/08/gtween_a_new_tw.html#events

    There are built in events for init, activated, and complete, and you can add your own events to any point in the Tween. Note that gTween uses event listeners rather than callbacks, which is an object-oriented approach, and more flexible than an onComplete callback.

  45. I see this in other situations and I always wonder the same thing, especially when it comes to Tweening.

    var myTween:GTween = new GTween(mySprite, 2, {x:200});

    myTween.addEventListener(Event.COMPLETE, handleTweenComplete);

    In this example is there something that makes sure the Event.COMPLETE doesn’t fire before the listener is registered? I would think you would want a myTween.start() function.

    I haven’t dug into TweenLite to verify this but I figured passing in the listeners/events in the constructor guaranteed the Tween won’t fire off the Event you need before you are listening for it. (and allows stuff like onStart Events)

  46. I noticed you have a special progress event… do you have something akin to the Tween Class’s onMotionChanged? That on is pretty useful.

  47. mike – when sequencing tweens, you will generally want to set the autoPlay property of the nextTween or child tweens to false:

    var myTween2:GTween = new GTween(target,0.2,{height:0},{autoPlay:false});

    jacob – you would receive the COMPLETE event ok (because it is delayed at least one frame), however, you would not receive the ACTIVATE or INIT events on a tween with autoPlay set to false. This is definitely an issue I need to resolve in GTween. There are no perfect answers, but I’m thinking through the available options and will select the best one.

    elliot – I considered broadcasting a “change” or “tic” event, however I decided not to because it results in a CPU cost for all tweens and I’m guessing it is a rarely used case. I will benchmark it, and if the speed difference is very minimal I will implement one.

  48. GTween: Quick Review

    One of the easy things to do in Flash is tween but it never hurts to make an easy thing easier and that’s exactly what Grant Skin…errr…my bad…gSkinner (hehe) has done. So, maybe it doesn’t suit you, heck…might not suit…

  49. Interesting albeit surprising to see another invention of the wheel spawn from the community. With TweenMax/TweenLite practically being industry standard I’m a bit confused why so much work has gone into creating this.

    Be that as it may, how does this weigh up to its alternatives in Memory imprint and processing penalty?

    Since at this point there’s really very little point in going anywhere with your projects unless something offers a very positive change in performance (like TweenLite/Max over Tweener) because of the impact it has on older projects and a development team, It’d be interesting to see some comparisons before I try it out πŸ˜‰

  50. Nice Grant,

    Altough i think you can get some more preformance upgrades. TweenLight is 10k but can handle 2500 instances. So untill nyours can handle 2500 i am staying with tweenlight πŸ™‚

    Nice effort though.

  51. To Rackdoll:

    what’s your meaning of TweenLight?Is that indicate TweenLite?And the weight of TweenLite is about 3K,where are your 10K come from?

  52. Wow to all the developers with negative comments:

    ———————————————-

    Where is the logic in complaining about receiving another avenue for free code? Its not like there are billions of tween engines out there, making it tedious to know which to use ,rather there is enough info on the web to quickly find the top engines out there , and find which one suites your needs. The edge of development is maintained and surpassed by people doing exactly what grant did , by continually providing new/different solutions. Did you say the same thing when the second or third engine found its way onto the internet free of charge ? why say it now .. have the tween saturation limits been reached ? I read a post on joa-ebert’s blog where he discussed his new engine he built , which surpasses tweenlites performance and prowl , while not for public release , its still very exciting to know such an engine exists and was built. ( http://blog.joa-ebert.com/2008/05/07/tweening-and-object-pools/ )

    Let me show you how you should respond:

    Thanks for your work and effort Grant πŸ˜‰

  53. I’ve run into an issue when trying to dynamically alter multiple tween properties using proxy. It seems that combining x, y, scaleX, scaleY and alpha does something to prevent the target display object from being rendered (it just disappears once the tween initializes). Here is a stripped down snippet that should replicate the issue:

    var tween:GTween = new GTween(testObject, 1);

    stage.addEventListener(MouseEvent.CLICK, clickHandler);

    function clickHandler(p_event:Event):void {

    tween.proxy.alpha = Math.random();

    tween.proxy.x = mouseX;

    tween.proxy.y = mouseY;

    tween.proxy.scaleX = Math.random() * 1;

    tween.proxy.scaleY = Math.random() * 1;

    tween.proxy.rotation = Math.random() * 360;

    tween.play();

    }

    The real bizarre part is that by adding another property to be tweened (ie: tween.proxy.width = 5;) or removing one property seems to completely resolve the issue. Any thoughts?

  54. Sorry: x, y, scaleX, scaleY, alpha and rotation.

  55. Hey Grant!

    Glad to see your throwing your hat into the Tweening ring!

    I just popped over to the TweenLite speed test site (http://blog.greensock.com/tweening-speed-test/) and was surprised to see that you’ve been added to the list. What’s also surprising is that your engine is rendering the particles as concentric circles. Now I don’t know what particle generation code is being used to generate this but the result seems a bit odd.

  56. Maximum performance is not the goal of this tweening engine. Instead I’m shooting for a balance between good performance, and a rich feature set.

    With all due respect, if you’re choosing your tween engine based on whether it can tween 4000 versus 3000 instances at once, instead of whether it suits your coding style and project types, you are probably very misguided. This is coming from someone that’s probably a little too anal about optimization. If you’re tweening that many instance, you’d be better off with a few lines of custom code, instead of a tween engine.

    Again though, I’m not trying to win anyone over here. If you like your existing tweening engine, or need to be able to tween that extra thousand instances, please stick with it. I’m just providing an alternative way of working with tweens (for free, I might add) that has worked well for my team.

    Now that I’m back from FlashForward I’ll be working a bit more on gTween, and hopefully will release a new version with some fixes and additions shortly.

    I’m also working with Jack to figure out why gTween bands in his test suite, but not in mine (showing 3000 active tweens):

    http://gskinner.com/libraries/gtween/demos/SpeedDemo.html

  57. @Brett

    I have done some testing in the office with GTween and proxies. I was unable to replicate the issue you reported using the same snippet you posted on the site.

    Is there a sample online that demonstrates the object not being rendered correctly?

  58. 43 Hot Flex and ActionScript 3.0 APIs, tips and tools for Autumn 2008

  59. Hi, Grant

    First thing i want to tell you : GREAT JOB, MAN.

    I’m also a big fan of TweenLite and family.

    I found your .proxy to change the end properties very useful, and it’s the kind of thing i really want from TweenLite.

    Also like the way you split up properties into two object, that will more efficient than one.

    But i really don’t like the event, i think onComplete, onUpdate, onStart of TweenLite will give the developer much more efficient, especialy who do much about code-animation. Adding onComplete, onUpdate, onStart would be extreamely useful. You may think that i’m not a good developer but it will really handy have these call back functions in hand.

    Thanks.

  60. First off, GREAT job Grant. I totally concur with ian who said the proper response to Grant releasing gTween is “THANKS!”. He’s doing what he’s known for doing – innovating and contributing to making the Flash community better.

    Regarding thienhaflash’s comment (and a few others’), I just wanted to point out that TweenMax (TweenLite’s “big brother”) has a setDestination() method that is somewhat similar to gTween’s proxy, and that you can use TweenLite/TweenMax in an object-oriented manner instead of the static to() and from() methods if you prefer. That’s NOT to say it’s better (or even as good) as gTween. Just different. http://www.TweenMax.com

    Grant has provided yet another solid tweening alternative, and he has done so in a spirit of generosity. Trust me, it takes a lot of time and effort to put something like this out for everyone to critique and then answer all the questions that come flooding in. If you like it, great – use it and let it make you more productive. If not, use something else, but be careful about complaining especially since it’s free!

    Thanks again Grant.

  61. @Nick

    So after looking at this again, its even more bizarre than I originally thought. The code snippet I provided consistently causes the issue for me, but only when testing the movie from within the Flash IDE. Opening the subsequently generated swf independently resolves the problem completely, and all tweens to the target display object are rendered as intended. I’ve never encountered anything like this before, but for all intensive purposes it seems to be a non issue.

  62. I’ve been using this class more and more lately but I was wondering if it supports bezier curves? I haven’t seen anything in the documentation so I’m pretty sure it doesn’t, but is that something that may end up in a final version?

  63. I am always surprised at the request for a bezier tween. A tween takes a single numeric property and transitions it from one value to another at a rate described by a curve function.

    A bezier necessarily ties together two variables, and x and a y, and tweens them over time. it also requires a series of points (x,y again) to describe the path to plot to. It necessarily takes a different function signature.

    Its a nice animation behavior, but its not a tween.

  64. Bug or Feature?

    First of all thanks for your ‘community work’ Grant – highly appreciated!

    There is a small, but troublesome issue when setting up the sequence of tweens – it is probably worth fixing or clarifying. It seems that depending when autoPlay is set it will or will not take effect. Here are two code sequences to demonstrate the problem:

    // this works playing one second tween after the first one…

    firstTween = new GTween(target, 1, { x:100 }, { ease:Cubic.easeOut } );

    secondTween = new GTween(target, 1, { y:100 }, { ease:Cubic.easeOut, autoPlay:false } );

    firstTween.nextTween = secondTween;

    // this does NOT work starting two tweens immediately…

    firstTween = new GTween(target, 1, { x:100 }, { ease:Cubic.easeOut } );

    secondTween = new GTween(target, 1, { y:100 }, { ease:Cubic.easeOut } );

    secondTween.autoPlay = false;

    firstTween.nextTween = secondTween;

    I took a look at the GTween source, but it was not immediately apparent why this happens, so it figured I will ask first… πŸ˜‰

  65. There are tons of engines out there, including my own, Twease, and all have their strengths and weaknesses, I don’t really see the reason to “take sides” (…unless you have your own engine of course heh)

    It’s kind of like indirect capitalism. We’re *really* not “competing” with each other’s engines, but when you see somebody else that can do it 5x faster and has some new features, you see that there’s room for improvement and it drives you more, creating a better “product”. None of us really get money or try and “sell” our “products”, but the community as a whole gets better options because of it.

    It’s kind of funny that we (the engine developers) are totally cool with each other and actually help each other out here and there, yet it’s the users that are the one’s that get all aggressive about it. But I digress.

    Anyways, good work Grant! I’ll have to take a look sometime, it looks top-notch. You’re more than welcome to checkout the source of Twease on Google code to see if it gives you any ideas or inspiration from its (quite) different approach.

    Keep up the great work!

  66. Hi Andrew,

    I’d like to think part of it is that the type of person that is willing to put a bunch of work into building, documenting, and releasing a major library for free, is unlikely to be the type of person to get all aggressive when someone else does the same.

    I’m definitely not in any kind of race, and I don’t think any of the other tween engine developers are either. It helps that there really isn’t any prize for the winner. πŸ™‚

  67. My favourite part of this is the commentary.

    I particular liked the part about GTween being object agnostic…

    Beautiful!

    Seriously though, some of these features are a “god” sent.

    /sniggers

  68. Hi Grant. Thanks for making a great product. I have been using it for a few weeks in a project with success. I do have a feature request for you:

    It would be nice to be able to link a queue of property changes on the same gTween instance. For instance say I want a sprite to move in a rectangular pattern on the screen. Currently, I am having to set a listener on the tween instance, modify its properties, then call play on it again, all while keeping track of what particular tween took place via a counter.

    Instead you could say something like gTween.propertyQueue = [{x:50}, {y:50}, {x:0}, {y:0}];

    gTween.autoLoop = true;

    gTween.play();

    and it would play thru the propertyQueue array, basically automating the nextTween process while using the same instance of the gTween.

    Dunno, just would be a feature I would like to see added.

    Also, since gTween is leveraging some enterframe/timer event to update the properties on the object being tweened, it would be good to be able to tap into that event so as not to have to duplicate that logic outside of the tween along with some flag to see if we are tweening. I’m lazy πŸ˜‰

  69. j,

    Thanks for the feedback.

    The property queue would actually be fairly easy to add. I’ll think about that. The workflow I would use right now to tween in a square would be to set up two sequenced tweens:

    verticalTween = new GTween(target,0.5,{y:200},{autoReverse:true, autoPlay:false});

    horizontalTween = new GTween(target,0.5,{x:200},{autoReverse:true, autoPlay:false, nextTween:verticalTween});

    verticalTween.nextTween = horizontalTween;

    verticalTween.play();

    In the above, the target will be tween vertically to y=200, then horizontally to x=200, then vertically back to its original y position (because of autoReverse), then horizontally back to its original x, then it will repeat.

    As to your second request, beta2 (ie. the current released version) has a CHANGE event, which fires whenever properties are updated. I believe that is what you are looking for.

  70. Hi Grant,

    Is it possible to create the Mac OS style distorted tween with gTween?

    Great stuff as always

  71. Great stuff Grant. I hope I can contribute to this engine some how.

  72. In the “docs” under the setAssignment() method, there is mention of the GTweenFilter method. Is this method available with the Beta 3 release and, if so, can you please give an example ?

  73. I too am looking for info regarding GTweenFilter.

  74. Hi

    I looked at the documentation, at the samples (they dont have a source view option) at the GTween source and still cannot find how I tween between two colors. I tried:

    var ct:ColorTransform = new ColorTransform(0, 0, 0, 100, 255, 255, 255, 0);

    var tw:GTween = new GTween(theclip, 0.5, { transform:ct }, { ease:Circular.easeOut} );

    But it does not work. I also tried using color:ct. I’m not sure how to use GTween.setAssignment()

    Thanks for any help.

  75. Ok I managed to solve my color question so I put it here for future reference (had to decompile the sample SWFs in the documentation… :$ )

    var coltw:GTween = new GTween(theclip.transform.colorTransform, 0.5, { redOffset:255, greenOffset:255, blueOffset:255 }, { ease:Circular.easeOut } );

    coltw.setAssignment(theclip.transform, “colorTransform”);

  76. That leaves the GTweenFilter question unanswered.

    there is no such class inside GTween.as unfortunately, so we have to assume it’s unreleased.

    It would be great if we could get access to it.

    I started working with GTween on a project, and it’s amazing.

    I thought I could use it for filters, when I read about GTweenfilter, and now I’m right in the middle of the project, and there is no such class… I might have to recode every tween..

    By the way, the .proxy method is amazing !!

    I’ve “subproxyed” the main Sprite classes with this as a getter, and now I’ve just to call “pad.proxy.x” on a pad instance to tween it… marvellous πŸ™‚

  77. Hi,

    This engine looks great, but I would love to see some rotation sample code to better understand what values can be passed to rotationProperties.

    I am looking to know how to rotate a 2D movie clip on the three axis.

    Rich

  78. I’m probably abusing proxies here which is why this doesn’t work. Just thought I post it and see what ya’ll think.

    Basically, I have a 3d scene with moving camera and I am trying to move 3d text, starting from the distance, to float just in front of the camera. I thought I’d be able to do this with GTween’s proxy — by putting a tween on the 3d text and setting it’s proxy’s x/y/z to just in front of the camera each frame.

    The problem is, setting the proxy also seems to change the duration of the tween, making the tween longer. With slow a tween, 3dtext never catches the camera.

    Here’s a hack that fixes it – would be nice to have a config option for this…

    var t:Number;

    t = messageTween.position;

    messageTween.proxy.x = camera.x;

    messageTween.proxy.y = camera.y + 50;

    messageTween.proxy.z = camera.z + 200;

    messageTween.position = t;

  79. I’d also really like a GTweenParams class. Firstly, having a properly typed params object makes its easier for us eclipse developers to guess which param we need without looking at the docs. Secondly it’ll help GTween run (even) faster. Ok, it’ll add a bit the files size but at 4.5k I think you have room.

  80. Joe –

    GTween tries it’s best to adapt to a change in the middle of a tween. There are basically 3 ways it can do this (listed in the order I thought of them originally):

    1) not adjust the duration at all. This sounds great until you think out possible scenarios. For instance, if tweening from 0 to 100 over 1 second, and then changing the destination back to 0 when the tween is 0.95 seconds through. This will cause the tween to suddenly jump back 0 (because it only has 0.05 seconds remaining).

    2) do a smart adjustment. In the above example, GTween could look at the new position, see that it was originally supposed to tween a delta of 1 over a period of 1 second, and apply that ratio to adjust the new duration to 0.95 (because it needs to move from the present position of 0.95 to 0).

    This also sounds great, until you consider that numerous properties may have been changed, and there’s no easy way to determine which property’s “change ratio” should be dominant. Basically it significantly increases the size and complexity of the code, while reducing it’s predictability.

    3) I finally settled on simply resetting the tween’s duration when properties change mid tween. It generally looks pretty decent, it’s predictable, and it still leaves the door open for developers to update the duration at the same time that they update their properties.

    In your case though, it looks like you’d be better off without using a tween. If you’re updating your objects position every frame, a tween won’t help you smooth that motion, because it has no interstitial frames to work with. I hope that makes sense.

  81. The params class is a good idea. It would be handy in FlexBuilder as well. I’ll look at adding that in the next release as something you can optionally use.

  82. Hi Grant. I like your tween engine. I started building my own engine (www.coretween.org) about a year and a half ago after I had many many frustrating moments with Fuse.

    My engine seems to have a lot of similarities with yours and to me that means that I was on the right track with my design. I like the fact how you introduced a ‘nextTween’ property in the gTween to sequence tweens. I used a special class for it called a TweenStack which is like a queue of tweens.

    A couple of months ago I was about to push out a v1.0 of CoreTween but I got side tracked with a big project. Maybe the Christmas will allow me to do some more work.

    Anyway, congrats on a great effort. I might try out your engine on a project in the future!

    – Luke

  83. I’ve been using gtween for a couple of small projects now and I quite like it.

    There are two things that I’ve noticed:

    The first is an, in my opinion, missing function.

    The functions setProperty and setProperties are a pair, but setTweenProperties lacks it’s single property version. Is this intentional?

    Also, I’ve found that I occasionally would like to fire an event a little while *after* a tween is completed.

    The way I did it (I was too lazy to set up a timer) was to add an empty tween after the first one and then listening for completion on that. But that’s not very pretty.

    Would something like a “post-delay” be doable without making things too confused?

  84. GSkinner.beta >= xyz.fullRelease;

    Great job, Grant as always.

    I have been trying to create a simple rollover glow, rollout glow reverse and I’m getting weird results.

    The first rollover works, the first rollout works. But the second rollover starts at a full glow and tweens dim (rather than the reverse). I’ve tried capturing the COMPLETE event and applying a reverse there but still undesired behavior.

    Thanks for you help.

    function onRollover(e:MouseEvent):void{

    outerGlow1Tween.play();

    innerGlowTween.play();

    }

    function onRollout(e:MouseEvent):void{

    outerGlow1Tween.play();

    innerGlowTween.play();

    }

    function handleTweenComplete(e:Event):void{

    innerGlowTween.reverse(false);

    outerGlow1Tween.reverse(true);

    }

    var outerGlow1Tween:GTweenFilter = new GTweenFilter(this,0.6,{blurX:15,blurY:15,strength:1.0}, {filterIndex:1,autoReverse:false,autoPlay:false,ease:Sine.easeOut,delay:0});

    var innerGlowTween:GTweenFilter = new GTweenFilter(this,1,{blurX:10,blurY:10,strength:1.5}, {filterIndex:0,autoReverse:false,autoPlay:false,ease:Sine.easeIn});

    outerGlow1Tween.addChild(innerGlowTween,GTween.DURATION);

    outerGlow1Tween.addEventListener(Event.COMPLETE, handleTweenComplete);

  85. I figured it out… needed a instance.beginning() in the complete handler.

    function handleTweenComplete(e:Event):void{

    innerGlowTween.reverse(false);

    outerGlow1Tween.reverse(false);

    innerGlowTween.beginning();

    outerGlow1Tween.beginning();

    }

    Thanks again, Grant.

    Jeff

  86. I wish I could make up my mind. This rollover/rollout approach is problematic.

    If the mouse moves over the button too quickly, the rollover event will hit but the rollout will not so the glow stays on.

    Is there a better way?

    Thanks,

    Jeff

  87. I don’t know if this is the best approach, but I have solved this by adding the following conditional to both the rollover and rollout handler methods:

    if(outerGlow1Tween.state == GTween.TWEEN_PHASE){

    innerGlowTween.reverse(false);

    outerGlow1Tween.reverse(false);

    }

    My apologies for the frequency, however I thought others would like to know.

    Jeff

  88. first off, thanks for sharing this!

    The proxy property seems like a really convenient way to adjust destination values mid-tween. To make it even more convenient, I extended GTween and added a getter method for destProperties. Now, I can make a tween watch an object’s properties and update itself if they change. Like so:

    myTween.addEventListener(GTween_DM.PROGRESS, updateTween);

    myTween.data = clip_to_mimic;

    function updateTween(e:Event):void

    {

    var twn:GTween_DM = e.target as GTween_DM;

    for (var prop in twn.destProps)

    {

    if(twn.proxy[prop] != twn.data[prop])

    {

    twn.proxy[prop] = twn.data[prop];

    }

    }

    }

    Also, I use the onUpdate functionality in other tweening engines often enough that I added a method to expose the tick event when I need it.

  89. I’ve always loved Tweener, but since GTween came out I’ve been inclined to try it out and maybe switch over.

    I think that the design of GTween is great but I wanted some kind of a manager to provide some global functionality between different GTween instances. I came up with a class that acts a little bit like Tweener but runs GTween at its core.

    I’m interested in hearing what you think and improving it to accommodate GTween’s strengths. Preferences on how tweening should be handled varies widely from person to person … this is just my effort to combine your excellent class with some of the workflow that works best for me.

    http://www.flashdevelop.org/community/viewtopic.php?f=7&t=4172

    I’m not trying to steal any of your thunder, so please don’t feel offended that I’ve used your library this way.

  90. My implementation of addEffect asks for the parameters needed to construct a GTween or GTweenFilter object, but I think it may be cleaner to accept a GTween instance instead.

    The main issue which kept me from building addEffect this way was that once I created a GTween object I did not see a way of finding which properties are being set. If I had some kind of getProperties method I would probably lean in this direction.

    Building it this way would simplify the use of subclasses (such as GTweenFilter) as well adding multiple tweens at once, perhaps to group them together or to set them all as children of each other for a sequenced animation.

  91. In other words, instead of:

    GTweener.addEffect (MySprite, 5, { alpha: 0 } );

    You would write:

    GTweener.addEffect (new GTween (MySprite, 5, { alpha: 0 } );

    If the name bothers you I could also look into something different, like GTweenManager.

  92. Joshua,

    Nice work! I definitely encourage people to extend, modify, and add to GTween – I released it under MIT specifically to make this easy. I’ll check it out, and consider adding a getter for the properties list as per your request above.

    Cheers.

  93. I’ve recently converted to using Gtween as my tween engine, however I’ve ran into a problem which I hope you would be able to explain to me. With Tweener, when I run an oncomplete function, such as

    onComplete:function() { trace(this)};

    It will return me with the object that has been tweened, however for tweener, if I do the same, it will return me Global instead. I was wondering if there’s a way that I can send in the tweened object instead? Because I would like to send the tween object as a parameter for the function it’ll run. Thanks πŸ™‚

  94. Kai – GTween uses AS3’s built in event model, so when you add a listener, it should be scoped to the object it was defined in. The exception to this is anonymous functions which are a bad idea 99% of the time.

    You can also access the target through the tween reference, which in turn is the target of the event object.

    myTween.addEventListener(Event.COMPLETE, handleComplete);

    function handleComplete(evt:Event):void {

    trace(this); // the current timeline.

    trace(evt.target); // the tween.

    trace(evt.target.target); // the tween’s target.

    }

    Hope that’s helpful.

  95. Ah, that clear things up real well, thanks Grant πŸ™‚ Will post up later on as of what I used Gtween for at work, basically I’m building a project for a movie with papervision, and am going to use GTween with it, will update with you later, thanks ^^

  96. Hi,

    I’ve been using the GTween class and it has been great. The application I am writing involves a lot of dynamic tweening, so I’ve used your proxy functionality extensively. However I am having some problems.

    I’ve setup a tween for each of my objects, which just the object and a time. No initial tweens were set. I then save all these tweens to an array. As a user interacts, I use the array to call the proxy function for each tween I have setup. This works great and things move around as expected.

    The problem comes when I want to know when these proxy tweens are done. They don’t seem to trigger the COMPLETE event. For now, I’ve resorted to doing a per frame comparison of the target and proxy’s property to see when the tween is done.

    I hope I’m making this problem clear and you can help me out, Thanks

    – Derek

  97. Hi All,

    Please check the below url, Will I be able to do this animation/text morphing/tween using this library in Flex ?

    http://gireeshkumar.ind.in/temp/2009-01-29_225737.jpg

    I wanted to show that the source work getting transformed to the target work letter by letter.

    Thanks

    Gireesh

  98. Can I use GTween to delay a method call or call a method repeatedly?

  99. Despite Grants comment that anonymous functions are a bad idea 99% of the time I just want to mention that the garbage collection prevention in GTween seems not to work if you use anonymous functions e.g. as a completeListener. Great tool otherwise!

  100. Grant,

    I’m trying to do use bitmapData to capture a clip that I’m rotating using gTween’s rotation, but it only captures it flat! Any idea how to get around that?

    Also, I’m using a motion tween and a blur tweenFilter but I can’t figure out how to turn the blur off when the tween is finished…do you know of any examples that might help?

    Thanks!

  101. Hi,

    This is good. How about the license? If this is free, can you please send me the license file?

    Thank you…

  102. Flasher – the license is MIT (a very permissive open source license), which is in the header of the source file.

  103. It seems the color tween does work if you do it like this:

    var col = new ColorTransform();

    col.color = 0xABCDEF;

    var coltw:GTween = new GTween(clip.transform.colorTransform, 2, {redOffset:col.redOffset, greenOffset:col.greenOffset, blueOffset:col.blueOffset}, { ease:Regular.easeOut } );

    coltw.setAssignment(clip.transform, “colorTransform”);

  104. Grant,

    I’m fairly new to Flash so maybe I’m in over my head by trying to use your great tween engine. I think I can learn the syntax if I can get the package installed properly.

    I placed the “Gtween” folder inside my “Adobe Flash CS4” folder. Your sample fla files run fine. So, I copied and modified your “GTweenFilterDemo.fla” so that it is simply this:

    import com.gskinner.motion.*;

    import fl.motion.easing.*

    // leaderCtr is in the library and is just a circle with radius = 4

    leader_mc = this.attachMovie(“leaderCtr”, “leaderCtr”, 1);

    new GTween(leader_mc,1,{_x:100,_x:500},{ease:Circular.easeIn});

    But when I test it I get several errors starting with these:

    Syntax error. package com.gskinner.motion {

    Attribute used outside class. public class GTween extends EventDispatcher {

    I think this means I’ve installed the package incorrectly. Would you please point me to some docs that will tell me how to install this properly?

    Thanks a lot.

    Bruce

  105. Grant,

    I spoke too soon. The problem I’m having is not the package installation. I had copied an old file into the “Gtween” directory and then modified the code.

    I realized my mistake just as I sent my previous message. The problem now is just that I’m still thinking in AS2 (attachMovie doesn’t work in AS3).

    Thanks anyway.

    Bruce T

  106. Hi Grant,

    I’m not sure how much you have explored haXe, but I thought you would like to know I recently ported GTween. Currently it targets JS, AS2, AS3, and CPP. The port can be found on Google code.

    Brett

  107. On the oficial downloads the timingMode property is missing. But on the downloads at http://code.google.com/p/gtweener/source/browse/trunk/com/gskinner/motion/GTween.as?r=2 the Gtween class has all or most elements.
    The oficial downloads at http://gskinner.com/libraries/gtween/#download should be updated?

  108. This is good. How about the license? If this is free, can you please send me the license file?

Comments are closed.