Reputation: 760
I am trying to make a object, which is a movieclip, move up and down continuously and print its y-axis value whenever it finished a move. The below code works fine.
var tweenUp:Tween = null, tweenDown:Tween = null;
function up():void {
tweenUp = new Tween(person,"y",None.easeNone,person.y,person.y+20,1,true);
tweenUp.addEventListener(TweenEvent.MOTION_FINISH, finishedUp);
}
function down():void {
tweenDown = new Tween(person,"y",None.easeNone,person.y,person.y-20,1,true);
tweenDown.addEventListener(TweenEvent.MOTION_FINISH, finishedDown);
}
function finishedUp(event:TweenEvent):void {
trace(person.y);
tweenUp.removeEventListener(TweenEvent.MOTION_FINISH, finishedUp);
tweenUp = null;
down();
}
function finishedDown(event:TweenEvent):void {
trace(person.y);
tweenDown.removeEventListener(TweenEvent.MOTION_FINISH, finishedDown);
tweenDown = null;
up();
}
up();
However, I am looking for a solution to pass a object to the callback function of listener. I try to use the way shown below but it does not work.
var tweenUp:Tween = null, tweenDown:Tween = null;
var functionFinishedUp:Function = null, functionFinishedDown:Function = null;
function up(object:MovieClip):void {
tweenUp = new Tween(object,"y",None.easeNone,object.y,object.y+20,1,true);
functionFinishedUp = finishedUp(object);
tweenUp.addEventListener(TweenEvent.MOTION_FINISH, functionFinishedUp);
tweenUp.removeEventListener(TweenEvent.MOTION_FINISH, functionFinishedUp);
tweenUp = null;
}
function down(object:MovieClip):void {
tweenDown = new Tween(object,"y",None.easeNone,object.y,object.y-20,1,true);
functionFinishedDown = finishedDown(object);
tweenDown.addEventListener(TweenEvent.MOTION_FINISH, functionFinishedDown);
tweenDown.removeEventListener(TweenEvent.MOTION_FINISH, functionFinishedDown);
tweenDown = null;
}
function finishedUp(object:MovieClip):Function {
return function(event:TweenEvent):void {
trace(object.y);
down(object);
}
}
function finishedDown(object:MovieClip):Function {
return function(event:TweenEvent):void {
trace(object.y);
up(object);
}
}
up(person);
It just goes up and then do nothing because it seems that the listener is removed just after added. Is there any good solution to remove the listener which has parameters passing, after the listener finished its task?
Thanks in advance for any help you are kind enough to provide!
Upvotes: 1
Views: 2310
Reputation: 4870
If you're looking for an easy way to remove an event listener right after the event was received, you can do this:
function listener(event:Event):void
{
// stop listening to the dispatcher for this event type
EventDispatcher(event.target).removeEventListener(event.type, arguments.callee);
// ...and do whatever else you need to do here
}
That line can be used in any event listener.
Another option would be to use Signals (https://github.com/robertpenner/as3-signals). They have an addOnce
method that will only listen once and then remove themselves.
Upvotes: 3
Reputation: 13215
First, I advise against using object
as the name of a variable! Although technically allowed it is semantically meaningless and unhelpfully similar to the reserved class name Object
.
The reason your code isn't working is that you are removing the event handler immediately after adding -- before it ever has a chance to get invoked. You really don't ever have to remove the listeners, because you want them to be invoked every time the respective tweens are complete. If you insist on attaching and detaching the listener functions every iteration you'll have to remove the event listener in the listener function itself. Of course this gets rather tricky with all those closures you're creating and tossing.
In fact you don't need the closures at all, since the tween
objects have a reference to the tweened object in the obj
property. In addition, you only need to create one up tween and one down tween for each target person, and can then just rewind()
and start()
each tween back and forth. You can keep track of which tween goes with which person using a couple of Dictionary objects, which use object references as the keys.
Here's a proof of concept that generates twenty person
s all with their own set of tweens -- but only two handlers are defined and neither of them are closures. I've also combined up
with finishedDown
and down
with finishedUp
:
var upTweens:Dictionary = new Dictionary();
var downTweens:Dictionary = new Dictionary();
for(var i:uint = 0; i < 20; i++) {
// Make a new Person
var person:Person = new Person();
person.y = 100;
person.x = i * 20;
addChild(person);
// Create the tweens but stop them before they can play at all
var top = person.y - 20; // Up is -y in Flash
var bottom = person.y;
var upTween:Tween = new Tween(person, "y", None.easeNone, bottom, top, 1, true);
upTween.stop();
upTween.addEventListener(TweenEvent.MOTION_FINISH, onUpFinished);
var downTween:Tween = new Tween(person, "y", None.easeNone, top, bottom, 1, true);
downTween.stop();
downTween.addEventListener(TweenEvent.MOTION_FINISH, onDownFinished);
// Associate tweens with this person, and start it up!
upTweens[person] = upTween;
downTweens[person] = downTween;
upTween.start();
}
function onUpFinished(e:TweenEvent):void {
var upTween:Tween = Tween(e.currentTarget);
var person:Person = Person(upTween.obj);
var downTween:Tween = Tween(downTweens[person]);
downTween.rewind();
downTween.start();
}
function onDownFinished(e:TweenEvent):void {
var downTween:Tween = Tween(e.currentTarget);
var person:Person = Person(downTween.obj);
var upTween:Tween = Tween(upTweens[person]);
upTween.rewind();
upTween.start();
}
Upvotes: 1