flash event listener for movieclip end?
Asked Answered
C

8

9

Could anyone advise the best way to trigger a functiont when a movieclip animation finishes? I figure an eventlistener could handle this, but not sure the best way to go about it. Thanks Paul

Caroylncarp answered 12/5, 2011 at 16:14 Comment(5)
dealing something similar at the moment. Easiest option is to use an event listener for the ENTER_FRAME event and check if the currentframe is the last one (e.g. function checkLastFrame(event:Event):void{ trace(currentFrame == totalFrames); } ), but depending on how simple or complex, you might find the following resources handy: adobe.com/devnet/flash/articles/timelinewatcher.html , bytearray.org/?p=603 , tink.ws/blog/framelabelmovieclip-uiframelabelmovieclipShine
Why can't you just fire an event on the last frame?Epiphyte
@Epiphyte Or even dispatch an event on the last frame and listen for it elsewhere.Ondrea
I'm coming at it from an as2 angle - so triggering an event from last frame was first thing I thought of, but i cant figure how to trigger a function in the root from a dynamically loaded movieclipCaroylncarp
I've often wondered why Flash doesn't have a built-in event for this, like it does for videos when they finish playing.Niacin
O
11

There are a few ways to go about this:

  1. Simply call the function from the last frame of your animation.
  2. Dispatch an event on the last frame of your function and listen for it elsewhere.
  3. 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");
        }
    }
}
Ondrea answered 12/5, 2011 at 23:38 Comment(0)
E
3

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");
}
Epiphyte answered 13/5, 2011 at 17:46 Comment(1)
This answer works if you put code on the timeline in Flash, but you may not have access to the original .fla or even want to put code on the timeline because that can be confusing sometimes. Plus I wouldn't exactly call the enterFrame event a "huge" use of resources.Niacin
D
2

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();
Dallis answered 12/5, 2011 at 21:0 Comment(0)
N
0

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

Nide answered 12/5, 2011 at 16:25 Comment(0)
E
0

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.

Eirena answered 12/5, 2011 at 16:40 Comment(0)
C
0

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
Corral answered 12/5, 2011 at 21:55 Comment(0)
P
0

if looking for shortest solution i think it would be :

        mc.addFrameScript(mc.totalFrames - 1, function():void 
        {
            trace("end of mc");
        });
Psoriasis answered 12/4, 2012 at 3:22 Comment(0)
E
0

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;
}
Emblaze answered 13/4, 2013 at 12:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.