EnterFrame handler to run only while timeline is stopped on a certain frame - actionscript-3

I have some code in a frame. It's basically
this.addEventListener(Event.ENTER_FRAME, handleUpdate);
function handleUpdate(e:Event):void
{...}
I want the code to be executed only when on that frame. But the handleUpdate function keeps getting called even when I'm out of that frame.
The timeline is stopped on this frame, and I want the handleUpdate to run continuously until the timeline moves off the frame.

If you're set on having the code for this on the frame in question, then you could do this:
var tmpCurFrame:int = currentFrame; //store the current frame
this.addEventListener(Event.ENTER_FRAME, handleUpdate)
function handleUpdate(e:Event):void {
if (tmpCurFrame != currentFrame) { //if the frame has changed, stop the frame handler
this.removeEventListener(Event.ENTER_FRAME, handleUpdate);
return;
}
//do your code
}
handleUpdate(null);
As an aside, it's much cleaner to have a document class and other class files that manage this sort of thing instead of using frame scripts. But if you all you're looking for is a quick and dirty tweak to your existing code, this should do the trick.

Haven't you heard about addFrameScript ?
It's perfect for your needs.
var desiredFrame = 25; // Timeline frame (starts from 1)
this.addFrameScript(desiredFrame-1, onFrame25); // 1st param is zero-based
function onFrame25():void
{
trace("I'm on frame", desiredFrame);
}

There's a few things you should consider with your approach:
Adding an ENTER_FRAME listener on the frame you care about happens after you enter that frame, so if the movieclip is playing you won't get an ENTER_FRAME event until the next frame (at which time it may have moved off that frame).
Be aware that code on a frame executes every time the playhead enters that frame, and you should be careful to remove listeners when appropriate for memory leak purposes.
So one approach would be to place this code on the frame in question - note that it also nicely removes its listener:
var thisFrame:int = currentFrame;
function handleUpdate(e:Event) {
if (currentFrame==thisFrame) {
// your code here...
} else {
// remove listener if we moved off the frame
removeEventListener(Event.ENTER_FRAME, handleUpdate);
}
}
// call it now because the listener won't fire until next frame
handleUpdate(null);
// add listener in prep for next ENTER_FRAME, though note that
// if we move off this frame, then the listener is removed above
addEventListener(Event.ENTER_FRAME, handleUpdate);
Another approach would be adding the following code on frame 1, so the listener always runs and is never cleaned up, and only performs the code when on frame 12:
addEventListener(Event.ENTER_FRAME, handleUpdate);
function handleUpdate(e:Event):void
{
if (currentFrame==12) {
// your code here...
}
}

Related

How to play animation and then play reverse on hover, start playing again until end on hover out using in Adobe Animate (Flash)?

