0

我正在为大学工作做一个小游戏,我不太了解垃圾收集器如何与 EventListeners 一起工作,我觉得“preCastTimer”EventListener 永远不会在下面的代码中被删除。问题是我不知道如何在完成后将其删除。

下面是我在按下键时用来施法的代码

在这里,我有 KeyboardEvents 调用的投射功能,火球是一个 MovieClip

preCast(fireball);

function preCast(spell)
{
    var tempSpell:Object = new spell;//create an object for the spell so castTime is accessible. 
    var preCastTimer:Timer = new Timer(tempSpell.castTime,1);
    var spellFunc:Function = cast(spell);
    preCastTimer.addEventListener(TimerEvent.TIMER_COMPLETE, spellFunc);

    preCastTimer.start();
}

function cast(spell):Function {
    return function(e:TimerEvent):void {
        parent.addChild(new spell);//For some reason if spell is not created here it never gets a parent
  };
}

这是火球电影剪辑的代码:

package  {

    import flash.display.MovieClip;


    public class fireball extends MovieClip {
        public var castTime:uint = 1000;


        public function fireball() {
            // constructor code
        }
    }

}

下面的代码在火球时间轴中。我知道使用类更好,但是当代码在包中而不是在时间轴框架上时,我仍然不理解育儿

import flash.events.Event;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.geom.Point;

if (parent)//only run if a parent exists, when created as object no parent is defined
{
    x = parent.getChildByName("player").x;
    y = parent.getChildByName("player").y;

    var direction = new Point(parent.mouseX - x,parent.mouseY - y);
    rotation = Math.atan2(parent.mouseY - y,parent.mouseX - x) * 180 / Math.PI;
    direction.normalize(5);
    if (direction.x == 0 && direction.y == 0)
    {
        parent.removeChild(this);
        return;
    }

    var spellTimer:Timer = new Timer(500,1);


    spellTimer.addEventListener(TimerEvent.TIMER_COMPLETE, spellKiller);
    this.addEventListener(Event.ENTER_FRAME, motion);

    spellTimer.start();
}

function spellKiller(e:TimerEvent):void
{
    this.removeEventListener(Event.ENTER_FRAME, motion);
    spellTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, spellKiller);
    parent.removeChild(this);
}

function motion(e:Event)
{
    x +=  direction.x * 5;
    y +=  direction.y * 5;
}
4

2 回答 2

0

所以你的代码有点过于复杂,缺少一些重要的部分,所以我不能真正评论那个父级的东西。据我了解,计时器应该触发一次,然后您希望删除它的侦听器,对吗?嗯,这很容易实现:

function cast(spell):Function {
    return function(e:TimerEvent):void {
        parent.addChild(new spell);
        e.target.removeEventListener(TimerEvent.TIMER_COMPLETE, spellFunc);
  };
}

为什么你觉得这不是正确的解决方案?您可以通过简单地将 TimerEvent.TIMER_COMPLETE 更改为 TimerEvent.TIMER(并删除传递给计时器构造函数的重复计数)来测试是否删除了侦听器。它应该只添加一次咒语。

另请注意,垃圾收集器不会立即将其捡起(嗯,很可能不会!)。它可能会在未来的某个地方捡起它,或者永远不会。实际上,如果您不将计时器设置为 null 或者您不创建另一个计时器对象并将其分配给与您的引用相同的变量,那么计时器可能永远不会被选中,因此它永远不会有资格进行垃圾收集。

于 2013-11-08T18:29:27.547 回答
0

请注意,addEventListeneruseWeakReference参数(第 5 个参数)。

public function addEventListener(
    type:String,
    listener:Function,
    useCapture:Boolean = false,
    priority:int = 0,
    useWeakReference:Boolean = false
):void;

EventDispatcher 文档中:

如果您不再需要事件侦听器,请通过调用 removeEventListener() 将其删除,否则可能会导致内存问题。事件监听器不会自动从内存中删除,因为只要调度对象存在,垃圾收集器就不会删除监听器(除非 useWeakReference 参数设置为 true)。

解决方案是在适当的情况下简单地将您的addEventListener调用转换为使用弱引用。

foo.addEventListener(type, listener, false, 0, true);

如果您不确定这对您有何帮助,请告诉我。

于 2013-11-08T16:20:10.030 回答