Stefan4024
Stefan4024

Reputation: 694

How to automatically delete Event Listener from an object in AS3

I am working on small flash game. The game contains 20 levels and main menu. The transition between levels is made by deleting every object on the frame and also all event listeners. Then the code adds objects from the next level...

Catching and the removing event listeners is done by this code:

override public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
    {
        super.addEventListener(type, listener, useCapture, priority, useWeakReference);
        arrListeners.push({type:type, listener:listener});

    }

    private function clearEvents():void
    {
       for(var i:Number = 1; i<arrListeners.length; i++){
          if(this.hasEventListener(arrListeners[i].type))
        {
             this.removeEventListener(arrListeners[i].type, arrListeners[i].listener);
          }
       }
       arrListeners = []
    }

This code overrides internal addEventListeners and makes every Listener to be added in an array. Second function checks if the EventListeners is still there(not prevoiusly removed) and the just remove every Listener from the array.

This code works fine for EventListeners that are assigned to the stage. However, when an EventListener is assigned directly to an Object then it's not added to the array, so it doesn't get removed automatically later.

I know that when you remove the object, also you remove the Event Listeners assigned to it. But when I add that object again the Listeners run twice. You can freely move through levels, so you can go back and forth. And when you go back I recieve problems. System is overused and is woring slower, because the amount of Event Listeners that are running is doubled.

So, can you modify this code or give me an advice how can I catch EventListeners that are assigned to Object and eventually remove them.

Code:

package

{
     Public Class Main extends MovieClip
     {
          Public function Main()
          {
               Intro();
          }
          Private function Intro():void
          {
             //Constructor contains a lot of addChild and a EventListeners. So I will upload what I think i important for this problem.
             Play_btn.addEventListener(MouseEvent.CLICK, clicked);
             function clicked (e:MouseEvent):void
             {
                 clearEvents();
                 clearChild(); // function that removes all children on stage
                 FirstLevel();
              }
           }
           Private function FirstLevel():void
           {
              //Also adding children and EventListeners, that affect the gameplay
              Next_level_btn.addEventListener(MouseEvent.CLICK, clicked1);
              function clicked1 (e:MouseEvent):void
             {
                 clearEvents();
                 clearChild();
                 SecondLevel();
              }
              Main_Menu_btn.addEventListener(MouseEvent.CLICK, clicked1);
              function clicked1 (e:MouseEvent):void
              {
                 clearEvents();
                 clearChild(); 
                 Intro();
               }
            }

And so on for the next 20 levels.

Thanks in advice.

Upvotes: 1

Views: 2697

Answers (2)

BadFeelingAboutThis
BadFeelingAboutThis

Reputation: 14406

Removing an object (removeChild(object)) does NOT automatically remove it's event listeners. You would need to do that yourself. Something like this could work:

in your class constructor:

super.addEventListener(Event.ADDED_TO_STAGE,addedToStage,false,0,true);  //only if you want the listeners added back again the next time this object is added to the stage  eg. addChild(this)
super.addEventListener(Event.REMOVED_FROM_STAGE,removedFromStage,false,0,true);

The handlers:

//this runs whenever the object is added to the display list
//if you don't want the listeners re-added, remove this function.
private function addedToStage(e:Event):void {
    for(var i:int=0; i<arrListeners.length; i++){
        super.addEventListener(arrListeners[i].type, arrListeners[i].listener, arrListeners[i].useCapture, arrListeners[i].priority, arrListeners[i].useWeakReference);
    }
}

//this runs whenever the object is removed from the display list
private function removedFromStage(e:Event):void {
    for(var i:int=0; i<arrListeners.length; i++){
        super.removedEventListener(arrListeners[i].type, arrListeners[i].listener, arrListeners[i].useCapture);
    }

    //OR if you want the listeners gone forever, use your clearEvents() method instead of the for loop above
}

This would make your listeners stop listening when the item is removed from the display list, and re-add them when added. You'd have to modify your array to include the other listener information like capture phase and weakReference. If you don't want them added again, just call your clearEvents() in the removedFromStage handler and take out the addedToStage listener/handler altogether.

This is assuming that the code you posted (and my additions) is the base-class of all the object you want it applied to.

Upvotes: 0

Barış Uşaklı
Barış Uşaklı

Reputation: 13532

Arrays indices start from 0, clearEvents should be :

 private function clearEvents():void
 {
     for(var i:int= 0; i<arrListeners.length; i++){
        if(this.hasEventListener(arrListeners[i].type))
        {
             this.removeEventListener(arrListeners[i].type, arrListeners[i].listener);
        }
     }
     arrListeners = []
 }

Not sure if that will fix your problem though. If you have event listeners that are created when you add new objects you should remove those listeners when the object is destroyed/removed.

Upvotes: 0

Related Questions