Sorry this is so specific but I have combed through so many pages and videos and tutorials and can't figure this out.
I have all of my animations within a MovieClip. In the movie clip is also a stage sized white square button with the instance name "btn". Back on the main stage I have a second layer called "actions" with the following code applied to the first (and only) frame. It's not working. At all. (HUGE) tia
stop(); // this will stop the movie from playing at the start
btn.addEventListener((MouseEvent.ROLL_OVER, playMovie);
btn.addEventListener((MouseEvent.ROLL_OUT, stopMovie);
function playMovie(evt:MouseEvent):void {
play();
}
function stopMovie(evt:MouseEvent):void {
stop();
}
The problem is when you say play(); or stop(); which object are you really commanding? Your playMovie function could be in theory used to control many MovieClips at once, in different ways, so be specific with your commands...
btn.play(); //start the playback of "btn" MC
btn.stop(); //stop the playback of "btn" MC
Also consider using MOUSE_OVER/OUT instead ROLL_OVER/OUT etc but whatever works for you.
For reversing you will use btn.prevFrame(); together with an ENTER_FRAME event function. This function reads your Document settings for the FPS. For example, if you set 30 frames-per-sec then whatever instructions you put inside the event function will be processed 30 times per second.
See this other Answer for advice about reversing the playback of a MovieClip.
#VC.One is correct in how you should implement a solve to your issue, however in response to your comment on their answer, I thought I would demonstrate how to implement this fully for you - incase they don't.
var removeUpdate = false;
btn.addEventListener(MouseEvent.MOUSE_OVER, playMovie);
btn.addEventListener(MouseEvent.MOUSE_OUT, stopMovie);
function playMovie(evt:MouseEvent):void {
// Stop rewinding the movie clip and play it
if(removeUpdate){
stage.removeEventListener(Event.ENTER_FRAME, update);
removeUpdate = false;
}
// play our button
btn.play();
}
function stopMovie(evt:MouseEvent):void {
// stop our button
btn.stop();
// ... and rewind it
stage.addEventListener(Event.ENTER_FRAME, update);
removeUpdate = true;
}
function update(evt: Event){
// moves the button movie clip backwards one frame.
btn.prevFrame();
// If we have finished rewinding the movie clip, then stop
if(btn.currentFrame == 1){
stage.removeEventListener(Event.ENTER_FRAME, update);
removeUpdate = false;
}
}
It is important that you remove the update event because if you don't, the movie will never play again, because it will go one frame forward and then back again every frame due to; btn.play(); btn.prevFrame();

Is there any way to remove and addListener based on a timer?

How would i go about disabling the controls for a character for 5 seconds after they've hit an object and then immediatly afterwards allowing the character to move freely? So far, i've been able to get the code for the hitTest done and the removing keyboard controls (the easy part) but now i'm stumped as to how i would set the keyboard controls on a timer. Any help? My code for the hitTest and removing of controls is as follows.
if (player.hitTestObject(folder))
{
trace("success!");
addChild(myInfo);
//stops player movement
stage.removeEventListener(KeyboardEvent.KEY_DOWN,kD);
}
else
{
addChild(myInfo);
removeChild(myInfo);
}
The other problems in the code are of no concern right now (such as the add/remove child in the else function.
private var m_tmr:Timer = new Timer(5000, 1);
private function someFunc():void
{
if (player.hitTestObject(folder))
{
trace("success!");
addChild(myInfo);
//stops player movement
stage.removeEventListener(KeyboardEvent.KEY_DOWN,kD);
m_tmr.addEventListener(TimerEvent.TIMER, onTimer);
m_tmr.start();
}
else
{
addChild(myInfo);
removeChild(myInfo);
}
}
private function onTimer(pEvent:TimerEvent):void
{
m_tmr.removeEventListener(TimerEvent.TIMER, onTimer);
stage.addEventListener(KeyboardEvent.KEY_DOWN, kD);
}
Adding/removing the timer's event listener each time is for purposes of efficiency; it's not critical that you keep adding/removing it like that.

AS3 Button to stop Movieclip after its finished playing

Ok, so I'm a beginner at AS3 and Flash and I managed to put this code together for an animation. A Button called start_btn is supposed to start and stop a movieclip called main_mc. On the first click of the Button, the Movieclip is supposed to play (which it does), however on the second click, the movie stops in the middle of its animation (which I don't want). My question is, when you click the Button a second time, how can i get the Movieclip to finish playing its animation then stop on the last frame?
I thought about using if (main_mc.currentFrame == main_mc.totalFrames); {main_mc.stop(); but the Movieclip still does not stop on the last frame. The Movieclip itself also has a gotoAndPlay(2); command on the last frame so that the animation repeats before the Button is clicked a second time.
here is the code i have:
`start_btn.addEventListener(MouseEvent.CLICK, mainaniS);
function mainaniS(event:MouseEvent):void
{
main_mc.play();
start_btn.removeEventListener(MouseEvent.CLICK, mainaniS);
start_btn.addEventListener(MouseEvent.CLICK, mainaniSt);
}
function mainaniSt(event:MouseEvent):void
{
if (main_mc.currentFrame == main_mc.totalFrames);
{main_mc.stop();}
start_btn.removeEventListener(MouseEvent.CLICK, mainaniSt);
start_btn.addEventListener(MouseEvent.CLICK, mainaniS);
}`
Try main_mc.gotoAndStop(main_mc.totalFrames).
I was going to provide a quick and dirty solution, but decided instead to try and explain a few of the issues with your current implementation and attempt to refactor and explain and better one. Unfortunately I don't have access to Flash right now, so the code is untested.
You're adding and removing event listeners often, which is generally a bad idea. Instead, since you're using a single button to perform multiple functions it would make sense to track the button state in a separate variable. In this case, a boolean for whether or not the movieclip is currently playing.
var playing:Boolean;
Now we can combine the mainaniS and mainaniSt into one and perform a different action based on whether or not the movieclip is playing, and just keep the one eventlistener on the button. I've also taken the liberty of naming the method something more meaningful:
start_btn.addEventListener(MouseEvent.CLICK, onStartClick);
function onStartClick(event:MouseEvent):void
{
if(playing) {
playing = false;
}
else {
playing = true;
main_mc.play();
}
}
You may be wondering why we don't call main_mc.stop() in the first block: the reason is that you don't want to stop the movieclip as soon as you click the button, but after the movieclip has finished playing if the button has been clicked. Therefore, we just set playing to false to indicate that we want it to stop later.
Finally, we need to make sure the movieclip stops upon completion, but only if playing is false. To do this we add a listener to movieclip that is called every frame, and checks whether playing is false, and if it's on the last frame. Note that the last frame is actually totalFrames - 1: this is because the frame numbers start from zero rather than one (i.e. if totalFrames is 3, the frame numbers will be 0, 1, 2).
main_mc.addEventListener(Event.ENTER_FRAME, animate);
function animate(event:Event):void {
if(!playing && main_mc.currentFrame == main_mc.totalFrames - 1) {
main_mc.stop();
}
}
All the refactored code together:
var playing:Boolean;
start_btn.addEventListener(MouseEvent.CLICK, onStartClick);
main_mc.addEventListener(Event.ENTER_FRAME, animate);
function onStartClick(event:MouseEvent):void
{
if(playing) {
playing = false;
}
else {
playing = true;
main_mc.play();
}
}
function animate(event:Event):void {
if(!playing && main_mc.currentFrame == main_mc.totalFrames - 1) {
main_mc.stop();
}
}

external swf should unload when reaches final frame

I have a swf file loaded into a main movie. When the child is finished playing, ie reaches its final frame, I would like the swf to unload. Can anyone tell me what bits I can add to this code?
//start button
start_button_aboriginal.addEventListener(MouseEvent.CLICK, fl_ClickToLoadUnloadSWF_3,false,0,true);
import fl.display.ProLoader;
var fl_ProLoader_3:ProLoader;
var fl_ToLoad_3:Boolean = true;
function fl_ClickToLoadUnloadSWF_3(event:MouseEvent):void
{
//ADDED APR02 START
fl_ProLoader_3.contentLoaderInfo.addEventListener(Event.INIT, childInitHandler);
fl_ProLoader_3.load(new URLRequest("myths/myth_aboriginal.swf"));
//ADDED APR02 END
if(fl_ToLoad_3)
{
fl_ProLoader_3 = new ProLoader();
fl_ProLoader_3.load(new URLRequest("myths/myth_aboriginal.swf"));
addChild(fl_ProLoader_3);
fl_ProLoader_3.x = 114;
fl_ProLoader_3.y = 41;
}
else
{
removeChild(fl_ProLoader_3);
fl_ProLoader_3.unloadAndStop();
fl_ProLoader_3 = null;
}
// Toggle whether you want to load or unload the SWF
fl_ToLoad_3 = !fl_ToLoad_3;
}
You could
1) Use the undocumented addFrameScript function defined in the MovieClip class to place a callback on the last frame of the child SWF. Useful if you don't have control over the code in your loaded SWF.
addFrameScript() has the following signature:
addFrameScript(frameNumber, callback); //frameNumber is zero-based (unlike in the Flash authoring suite, here you would enter 0 to refer to the first frame, and 1 for the second.)
In the parent SWF, add the following:
function fl_ClickToLoadUnloadSWF_3(event:MouseEvent):void {
...
fl_ProLoader_3.contentLoaderInfo.addEventListener(Event.INIT, childInitHandler);
fl_ProLoader_3.load(new URLRequest("myths/myth_aboriginal.swf"));
...
}
function childInitHandler(event:Event):void {
MovieClip(fl_ProLoader_3.content).addFrameScript(MovieClip(fl_ProLoader_3.content).totalFrames-1, unloadChild);
}
function unloadChild() {
fl_ProLoader_3.unloadAndStop();
}
If you're worried about addFrameScript going away - don't be. When you put code on the timeline, all that code is actually compiled into functions in the document class, with frame listeners added via addFrameScript.
Remember to define function unloadChild().
function unloadChild():void {
fl_ProLoader_3.unloadAndStop();
}
-OR-
2) Dispatch an event from your loaded SWF when it reaches the final frame.
In last frame of child SWF:
this.dispatchEvent(new Event("lastFrameReached"));
In parent SWF, add the following:
fl_ProLoader_3.content.addEventListener("lastFrameReached", unloadChild);
-OR-
3) Subscribe to the ENTER_FRAME event of the child and check if the child is on its last frame.
In parent SWF, add the following:
fl_ProLoader_3.content.addEventListener(Event.ENTER_FRAME, checkIfEnded);
function checkIfEnded(event:Event):void {
if (fl_ProLoader_3.content.currentFrame == fl_ProLoader_3.content.totalFrames) {
unloadChild();
}
}
I personally prefer addFrameScript - seems to me a cleaner solution. Callback runs once, you don't have to poll and you don't need to modify the child SWF.
There are a number of ways to solve this, and it has been asked many times...
Unload child swf on last frame of child swf
When External SWF has reached Frame X, how do I unload it?
That said, one way you could resolve this without creating event listeners on the child swf, is by periodically checking the child swf for the current frame. If it's the last one on the swf, call the unload method.
// once every second, indefinitely.
var tick:Timer = new Timer(1000, 0);
tick.addEventListener(TimerEvent.TIMER, checkSWF);
tick.start();
//Load something to the stage.
var loader:Loader = new Loader();
loader.load(new URLRequest("child.swf"));
addChild(loader);
function checkSWF(e:Event):void {
if (loader.content.currentFrame == loader.content.totalFrames) {
tick.stop(); // stop the timer
loader.unloadAndStop();
}
}

