View Full Version : TweenEvent.MOTION_FINISH does not fire all the time
random0xff
04-23-2008, 10:00 AM
I have created a class to display images one after the other with a transition in between. It starts a timer. The class has an event listener that handles the timer event to load a new image into a loader. At that moment the timer is stopped. The class has an event listener that handles the complete event for the loader (actually for the associated LoaderInfo). In that method I create a new tween. The class has a third event handler for the motionfinished event of the tween in which the timer is started again.
Here's the flow:
timer event handler > stop timer, start loading > loading complete handler > create tween > motion finished handler > start timer
What happens if I create more than one instance and add them to the stage then one, two or sometimes all of them will fail to call the handler for the motion finished event, thus not starting the timer. So they 'hang' on the third picture, or the 2nd picture in the third iteration (it loops over a finite set of pictures). It seems random, and sometimes they hang in the middle of the tween.
Is this a know problem, is the tween somehow 'unreliable'? I can attach code if needed.
PS. This is my first actionscript 3 script
harosch
04-23-2008, 12:34 PM
could you post your code?
random0xff
04-23-2008, 01:07 PM
Here's the slideshow class. You can instantiate two or three, all you need is a folder with some pictures in it. Set the folder on the instance using the setFolder() method, and add the filenames using the addFile() method.
package {
import flash.display.*;
import flash.events.*;
import flash.net.URLRequest;
import flash.utils.Timer;
import fl.transitions.Tween;
import fl.transitions.TweenEvent;
public class Slideshow extends Sprite {
private var folder:String;
private var files:Array = new Array();
private var timer:Timer;
private var transitionDuration:Number = 0.5;
private var delay:Number = 2;
public function Slideshow() {
for(var i:int = 0; i < 2; i++) {
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.CO MPLETE, loadingComplete);
this.addChild(loader);
}
getChildAt(1).alpha = 0;
timer = new Timer(this.delay * 1000);
timer.addEventListener(TimerEvent.TIMER, timer_Timer);
this.addEventListener(Event.ADDED, function(e:Event) {
if(e.eventPhase == EventPhase.AT_TARGET) {
start();
}
});
}
public function start():void {
if(files.length > 1) {
var loader:Loader = getChildAt(0) as Loader;
if(loader.content == null) {
loader.load(new URLRequest(files[0]));
}
}
if(files.length >= 2) {
timer.start();
}
}
public function stop():void {
timer.stop();
}
private function timer_Timer(e:TimerEvent):void {
timer.stop();
var picture:Loader = this.getChildAt(timer.currentCount % 2) as Loader;
picture.load(new URLRequest(files[timer.currentCount % files.length]));
}
private function loadingComplete(e:Event):void {
if(timer.currentCount == 0) return;
var picture:DisplayObject = this.getChildAt(1) as DisplayObject;
var tween:Tween = new Tween(picture, "alpha", null, picture.alpha, picture.alpha == 0 ? 1 : 0, transitionDuration, true);
tween.addEventListener(TweenEvent.MOTION_FINISH, transitionFinished);
}
private function transitionFinished(e:TweenEvent):void {
timer.start();
}
public function setFolder(value:String):void {
if(value.charAt(value.length - 1) != "/") {
if(value.charAt(value.length - 1) == "\\") {
value = value.substr(0, value.length - 1);
}
value += "/";
}
folder = value;
}
public function addFile(file:String):void {
var regex:RegExp = new RegExp("\.jpg$|\.jpeg$|\.gif$|\.png$");
if(!file.match(regex)) {
throw new Error();
}
this.files.push(folder + file);
}
public function clearFiles():void {
this.timer.stop();
this.files = new Array();
}
}
}
Thanks for looking!
mattb
04-23-2008, 01:08 PM
I've come up against a similar problem in the past. The first thing to check is that the Tween instance does not go out of scope. For example (this is pseudo code)...
private function doTween():void {
var tween:Tween = new Tween(....);
tween.addEventListener(TweenEvent.MOTION_FINISH, onFinished);
}
... will not work reliably - the tween instance goes out of scope when the function finishes (despite having an event listener attached to it) and I've found this unreliable. I make sure that the tween instance is always in scope:
private var tween:Tween;
private function doTween():void {
tween.addEventListener(TweenEvent.MOTION_FINISH, onFinished);
}
Secondly, and this is less likely, but make sure that you're not firing the tween twice. I had a case where placing the mouse ever an object started the tween - if i moved the mouse over, out then over again the tween got messed up as I was trying to kick it off twice.
mattb
04-23-2008, 01:09 PM
After seeing your code I'd definitely recommend declaring the tween outside of the function.
Mazoonist
04-23-2008, 01:13 PM
You must declare your tween outside of the function that uses it:
var tween:Tween;
function foo(event:Event):void {
tween = new Tween(......etc);
}
random0xff
04-24-2008, 07:56 AM
Well, at first I had it the other way around, the motion finished event handler was declared as an anonymous function:
tween.addEventListener(TweenEvent.MOTION_FINISH, function(e:TweenEvent) { timer.start(); });
It is my understanding that this should create a closure such that the tween variable is in the scope of the event handler, right? Either way, that had the same problem.
So I'll try declaring the tween variable on the class level. Thanks so far!
Edit:
It works reliably now, thank you all!
1boeman
08-26-2009, 08:08 PM
I've come accross this numerous times - and logically there's no reason it should happen. It's still an unsolved bug in AS I would say.
Curtisch
03-24-2010, 11:04 PM
Thanks to the folks who responded to this. It was exactly what I needed to solve a similar problem where a tween would work half way, then go out of scope & stop.
|
vBulletin® v3.8.5, Copyright ©2000-2012, Jelsoft Enterprises Ltd.