object 的舞台引用在 re-instantiated 从内存和显示列表中删除后丢失

object's stage reference lost when re-instantiated after being removed from memory & displaylist

我正在制作游戏。当您死亡或赢得关卡时,系统会提示您继续或 return 进入主菜单。如果您选择进入主菜单,您可以开始新游戏。当你开始一个新游戏时,游戏 object 被重新创建并且 children 失去了对舞台的引用。我不确定为什么会这样,我花了一个多星期试图找出原因。以下是游戏中的一些代码(和代码描述),希望能够提供足够的洞察力来说明问题可能发生的原因:

如果在 startMenu 上单击 "new game" 按钮,则会调度 NavigationEvent.START 事件。当关卡完成时,WeeBeeGame 会发送一个 LevelEvent.COMPLETE 事件。

public class DocumentClass extends MovieClip {

    public var startMenu:StartMenuGenerator = new StartMenuGenerator();
    public var weeBeeGame:WeeBeeGame;
    public var youWonBox:YouWonBox = new YouWonBox();

    public function DocumentClass() {
        // constructor code
        addChild(startMenu);
        startMenu.addEventListener(NavigationEvent.START, startGameHandler);
    }

    public function startGameHandler(e:NavigationEvent) : void {
        this.removeChild(startMenuBG);
        removeChild(startMenu);

        weeBeeGame = new WeeBeeGame();
        this.addChild(weeBeeGame);

        weeBeeGame.addEventListener(LevelEvent.COMPLETE, levelCompleteHandler);
    }

    public function levelCompleteHandler(e:LevelEvent) : void {

        youWonBox.x = this.stage.stageWidth/2;
        youWonBox.y = this.stage.stageHeight/2;
        addChild(youWonBox);

        youWonBox.addEventListener(MouseEvent.CLICK, mouseClickHandler);
    }

    private function mouseClickHandler(e:MouseEvent) : void {
        if(e.target.name === "mainmenubtn"){
            mainmenuHandler();  
        }
    }

    private function continueHandler() : void {
        youWonBox.removeEventListener(MouseEvent.CLICK, mouseClickHandler);
    }

    private function mainmenuHandler() : void {
        youWonBox.removeEventListener(MouseEvent.CLICK, mouseClickHandler);
        WeeBeeGame.collisionDOC.removeChildren();
        removeChild(weeBeeGame);
        weeBeeGame = null;

        this.addChild(startMenuBG);
        addChild(startMenu);
        removeChild(youWonBox);
    }
}

调度 LevelEvent.COMPLETE 事件的代码未显示,但它会在关卡完成时调度。 collisionDOC 需要是静态的,因为它在很多其他 类 中都需要,并且包含第 3 方 pixel-level 碰撞检测所需的显示 object。

public class WeeBeeGame extends MovieClip {

    public var bee: Bee;
    public var beeHurt:BeeHurt;

    public var spawningDaemon:SpawningDaemon;

    public static var collisionDOC:DisplayObjectContainer;

    public function WeeBeeGame() {
        this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler, false, 0, true);
    }

    private function addedToStageHandler(e:Event) : void {
        this.removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);

        collisionDOC = new MovieClip();
        addChild(collisionDOC);

        bee = new Bee();
        collisionDOC.addChild(bee);

        beeHurt = new BeeHurt(bee.x, bee.y);
        addChild(beeHurt);
        beeHurt.visible = false;

        spawningDaemon = new SpawningDaemon(currentLevel);

        this.addEventListener(LevelEvent.COMPLETE, levelCompleteHandler, false, 0, true);
    }

    private function levelCompleteHandler(e:LevelEvent) : void {
        removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
    }
}

引发 1009 错误(无法访问 属性 或空 object 引用的方法)的第一行是包含 stage.mouseX 的行,因为阶段引用为空。

public class Bee extends MovieClip {

    public function Bee() {
        this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
    }

    private function addedToStageHandler(e:Event) : void {
        this.removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
        this.x = this.stage.stageWidth / 2;
        this.y = this.stage.stageHeight - this.stage.stageHeight / 9;
        this.addEventListener(Event.ENTER_FRAME, enterFrameHandler, false, 0, true);
    }

    private function enterFrameHandler(e:Event) : void {
        if(stage == null){
            trace('stage is null' + stage.mouseX);
        }
    }
}

当 swf 首次打开并创建新的 WeeBeeGame 时,其 children 具有对舞台的引用。但是当 WeeBeeGame 和它的 children 从显示列表和内存中删除时,它们会丢失引用,即使它们是 re-instantiated,它们的引用仍然会丢失。我该如何解决?我很困惑。谢谢大家!!

ENTER_FRAME 处理程序继续执行,即使显示对象从舞台上移除。因此,当您 removeChild(weeBeeGame) 时,那些 ENTER_FRAME 处理程序仍在尝试访问 stage.mouseX 每一帧。您需要停止 ENTER_FRAME 个处理程序。

可能最简单的解决方法是添加一个 Event.REMOVED_FROM_STAGE 处理程序来删除 Event.ENTER_FRAME 处理程序。

IMO 更好的解决方法是不从游戏对象添加任何 ENTER_FRAME 处理程序,而是公开一个 public 函数,如 update(),它从单个 [=10] 调用=] 处理程序在你的 WeeBeeGame 当游戏是 运行 时。然后要完全停止游戏,您可以通过简单地删除单个 ENTER_FRAME 处理程序来停止所有更新。这是一种常见的做法。