убить безымянные сгенерированные экземпляры после времени во флэш-памяти (as3)

Я делаю небольшую игру, в которой создаются экземпляры, и я хочу, чтобы они были убиты через две секунды. Проблема, с которой я столкнулся, заключается в том, что у экземпляров есть сгенерированное имя, и я не знаю, как с ними разговаривать после их появления.

Я пробовал такие вещи, как Timeout или обычный таймер, но все еще не могу с ними разговаривать.

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
}

Кто-нибудь может мне помочь?


person themrnjs    schedule 09.10.2015    source источник


Ответы (2)


Я представлю вам два варианта.

1. (Простой способ) - используйте динамические свойства и массив (или вектор)

Создайте массив или вектор для хранения всех созданных вами предметов.

var items:Array = [];

Затем, когда вы создаете свои элементы, добавляете их в массив / вектор и даете им созданное свойство, назовем его длительностью, и оно сохранит текущее время плюс 2 секунды:

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

Затем создайте ОДИН мастер-таймер, который срабатывает 10 раз в секунду (или сколько угодно долго).

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

Или вместо этого вы можете прослушивать каждый кадр: (более точно, но менее производительно)

this.addEventListener(Event.ENTER_FRAME, timerListener);

В обработчике такта таймера (или введите обработчик кадра) проверьте продолжительность каждого элемента и посмотрите, нужно ли его еще удалить:

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. Создайте базовый класс, который сделает всю работу

Лучший способ сделать это - создать базовый класс для всех тех объектов, для которых вы хотите использовать определенную продолжительность.

Вы можете создать файл с именем MyBaseClass.as рядом с вашим .fla. В этом файле вы можете сделать что-то вроде этого:

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);
        }
    }
}

Все, что расширяет этот базовый класс, убьет себя через 2 секунды после добавления на дисплей.

Чтобы расширить его, щелкните правой кнопкой мыши свои ресурсы в библиотеке (в FlashPro) и в настройках «Экспорт для ActionScript» введите MyBaseClass в текстовое поле базового класса.

введите описание изображения здесь


Конечно, есть и другие способы сделать это, и вы также можете использовать некоторую комбинацию из двух, которые я показал, поскольку наличие только одного таймера более эффективно, чем каждый элемент, имеющий собственный таймер.

3. Используйте setTimeout (не идеально)

Если вы хотите просто понять, как вы можете использовать setTimeout, это будет правильное использование:

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

function kill(itemToKill:DisplayObject):void {
    removeChild(itemToKill);
}
person BadFeelingAboutThis    schedule 09.10.2015

еще один вариант - создать замыкание в качестве прослушивателя событий, которое будет заключать в себе значение плоскости, а после срабатывания будет удалять себя как прослушиватель событий и удалять плоскость. Именно так:

function getKillFn(plane:Plane):Function {
    return function handler(event:TimerEvent):void {
        Timer(event.currentTarget).removeEventListener(TimerEvent.TIMER, handler);
        plane.parent.removeChild(plane);
    }
}

поэтому все, что вам нужно изменить в своем коде, - это заменить эту строку:

killtimer.addEventListener(TimerEvent.TIMER, timerListener);

с этим:

killtimer.addEventListener(TimerEvent.TIMER, getKillFn(plane));

Или вы даже можете создать эту функцию на месте (в функции спауна):

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);

        function killPlane(event:TimerEvent):void {
            killTimer.removeEventListener(TimerEvent.TIMER, killPlane);
            plane.parent.removeChild(plane);
        }

        killtimer.addEventListener(TimerEvent.TIMER, killPlane);
        //setTimeout(kill, 2000);
        addChild(plane);
        killtimer.start();
    }
    ...

и еще кое-что: поскольку вы создаете новый таймер при каждом вызове порождения, вы должны остановить его и переработать в обработчике, или лучше использовать TimerEvent.COMPLETE, чтобы он останавливался автоматически:

var killtimer: Timer = new Timer(2000, 1);

function killPlane(event:TimerEvent):void {
    killTimer.removeEventListener(TimerEvent.COMPLETE, killPlane);
    killTimer = null;
    plane.parent.removeChild(plane);
}

killtimer.addEventListener(TimerEvent.COMPLETE, killPlane);

надеюсь, это поможет

person leetwinski    schedule 09.10.2015
comment
Остерегайтесь встроенных функций, прикрепленных к слушателям (или любых встроенных функций в этом отношении). Если вы забудете удалить слушателя должным образом или у вас есть ссылки на него, вы очень быстро окажетесь в полосе утечки памяти (особенно в программе, которая постоянно что-то порождает). Я не умаляю достоверности ответа (это определенно способ, которым вы можете это сделать, и некоторые действительно это делают), просто предупреждение о том, что встроенные функции могут часто возвращаться, чтобы укусить вас с точки зрения памяти / стабильности, если вы не очень осторожны. - person BadFeelingAboutThis; 10.10.2015