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.
Thanks! This really helps me alot! :D
ReplyDeletethanks, your article confirmed my suspicion about the gc cleaning the tweener up
ReplyDeleteAwesome man... I would have been looking for hours without this tip. Great help. I wish they made this more obvious to people.
ReplyDeleteThis is simple great. I have been struggling so hard over this problem! Man... tried so many wierd things to get it working.
ReplyDeleteThanks a million!
Thanks mate, stupid bug I new it'd be a simple anwer , GC tramp
ReplyDeleteThanks. This is way simpler than storing in arrays and then cleaning it all up on MOTION_FINISH. Whew.
ReplyDeleteLove this article. A simple one for a simple answer. (to a hell of an annoying problem!) Thank you.
ReplyDeleteThanks for taking the time to post - very helpful!
ReplyDeleteThis comment has been removed by a blog administrator.
ReplyDeleteIt's been said before, but to better represent the scope of people you've helped: Thanks, dude.
ReplyDeleteGlad this is helping so many people! =) Happy coding everyone!
ReplyDeleteThat has just saved me soo much time and stress! Cheers.
ReplyDeletewell, 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 :|
ReplyDelete@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.
ReplyDeleteThe 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!
ReplyDeleteAmazing 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!
ReplyDeleteYou are the man. This has been a recurring problem for me for a long time!
ReplyDeleteDitto to all of the above - what a nightmare scenario! I have been checking my event listeners, tweens, class structures - everything!!! THANK YOU FOR THIS VERY, VERY VALUABLE ARTICLE.
ReplyDeleteWhat if my variables are set globally and it still freezes...
ReplyDelete@Jerome can you share relevant code snippets and I will take a look :)
ReplyDeletethank you!
ReplyDeletethanks a lot!
ReplyDeleteThanks a lot!
ReplyDeleteCheers from Latvian games developers! :)
Hi! I have a situation like Jerome. I've sent you an email to your gmail account. Didn't post it here because the code was too long. I've set the tween variables globally but it still stops randomly.
ReplyDeleteSeriously man, this has saved me a lot of time searching.
ReplyDeleteIt was one between only two answers i could find on google.
Well, it seems i have to get knowing the mr. Garbage collector...
Thank you so much!!
ReplyDeleteI had multipe tweens and sometimes half of them would all stop simultaneously. I would have never guessed it was the garbage collector.
So I created a global array for all my tweens.
Thanks for this, it was driving me crazy. Appreciated.
ReplyDeleteTks a lot
ReplyDeleteThanks...Helpfullll!
ReplyDelete