It worked great...most of the time. The rest of the time, the Tweens would randomly decide to stop -- mid-animation -- without throwing any error as to why. "Most of the time" just doesn't cut it.
The Problem
Here is a simplified example of this situation:package
{
import flash.display.*;
import fl.transitions.*;
import fl.transitions.easing.*;
public class SomeContainer() extends Sprite
{
...
public function animate(o:DisplayObject, x2:int, duration:uint)
{
var tween:Tween = new Tween(
o,
"x",
Regular.easeOut,
someDisplayObject.x,
x2),
duration);
}
}
}
{
import flash.display.*;
import fl.transitions.*;
import fl.transitions.easing.*;
public class SomeContainer() extends Sprite
{
...
public function animate(o:DisplayObject, x2:int, duration:uint)
{
var tween:Tween = new Tween(
o,
"x",
Regular.easeOut,
someDisplayObject.x,
x2),
duration);
}
}
}
When invoking animate(), the tween works most of the time, but randomly it stops.
There is no warning of this problem in the ActionScript 3 reference manual, but this Adobe Devnet article contains some fine print that reads:
Note: Consider variable scope when using the Tween class. If a tween is created in a function, it is important that the variable's scope exists beyond the function itself. If a tween is stored to a variable of local scope, ActionScript garbage collection removes the tween as the function completes, which will likely be before the tween has even begun.
So the problem with this scenario is that the Flash Garbage Collector does not care whether the function-scoped variable is still working asynchronously or not - it destroys objects simply by reference counts and in this case nothing outside of the function references this Tween instance.
The Solution
To fix this, simply scope the Tween instance to a class-level variable (a private attribute) rather than a function-level variable. For example:package
{
import flash.display.*;
import fl.transitions.*;
import fl.transitions.easing.*;
public class SomeContainer() extends Sprite
{
...
public function animate(o:DisplayObject, x2:int, duration:uint)
{
tween = new Tween(
o,
"x",
Regular.easeOut,
someDisplayObject.x,
x2),
duration);
}
private var tween:Tween;
}
}
{
import flash.display.*;
import fl.transitions.*;
import fl.transitions.easing.*;
public class SomeContainer() extends Sprite
{
...
public function animate(o:DisplayObject, x2:int, duration:uint)
{
tween = new Tween(
o,
"x",
Regular.easeOut,
someDisplayObject.x,
x2),
duration);
}
private var tween:Tween;
}
}
This way, the garbage collector sees that something outside of the scope of the function still references the Tween instance created within the function, so it does not destroy the instance.
17 comments:
Thanks! This really helps me alot! :D
thanks, your article confirmed my suspicion about the gc cleaning the tweener up
Awesome man... I would have been looking for hours without this tip. Great help. I wish they made this more obvious to people.
This is simple great. I have been struggling so hard over this problem! Man... tried so many wierd things to get it working.
Thanks a million!
Thanks mate, stupid bug I new it'd be a simple anwer , GC tramp
Thanks. This is way simpler than storing in arrays and then cleaning it all up on MOTION_FINISH. Whew.
Love this article. A simple one for a simple answer. (to a hell of an annoying problem!) Thank you.
Thanks for taking the time to post - very helpful!
It's been said before, but to better represent the scope of people you've helped: Thanks, dude.
Glad this is helping so many people! =) Happy coding everyone!
That has just saved me soo much time and stress! Cheers.
well, doesn't work for me, i mean i got it the way you said it, but it still randomely stops. I use Loader to load images from xml and in the loop which loads images after image i create new Tween, but var definition is outside the function which contains that loop, still the same thing :|
@pau if you are creating a new Tween for each image you load, you would need to store those in an array rather than a var.
The array would then show the garbage collector that the Tween instances are still referenced by something.
If you over-wrote the same var, then only the most recently-created Tween would work without being garbage-collected.
Dude...thank you thank you thank you...I was really pulling my hair out on this exact issue!
Amazing tip! I actually spent hours on this, kept thinking either i'd coded something wrong, or my installation of flash was messing up! Thanks for the article, and i agree with an above comment that things like this should be made more obvious in the documentation!
You are the man. This has been a recurring problem for me for a long time!
Post a Comment
Was this post helpful? Do you have questions about it? Do you want to share your own programming blog? I'd love to read your feedback.