Could anyone advise the best way to trigger a funct开发者_Python百科iont when a movieclip animation finishes? I figure an eventlistener could handle this, but not sure the best way to go about it. Thanks Paul
There are a few ways to go about this:
- Simply call the function from the last frame of your animation.
- Dispatch an event on the last frame of your function and listen for it elsewhere.
- The long but effective / neat / recommended way.
In reference to point 3, I would create a base class for your object. This way you can apply the same logic to multiple elements being animated.
Something like this:
package
{
import flash.display.MovieClip;
import flash.events.Event;
public class AnimatingObject extends MovieClip
{
// constants
public const ANIMATION_COMPLETE:String = "animation_complete";
/**
* Constructor
*/
public function AnimatingObject()
{
addEventListener(Event.ENTER_FRAME, _handle);
}
/**
* Called on dispatch of Event.ENTER_FRAME
*/
private function _handle(e:Event):void
{
if(currentFrame == totalFrames)
{
var evt:Event = new Event(ANIMATION_COMPLETE);
dispatchEvent(evt);
}
}
}
}
Now we can listen for "animation_complete" and do stuff accordingly.
package
{
import flash.events.Event;
public class MyAnimatingObject extends AnimatingObject
{
/**
* Constructor
*/
public function MyAnimatingObject()
{
addEventListener(ANIMATION_COMPLETE, _lastFrame);
}
/**
* Called on dispatch of AnimatingObject.ANIMATION_COMPLETE
*/
private function _lastFrame(e:Event):void
{
trace("i'm done");
}
}
}
It's been awhile since I played with flash. I mostly do flex now, but this should work.
Using the enterFrame Event would be a huge waste of resources, and creating a custom event class is not nessesary.
On the last frame put this
dispatchEvent(new Event("INSERTSTUPIDEVENTNAMEHERE"));
And in your code on your "root"
movieInstanceName.addEventListener( "INSERTSTUPIDEVENTNAMEHERE", someCallBackFunction );
function someCallBackFunction ( e:Event ):void{
trace( "Last frame hit");
}
By making use of an ENTER_FRAME listener, you can tell if a MovieClip has readed the end of playback; you can then take this one step further by wrapping it up in a Wrapper class that will perform the monitoring for you:
public class EndOfMovieClipEventDispatcher extends EventDispatcher
{
private var target : MovieClip;
private var endReachedEvent : String;
public function EndOfMovieClipEventDispatcher(target : MovieClip, endReachedEvent : String = "complete") {
this.target = target;
this.endReachedEvent = endReachedEvent;
target.addEventListener(Event.ENTER_FRAME, onEnterFrameEvent, false, 0, true);
}
public function destroy() : void {
target.removeEventListener(Event.ENTER_FRAME, onEnterFrameEvent);
}
private function onEnterFrameEvent(event : Event) : void
{
if (target.currentFrame == target.totalFrames) {
dispatchEvent(new Event(endReachedEvent));
}
}
}
Usage is pretty straight forward; the call to destroy() is optional thanks to the weak event listener; but recommended if you are finished :)
new EndOfMovieClipEventDispatcher(myMovieClip).addEventListener(Event.COMPLETE, onMovieClipCompleteEvent);
myMovieClip.play();
I do not believe there is an event broadcast at the end of a movieclip, you could always run a script on the last frame of an animation to execute what you want. If you really want to use events, the last frame of the movieclip could execute a script that utilizes dispatchEvent() to send a custom even which can be picked up.
I'm not sure from your post if you have used eventhandlers before, so here's a tutorial on that (I'm not good at explaining, sorry!): http://edutechwiki.unige.ch/en/ActionScript_3_event_handling_tutorial
and for dispatchEvent(): http://www.actionscript.org/resources/articles/204/1/Using-EventDispatcher/Page1.html
You could use an enterframe listener that checks to see if the movieclip's currentFrame == totalFrames, and if they are equal, dispatch a custom event that you make (like TimelineComplete).
Another option would be to create a small component that dispatches your custom TimelineComplete event, and place that component on the final frame of any animation you'd like to monitor. This would allow you to get more creative in the future and add things like a delay before the event is triggered.
You've got a few options, none of which are ideal in my opinion, however they do work, and if done well they won't become unwieldy. The one thing I wouldn't do is add a little bit of code on the last frame. That gets rather hard to keep track of over time.
You can create a custom MovieClip
class that dispatches an event when the movie clip object is on the last frame. You can then make the custom MovieClip
class the base class of your movie clip animation:
CustomMovieClip.as:
package display
{
import events.TimelineEvent;
import flash.display.MovieClip;
import flash.events.Event;
public class CustomMovieClip extends MovieClip
{
private var _isLastFrame:Boolean;
public function get isLastFrame():Boolean { return _isLastFrame }
public function CustomMovieClip()
{
init();
}// end function
private function init():void
{
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}// end function
private function onEnterFrame(e:Event):void
{
if (!_isLastFrame)
{
if (currentFrame == totalFrames)
{
dispatchEvent(new TimelineEvent(TimelineEvent.LAST_FRAME));
_isLastFrame = true;
}// end if
}
else
{
if (currentFrame != totalFrames) _isLastFrame = false;
}// end else
}// end function
}// end class
}// end package
TimelineEvent.as:
package events
{
import flash.events.Event;
public class TimelineEvent extends Event
{
public static var LAST_FRAME:String = "lastFrame";
public function TimelineEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}// end function
public override function clone():Event
{
return new TimelineEvent(type, bubbles, cancelable);
}// end function
}// end class
}// end package
Main.as(document class):
package
{
import display.CustomMovieClip;
import events.TimelineEvent;
import flash.display.Sprite;
import flash.events.Event;
public class Main extends Sprite
{
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}/// end function
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
var customMovieClip:CustomMovieClip = new CustomMovieClip();
customMovieClip.addEventListener(TimelineEvent.LAST_FRAME, onCustomMovieClipLastFrame);
customMovieClip.play();
}// end function
private function onCustomMovieClipLastFrame(e:TimelineEvent):void
{
var customMovieClip:CustomMovieClip = CustomMovieClip(e.target);
customMovieClip.removeEventListener(TimelineEvent.LAST_FRAME, onCustomMovieClipLastFrame);
trace(customMovieClip.isLastFrame); // output: true
}// end function
}// end class
}// end package
if looking for shortest solution i think it would be :
mc.addFrameScript(mc.totalFrames - 1, function():void
{
trace("end of mc");
});
Only check currentFrame
and totalFrames
is not enough for a MovieClip that has multiple scenes. You must also check if it is at the last scene.
function isAtLastFrame(mc:MovieClip):Boolean
{
return currentScene.name == mc.scenes[mc.scenes.length - 1].name && currentFrame == currentScene.numFrames;
}
精彩评论