操作脚本3:整个事件调度变得无法使用

时间:2013-02-24 20:09:57

标签: actionscript-3

我正在研究类似于愤怒的小鸟“推出”的选项等等,但我遇到了一个相当大的问题。

卷展栏本身只是一个切换按钮,当您触摸切换按钮时,其他几个按钮会添加到显示列表中。这些按钮中的每一个都是一个扩展Sprite的类,包含触摸事件,开始,结束和结束的各个方法。当这些按钮被初始化(未实例化)时,会添加触摸开始侦听器。像这样:

    public function Initialize():void 
    { 
        this.addEventListener(TouchEvent.TOUCH_BEGIN, OnTouchBegin, false, int.MAX_VALUE);
    }

    private function OnTouchBegin(e:TouchEvent):void
    {
        this.removeEventListener(TouchEvent.TOUCH_BEGIN, OnTouchBegin);
        this.addEventListener(TouchEvent.TOUCH_END, OnTouchRelease, false, int.MAX_VALUE);
        this.addEventListener(TouchEvent.TOUCH_OUT, OnTouchOut, false, int.MAX_VALUE);
    }

    private function OnTouchRelease(e:TouchEvent):void
    {
        this.addEventListener(TouchEvent.TOUCH_BEGIN, OnTouchBegin, false, int.MAX_VALUE);
        this.removeEventListener(TouchEvent.TOUCH_END, OnTouchRelease);
        this.removeEventListener(TouchEvent.TOUCH_OUT, OnTouchOut);
    }

    private function OnTouchOut(e:TouchEvent):void
    {
        this.addEventListener(TouchEvent.TOUCH_BEGIN, OnTouchBegin, false, int.MAX_VALUE);
        this.removeEventListener(TouchEvent.TOUCH_END, OnTouchRelease);
        this.removeEventListener(TouchEvent.TOUCH_OUT, OnTouchOut);
    }

然后,当这些按钮从屏幕上隐藏时,会调用一个方法来删除当前在其上激活的任何侦听器:

    public function Deactivate():void 
    {
        this.removeEventListener(TouchEvent.TOUCH_OUT, OnTouchOut);
        this.removeEventListener(TouchEvent.TOUCH_END, OnTouchRelease);
        this.removeEventListener(TouchEvent.TOUCH_BEGIN, OnTouchBegin);

    }

这仅适用于标准按钮功能(上/下纹理和声音),除此之外,当我制作游戏时,在我的rollout类中,我还有一个额外的方法将为自定义逻辑添加另一个事件侦听器触摸按钮时应该发生的事情(按钮本身是在其他地方创建的)。

    public function AddRolloutButton(listener:Function):void
    {
        if (listener != null) 
        {
            _buttons[index].addEventListener(TouchEvent.TOUCH_BEGIN, listener);
        }

卷展栏中的按钮本身将从显示列表中删除,直到显示它们为止。关闭卷展栏时,按钮将被取消激活(从显示列表中删除,按钮类中的3个按钮侦听器将被删除)。

第一次打开和关闭部署时,一切都运行得很好。之后,事件调度系统莫名其妙地死了。无论位置或类型如何,屏幕上的每个InteractiveObject都将变得无法使用。我查看了听众是否仍然在滚动切换按钮上,并且确实如此。我还确认了推出按钮本身是显示列表中唯一的东西。

我注意到的是,如果我在触摸开始侦听器的按钮的去激活方法中注释掉侦听器,或者在AddRolloutButton方法中为侦听器方法传入null,则一切正常。问题似乎源于在卷展栏按钮上有多个相同类型的侦听器,然后删除其中一个或全部。

如果有人对正在发生的事情有任何想法,那将非常有帮助。我的印象是,向InteractiveObject添加多个相同类型的侦听器是完全有效的。

更新:

看来我只有这个问题才能打破TouchEvents。我只是在打开和关闭卷展栏后尝试在舞台上使用鼠标单击侦听器,这仍然有效。因此,只有触摸事件会被破坏,如果这有帮助的话。

3 个答案:

答案 0 :(得分:0)

您的AddRolloutButton方法似乎出现了问题。您确定要分配正确的侦听器功能吗?

在您的示例中,listener:Function参数应等于_buttons[index]. OnTouchBegin

或者,因为拥有AddRolloutButton方法的任何类似乎都在按钮的 control 中,所以你可能会完全废弃监听器参数,因为你知道需要触发的方法。

例如:

public function AddRolloutButton():void {
    var currentButton:MyButtonClass = _buttons[index] as MyButtonClass;
    currentButton.addEventListener(TouchEvent.TOUCH_BEGIN, currentButton.OnTouchBegin);
    [...]
}

但是,您可以做的是永远不要删除TouchEvent.TOUCH_BEGIN函数中的Deactivate。当DisplayObject不在显示列表中时,将永远不会触发触摸事件。这意味着每次要将按钮再次添加到显示列表时,您无需担心添加侦听器。

如果您将侦听器设置为使用弱引用,则不会阻止按钮在不再需要时进行垃圾回收。要使您的事件侦听器使用弱引用,请将addEventListener方法的第五个参数设置为true。

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

public function Initialize():void { 
    this.addEventListener(TouchEvent.TOUCH_BEGIN, OnTouchBegin, false, int.MAX_VALUE, true);
}

答案 1 :(得分:0)

关闭推出后,您是否在某个时刻再次调用Initialize方法?

从您的代码中看起来好像您删除了Deactivate中的所有事件侦听器,然后再也没有添加TouchEvent.TOUCH_BEGIN侦听器。

答案 2 :(得分:0)

我不确定你要通过删除事件监听器来完成什么。由于Button具有对回调的引用,因此无论是否附加了侦听器,它都会引用该回调。您是否认为添加侦听器会创建从回调到按钮的引用?它不是 - reverse is true

如果你真的希望Button从显示列表中删除它时释放回调,那么它在删除侦听器后就无法保存该引用。请考虑使用Supervising PresenterRobotLegs Mediator之类的内容来管理这些依赖项。

我严重怀疑整个事件系统正在被你正在做的事情所困扰。

我更倾向于相信这一点:

        if (listener != null) 
        {
            _buttons[index].addEventListener(TouchEvent.TOUCH_BEGIN, listener);
        }

失败,要么是因为引用的按钮不是实际在舞台上的按钮,要么是因为侦听器为空...

已经看到添加和删除具有优先级的事件会导致事情失败的时间,但通常情况下这是因为事件未在显示列表中传播。

您可以测试这种方法的一种方法就是收听主要文档或触摸事件的舞台,看看您是否收到了这些事件。如果整个事件系统都被堵塞了,你就不会得到它们,但是如果你的听众逻辑是错误的,你就会。

您可能还想检查按钮和事件上的willTrigger属性。