1
votes

In my Flash project I have a movieclip that has 2 keyframes. Both frames contain 1 movieclip each.

frame 1 - Landing
frame 2 - Game

The flow of the application is simple:

  1. User arrives on landing page (frame 1)
  2. User clicks "start game" button
  3. User is brought to the game page (frame 2)
  4. When the game is over, the user can press a "play again" button which brings them back to step 1

Both Landing and Game movieclips are linked to separate classes that define event listeners. The problem is that when I end up back at step 1 after playing the game, the Game event listeners fire twice for their respective event. And if I go through the process a third time, the event listeners fire three times for every event. This keeps happening, so if I loop through the application flow 7 times, the event listeners fire seven times. I don't understand why this is happening because on frame 1, the Game movieclip (and I would assume its related class instance) does not exist - but I'm clearly missing something here.

I've run into this problem in other projects too, and tried fixing it by first checking if the event listeners existed and only defining them if they didn't, but I ended up with unexpected results that didn't really solve the problem.

I need to ensure that the event listeners only fire once. Any advice & insight would be greatly appreciated, thanks!

2

2 Answers

2
votes

If you have two frames with different clips on the same layer, each time that frame "enters", that clip is created. When it "leaves" the clip is removed, but it still will be kept around and not be garbage collected. So the next time the frame enters a different clip is "created" and it gets its own listener. Your best bet is to remove the listeners when you change frames. I usually get around this kind of stuff by having a listener for Event.REMOVED_FROM_STAGE in each class. If it's removed, then you clean up the remaining listeners.

You may also want to experiment with "weak listeners":

addEventListener(GameEvent.GAME_START, gameStartedHandler, false, 0, true);

The "true" makes the link "weak" so if an object is removed, the garbage collector can pick it up. I wouldn't rely on this completely though. Better to manually remove references so you can be sure.

This answer assumes a lot of course. It'd be helpful if you posted code/screenshots/flas to better diagnose.

2
votes

Without seeing the code or knowing what events you are listening for and who/what fires them, it's kind of hard to know for sure.

But, my guess is that the movieclips are not being collected (this is not necessarily a memory leak!) and so, they're still alive and kicking. You should probably have a method that sets them to an "idle" state, so to speak. Meaning, you remove listeners, stop timers, etc. The idea is to put your object in a state where it doesn't run any code.

A simple approach for movieclips and other display objects, which is often good enough, is listening for the ADDED_TO_STAGE and REMOVED_FROM_STAGE events. The idea here is that your object "activates" when it's added to the stage, which in your case would be when you reach frame 2 for your Game class; it "deactivates" when it's removed, that is, when you go back to frame 1.

Something along these lines:

public class Game extends MovieClip {

    private var _timer:Timer;

    public function Game() {
        addEventListener(Event.ADDED_TO_STAGE,init);
        addEventListener(Event.REMOVED_FROM_STAGE,destroy);
    }

    private function init():void {
        //  your init code goes here
        //  just an example:
        _timer = new Timer(33);
        _timer.addEventListener(TimerEvent.TIMER,mainLoop);
        _timer.start();
        trace("init");
    }

    private function destroy():void {
        _timer.stop();
        _timer.removeEventListener(TimerEvent.TIMER,mainLoop);
        trace("destroy");
    }

    private function mainLoop(e:TimerEvent):void {
        //  code for main loop here...
        trace("mainLoop");
    }
}

Check the traces to see if its working correctly. You should see "init" traced out, then "mainLoop" as long as you stay in frame 2 and "destroy" when you go back to frame 1. "mainLoop" should stop tracing at this point.

In addition to that, you might want to check that there's no memory leak (the fact that you have 7 instances does not necessarily mean you have a leak; but at some point, if the GC runds, at least some of them should be released; if this never happens, it's a symptom of a leak; try forcing a GC to see if the number of alive instances goes down; if not, it's quite likely that you have a leak).