Flash AS3 - removeChild()用于完全删除对象?

时间:2011-02-09 14:52:29

标签: flash actionscript-3 object removechild

我正在创建一个小行星游戏,在我的主要课程中,我在处理船发射的子弹时遇到了一些麻烦。

所有子弹都属于“Bullet”类,并存储在主类中称为“项目符号”的数组中。当项目符号退出屏幕时,将调用主类中的removeBullet(bulletID)。

private function removeBullet(id:int)
    {
        removeChild(bullets[id]);
        bullets.splice(id);
    }

在我的Bullet类中,我有一个跟踪“stillHere”的enterFrame监听器。因此,只要使用addChild将子弹添加到主舞台,就会在我的输出面板中弹出“stillHere”。

我的问题是,即使在我调用removeBullet之后,“stillHere”仍然会在输出面板中弹出,这告诉我,我试图删除的对象仍然在内存中的某处。

我可以做些什么来完全摆脱它?

2 个答案:

答案 0 :(得分:4)

事件监听器本身很可能是它仍然在内存中的原因。这不是测试某些东西是否被垃圾收集的好方法。

此外,即使这是检查对象是否已被垃圾收集的好方法,收集也不是一个瞬时过程。 Flash Player只在需要分配更多内存时才会运行gc,并且无法执行此操作。

假设除了显示列表和项目符号数组之外没有其他对项目符号的引用,你所做的就足以让它被垃圾收集了。

编辑:回答是否有办法观察是否收集了一个物品的问题......

您可以在弱键字典中将对象用作

private var _dict:Dictionary = new Dictionary(true);
_dict[bullet] = "Bullet is still here...";

然后,只要你想检查子弹是否仍然存在,你就可以使用for ... in循环来迭代键

for(var key:* in _dict){
    trace(key + " " + _dict[key]);
}

因为弱键控字典的键不计入垃圾收集的引用,所以这是有效的。

如果您非常关心内存泄漏,可以考虑编写一个对象池,将放置在舞台上的旧子弹对象放入其中,然后一遍又一遍地重复使用它们。通过这种方式,你永远不会允许任何子弹被垃圾收集,但你可能只会创建一个有限数量的子弹(这是用户同时在屏幕上看到的子弹数量)在给定的时间)。这对你来说可能是最好的解决方案,因为子弹可能占用的内存很少,而且你可以获得不强制Flash清理垃圾的好处。在垃圾被移除时运行GC会导致性能下降,因此通过该措施尽可能地防止甚至需要它是一件好事。

答案 1 :(得分:4)

由于您使用的是ActionScript,因此无法直接控制何时删除对象。

您遇到的真正问题是您的事件侦听器仍在触发。显然,您可以在删除时调用removeEventListener来解决此问题。

然而更好的方法是整个游戏只有一个ENTER_FRAME监听器。它需要单独推进所有游戏元素(船舶,小行星,子弹,碎片等)。此方法消除了您不小心忘记删除事件侦听器的任何可能性,并且它还使代码更清晰,因为您可以看到元素将在一个时间步骤内更新的顺序。

我的临时对象中通常有destroy函数,其内容如下:

public function destroy():void {
    stop(); // if it's a MovieClip
    if(parent) parent.removeChild(this);
}

只要我调用此函数然后删除对象的引用,通常会收集它。

出于这个原因,我的代码很少有个别对象的监听器。