Search code examples
actionscript-3flashflash-cc

kill unnamed generated instances after time in flash (as3)


I am making a little game, where instances are spawned and I want them to be killed after two seconds. The problem I was running into is that the instances have a generated name, and I don't know how to talk to them after they have spawned.

I tried things like Timeout or a normal Timer, but I still can't talk to them.

function spawn(): void {
    if (Math.floor(Math.random() * 70) == 0) {
        plane = new Plane();
        plane.x = Math.random() * (stage.stageWidth - 100) + 50;
        plane.y = Math.random() * (stage.stageHeight - 100) + 20;
        plane.addEventListener(MouseEvent.CLICK, shoot);
        var killtimer: Timer = new Timer(2000);
        killtimer.addEventListener(TimerEvent.TIMER, timerListener);
        //setTimeout(kill, 2000);
        addChild(plane);
        killtimer.start();
    }

    if (Math.floor(Math.random() * 30) == 0) {
        bird = new Bird();
        bird.x = Math.random() * (stage.stageWidth - 100) + 50;
        bird.y = Math.random() * (stage.stageHeight - 100) + 20;
        bird.addEventListener(MouseEvent.CLICK, shoot);
        //setTimeout(kill, 2000);
        addChild(bird);
    }

    if (Math.floor(Math.random() * 300) == 0) {
        g_bird = new Golden_bird();
        g_bird.x = Math.random() * (stage.stageWidth - 100) + 50;
        g_bird.y = Math.random() * (stage.stageHeight - 100) + 20;
        g_bird.addEventListener(MouseEvent.CLICK, shoot);
        //setTimeout(kill, 2000);
        addChild(g_bird);
    }
}

function timerListener(e: TimerEvent): void {
    trace("Killtimer: " + flash.utils.getQualifiedClassName(e.currentTarget));
    e.currentTarget.parent.removeChild(e.currentTarget);  <- Problem e is the timer, not the instance
}

Can anybody help me?


Solution

  • I'll present you with two options.

    1. (Easy-ish way) - Use dynamic properties and an Array (or Vector)

    Create an Array or Vector to hold all your spawned items.

    var items:Array = [];
    

    Then, when you spawn your items, add them to the array/vector, and give them a made up property, let's call it duration and it will store the current time plus 2 seconds:

    plane = new Plane();
    items.push(plane);
    plane.duration = flash.utils.getTimer() + 2000; //this is when the item expires and can be removed
    

    Then, make ONE master timer that ticks 10 times per second (or however long you'd like)

    var mainTimer:Timer = new Timer(100);
    mainTimer.addEventListener(TimerEvent.TIMER, timerListener);
    mainTimer.start();
    

    Or instead of that, you could listen every frame: (more accurate, but less performant)

    this.addEventListener(Event.ENTER_FRAME, timerListener);
    

    In the timer tick handler (or enter frame handler), check the duration of each item and see if it needs to be removed yet:

    function timerListener(e:Event):void {
        //get the current time
        var time:Number = flash.utils.getTimer();
    
        //iterate backwards through all the items
        for(var i:int=items.length-1;i--){
            //if the current time is the same or greater
            if(items[i]).time >= time){
                removeChild(items[i]); //remove it from the screen
                items.splice(i,0); //delete it from the array
            }
        }
    }
    

    2. Create a base class that does all the work

    The best way to do this, would be to make a base class for all those objects who you wish to last a specific duration.

    You could create a file called MyBaseClass.as next to your .fla. In that file, you could do something like this:

    package {
        import flash.display.Sprite;
        import flash.utils.Timer;
        import flash.events.Event;
        import flash.events.TimerEvent;
    
        public class MyBaseClass extends Sprite {
            private var timer:Timer = new Timer(2000,1);
    
            public function MyBaseClass():void {
                this.addEventListener(Event.ADDED_TO_STAGE, addedToStage, false, 0, true);      timer.addEventListener(TimerEvent.TIMER, kill,false,0,true);
            }
    
            private function addedToStage(e:Event):void {
                timer.start();
            }
    
            private function kill(e:Event):void {
                if(parent) parent.removeChild(this);
            }
        }
    }
    

    Anything that extends this base class, will kill itself after 2 seconds of being added to the display.

    To extend it, right click your assets in the library (in FlashPro), and in the "export for actionscript" settings, put MyBaseClass in the base class text field.

    enter image description here


    Of course there are other ways to accomplish this as well, and you could also do some combination of the two I've shown, as having just one timer is more efficient than every item having it's own timer running.

    3. Use setTimeout (not ideal)

    If want to just understand how you could use setTimeout, this would be the correct usage:

    plane = new Plane();
    setTimeout(kill, 2000, plane);
    

    function kill(itemToKill:DisplayObject):void {
        removeChild(itemToKill);
    }