Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/actionscript-3/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Actionscript 3 在AS3中,removeEventListener(Event.ENTER_FRAME)不工作_Actionscript 3_Event Handling_Event Listener_Game Loop_Enterframeevent - Fatal编程技术网

Actionscript 3 在AS3中,removeEventListener(Event.ENTER_FRAME)不工作

Actionscript 3 在AS3中,removeEventListener(Event.ENTER_FRAME)不工作,actionscript-3,event-handling,event-listener,game-loop,enterframeevent,Actionscript 3,Event Handling,Event Listener,Game Loop,Enterframeevent,我已经处理这个问题好几天了。我束手无策! 我似乎在任何论坛、文档等上都找不到明确的答案 在第一次运行时,或者当我加载下一个级别供用户玩时,一切看起来都很好。但是,如果用户按ESC键加载不同的级别,则不会删除ENTER FRAME侦听器,它会复制其中的所有触发器,显示播放器运行得非常快,而且非常时髦,因为它构建在先前实例化的ENTER FRAME侦听器的基础上 我不知道我是否有匿名函数的问题,或者我的removeEvent中引用了未知实例。。。命令。。。总之,我放弃了,我需要这份工作上的帮助 代码

我已经处理这个问题好几天了。我束手无策! 我似乎在任何论坛、文档等上都找不到明确的答案

在第一次运行时,或者当我加载下一个级别供用户玩时,一切看起来都很好。但是,如果用户按ESC键加载不同的级别,则不会删除ENTER FRAME侦听器,它会复制其中的所有触发器,显示播放器运行得非常快,而且非常时髦,因为它构建在先前实例化的ENTER FRAME侦听器的基础上

我不知道我是否有匿名函数的问题,或者我的removeEvent中引用了未知实例。。。命令。。。总之,我放弃了,我需要这份工作上的帮助

代码如下:

function initPlay():void
{ 
    //code here determining what display object to add to the list and assign it to the currentLevel variable (a movieclip)

    if(userIsLoadingOtherLevel){
        removeEnterFrameListener();
        addChild(currentLevel);
        }
    if(userIsGointToNextLevel)
        addChild(currentLevel);

    currentLevel.addEventListener(Event.ENTER_FRAME, onEnterFrame);
    function onEnterFrame(event:Event):void
    {
        //collision detection, parallax scrolling, etc, etc is done here.
        if(allCoinsCollected)
            loadNextLevel();
        if(ESCKeyPressed)
            ESCKeyPressHandler();
    }
    function loadNextLevel():void
    {
        removeChild(currentLevel);
        newLevelToLoad++
        removeEnterFrameListener();
        initPlay();
    }

    function ESCKeyPressHandler():void
    {
        removeChild(currentLevel);
        initPlay();
    }
    function removeEnterFrameListener();
    {
        currentLevel.removeEventListener(Event.ENTER_FRAME,onEnterFrame)
        trace("currentLevel.hasEventListener(Event.ENTER_FRAME) = "+currentLevel.hasEventListener(Event.ENTER_FRAME)); //outputs TRUE if called from loadNextLevel but FALSE if called from initPlay() !!!
    }
}
我还尝试将eventListener添加到stage、MovieClip(Root)或什么都不添加或删除,结果总是一样的

我知道可能有其他方法来设计这样一个过程,但请注意,我现在在做这件事上不是很灵活,因为这个项目很长(大约4000行代码),用这种方式删除回车框,疯狂或不疯狂应该仍然有效


提前感谢任何愿意帮助的人

问题似乎是
initPlay()
方法中的嵌套函数

每次调用
initPlay()。其中一些嵌套函数本身调用
initPlay()

函数是对象(内存引用)。因此,每次调用
initPlay()
都是对新函数的新引用。因此,当您尝试删除事件侦听器时,您只能删除其中一个事件处理程序(当前执行范围内的事件处理程序)

我不确定我是否解释得很清楚,也许这个例子会有所帮助。我将使用数字表示对每个函数的引用,以及一个与您类似的简单场景:

function example():void
{
    addEventListener(MouseEvent.CLICK, mouseClickHandler);

    function mouseClickHandler(event:Event):void
    {
        if (someCondition)
        {
            example();
        }
        else
        {
            removeEventListener(MouseEvent.CLICK, mouseClickHandler);
        }
    }
}
当我们第一次运行此函数时,在
example()
函数的范围内定义了一个新函数。让我们使用数字1表示对此嵌套函数的引用
someCondition
在第一次时为
true
,因此再次调用
example()
函数