Dispatch event on every frame for MovieClip

I have a Movie Clip, and I need to stop the movie when it's reaches a certain frame. To do this, I need to add an event listener that will dispatch when that specific movie clip enters a new frame (as opposed to the whole animation ENTER_FRAME).
bar.addEventListener(Event.ENTER_FRAME, function(e:Event) {
var b:MovieClip = MovieClip(e.currentTarget);
if(b.currentFrame == mp.getPopularity())
b.stop();
});
Any ideas?
Thanks.
Try this;
A simple function:
function playUntil(target:MovieClip, frame:int):void
{
target.stopFrame = frame; // Works because MovieClip is dynamic.
target.addEventListener(Event.ENTER_FRAME, _checkFrame);
}
With the listening function:
function _checkFrame(e:Event):void
{
var m:MovieClip = e.target as MovieClip;
if(m.currentFrame == m.stopFrame)
{
m.stop();
m.removeEventListener(Event.ENTER_FRAME, _checkFrame);
}
}
Apply it to all your instances:
playUntil(instance1, 15);
playUntil(instance2, 27);
playUntil(instance3, 113);
You should remove the event listener when it's no longer needed, otherwise you risk memory leaks. An anonymous function can make this difficult, though you might be able to do it with arguments.callee.
bar.addEventListener(Event.ENTER_FRAME, function(e:Event) {
var b:MovieClip = MovieClip(e.currentTarget);
if(b.currentFrame == mp.getPopularity()){
b.stop();
b.removeEventListener(e.type, arguments.callee);
// ^^ this may work to remove your anonymous listener.
}
});
There's another way to go about this, though. Does mp.getPopularity() change frequently? If it does not change after bar is told to play() then you could use addFrameScript. Just remember that addFrameScript is 0-indexed, so adding a script to frame 1 means you have to pass 0... so if an action is to happen on mp.getPopularity() then you'll have to pass mp.getPopularity() - 1.
var framescript:Function = function():void{
bar.stop();
bar.addFrameScript(bar.currentFrame-1, null);
// ^^ nulling the framescript after
// ^^ it is no longer needed.
}
bar.stop(); // Generally a good idea to call stop before calling addFrameScript
bar.addFrameScript(mp.getPopularity() - 1, framescript);
bar.gotoAndPlay(1); // or wherever it needs to start from.
This is a more precise solution, but you do have to remember to clean up your framescript after you're done, if you plan to use this same bar instance later with a different mp.getPopularity() value.