我已经处理好这个问题好几天了。我没办法! 我似乎无法在任何论坛,文档等任何地方找到明确的答案。
首次运行时,或者当我为用户加载下一级别时,一切看起来都很好。但是如果用户点击ESC键加载不同的级别,则不会删除ENTER FRAME侦听器,它会复制其中的所有触发器,显示播放器运行速度非常快,并且所有时髦,因为它建立在之前的基础之上实例化的ENTER FRAME监听器。
我不知道我是否有匿名函数的问题,或者我的removeEvent ...命令中引用了一个未知实例...底线,我放弃了,我需要这个工作帮助!!! / p>
以下是代码:
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行代码)并删除了输入框架这个方式,疯狂与否应该仍然有效!!
感谢任何愿意提供帮助的人。
答案 0 :(得分:2)
问题似乎是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()
的范围内,所以无法在此处删除它。
我的简单示例在此之后发生故障......但我希望它能说明为什么不应将事件处理程序嵌套在函数中。不可否认,这很难描述,在像你这样的现实世界中更是如此。但我非常有信心,这是你所描述的大多数(如果不是全部)问题的根源。
答案 1 :(得分:0)
通过创建一个名为“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
}