在第二次执行
example()
函数时,将创建对鼠标事件处理程序的新引用(#2)。我们还再次添加事件侦听器。此时,内存中有两个事件处理函数,它们都将在调度事件时执行

假设在第二次调用
example()
时,
someCondition
false
,现在我们要删除侦听器。当我们打电话时:

removeEventListener(MouseEvent.CLICK, mouseClickHandler);
它指的是事件处理程序#2。事件处理程序#1仍然存在,并且由于它隐藏在
example()
的第一次调用范围内,因此不能在此处删除它


我的简单示例在此之后崩溃。。。但我希望它能清楚地说明为什么事件处理程序不应该嵌套在函数中。诚然,这很难描述,在像你这样的现实世界中更是如此。但我很有信心,这是您所描述的大多数问题(如果不是全部的话)的根源。

以下是我如何通过创建一个名为“loadingNewGame”的布尔变量,在不改变嵌套函数的范围的情况下绕过这一问题(尽管我同意这将是首选解决方案)在onEnterFrame外部将其更改为true(事实上,这个赋值是从initPlay()完成的,然后从onEnterFrame调用removeEnterFrameListener()函数

以下是代码,以防任何人感兴趣:

// package, and other code here.

var loadingNewGame:Boolean = new Boolean(false);
function initPlay():void
{ 

    //code here determining what display object to add to the list and assign 
    //it to the currentLevel variable (a movieclip)

    if(userIsLoadingOtherLevel)
        {
        loadingNewGame = true;
        removeEnterFrameListener();
        addChild(currentLevel);
        }
    if(userIsGointToNextLevel)
        addChild(currentLevel);

    loadingNewGame:Boolean = false;
    currentLevel.addEventListener(Event.ENTER_FRAME, onEnterFrame);
    function onEnterFrame(event:Event):void
    {
        if(loadingNewGame)
            removeChild(currentLevel);
        //collision detection, parallax scrolling, etc, etc is done here.
        if(allCoinsCollected)
            loadNextLevel();
        if(ESCKeyPressed)
            ESCKeyPressHandler();
    }
    function loadNextLevel():void
    {
        removeChild(currentLevel);
        newLevelToLoad++
        removeEnterFrameListener();
        initPlay();
    }

    function ESCKeyPressHandler():void
    {
        initPlay();
    }
    function removeEnterFrameListener();
    {
        currentLevel.removeEventListener(Event.ENTER_FRAME,onEnterFrame)
        trace("currentLevel.hasEventListener(Event.ENTER_FRAME) = "+currentLevel.hasEventListener(Event.ENTER_FRAME)); 
        //outputs true
    }

如果您使用loadNextLevel而不是ESCKeyPressHandler,它会工作吗?我还感觉到发生的事情是,ENTER_FRAME事件侦听器连接到currentLevel显示对象的所有子对象,当我移除它以添加不同的级别时,它仍然保留在一些currentLevel子对象中,或者类似的东西。我认为这可能是因为在加载新关卡后,玩家仍然会与“隐形”发生冲突对象可能仍然存在于之前的…是的,这很好。我只是在使用ESCKeyPress处理程序时遇到问题。它只是没有删除它!上面的代码正确吗?我问这个问题是因为您似乎在
initPlay()中定义函数
function。语法方面,这很好。但从逻辑上讲,这可能是您的问题的一部分。也许这只是一个打字错误,您忘记了在右括号中粘贴/键入内容。
trace()
语句是一个很好的调试工具。在每个方法的开头放上
trace()
语句。然后在这两种情况下运行您的代码(当其正常工作和出现故障时)。比较从跟踪语句中获得的输出,也许你会看到事情的发展方向。你当前的工作可能会导致性能问题,并导致执行大量enter frame侦听器。不确定我是否对此进行了清楚的解释……也许这个示例有些过火。如果我更清楚地解释一下……顺便说一句,对事件处理程序(甚至匿名函数)使用嵌套函数是可以的,但在逻辑变得复杂的情况下就不行了。在这种情况下,最好将这些函数移到“外部”作用域,这样就不会对添加/删除的内容产生混淆。事实上,你说得很有道理。然后我要做的是将嵌套函数移到外部,除非绝对有必要将它们保持嵌套状态。这还应该简化开发过程中的其他任务。我添加out scope变量的临时修复方法修复了它,因为它允许我从“enter frame”本身中删除事件处理程序,但它不会