AS3在子节点之前删除事件侦听器仍导致空对象引用

时间:2014-01-18 11:51:15

标签: actionscript-3 flash

我用外部类制作了一个Pong游戏,它当前配置为当playerScore / cpuScore == 1时,播放器,CPU和球从舞台上移除。这些由main.as文件删除,调用removePlayer(),removeBall()和removeCPU(),例如,

        public function removePlayer(): void
        {
        removeEventListener(Event.ENTER_FRAME, loop);
        parent.removeChild(this);
        }

在从子阶段中删除子元素之前,事件侦听器会删除元素的主循环。这适用于播放器和CPU,但对于球,我收到以下错误:

TypeError: Error #1009: Cannot access a property or method of a null object reference.
    at com.classes::ball/loop()

注释掉parent.removeChild(this);摆脱错误,但显然球保持可见。 removeEventListener似乎已经起作用,因为当调用时球停止移动,但是我不知道为什么如果循环被移除,我将获得空对象引用。这是我球的代码:

    package com.classes 
    {
    import flash.display.MovieClip;
    import flash.display.Stage;
    import flash.events.Event;
    import flash.media.Sound; 
    import flash.media.SoundChannel;
    import flash.net.URLRequest;

    public class ball extends MovieClip 
        {
        private var theBackground:bg;
        private var bounce:Sound = new Sound();
        private var point:Sound = new Sound();
        private var channel:SoundChannel = new SoundChannel();

        public var ballSpeedX:int = -3;
        public var ballSpeedY:int = -2;

        public function ball(score:bg) 
        {
            theBackground = score;
            bounce.load(new URLRequest("com/sounds/sfxBounce.mp3"));
            point.load(new URLRequest("com/sounds/sfxScore.mp3"));
            addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
        }

        private function loop(e:Event) 
        {
            x += ballSpeedX;
            y += ballSpeedY;

            if (x <= width/2)
            {
                x = width/2;                                
                ballSpeedX *= -1;                           
                theBackground.cpuScore++;
                theBackground.updateScores();
                channel = point.play();
            } 
            else if (x >= stage.stageWidth - width/2)
            {
                x = stage.stageWidth - width/2;             
                ballSpeedX *= -1;                           
                theBackground.playerScore++;
                theBackground.updateScores();
                channel = point.play();
            }

            if (y <= height/2)
            {
                y = height/2;
                ballSpeedY *= -1;
                channel = bounce.play();
            }
            else if (y >= stage.stageHeight - height/2)
            {
                y = stage.stageHeight - height/2;
                ballSpeedY *= -1;
                channel = bounce.play();
            }
        }

        public function removeBall(): void
        {
            removeEventListener(Event.ENTER_FRAME, loop);
            parent.removeChild(this);
        }
    }
}

非常感谢任何帮助或指示!

1 个答案:

答案 0 :(得分:0)

您可以在if (!stage) return;函数的开头添加loop语句。显然你正在尝试在处理另一个removeBall()监听器时调用Event.ENTER_FRAME,可能是在时钟或播放器或其他地方,这会导致事件的侦听器序列已经缓存在Flash中。也就是说,如果要从同一事件的另一个侦听器中删除某个事件类型的事件侦听器(输入帧事件限定条件),则仍会为该事件调用侦听器。您应该从其他地方调用removeBall(),而不是从enterframe侦听器调用,或者只是在该侦听器中进行空检查以避免出现奇怪的错误。

编辑:显然你在removeBall()时调用theBackground.updateScores(),在你这样做之后,处理事件的球已被删除,因此进一步处理听众是没用的。触发声音后发出return声明,以便在调用theBackground.updateScores()的所有条款中播放,您应该没问题。

      if (x <= width/2)
        {
            x = width/2;                                
            ballSpeedX *= -1;                           
            theBackground.cpuScore++;
            theBackground.updateScores();
            point.play();
            return; // here
        } 
        else if (x >= stage.stageWidth - width/2)
        {
            x = stage.stageWidth - width/2;             
            ballSpeedX *= -1;                           
            theBackground.playerScore++;
            theBackground.updateScores();
            point.play();
            return; // and here
        }