【问题标题】:Error #2025: The supplied DisplayObject must be a child of the caller - Not sure how to fix错误 #2025:提供的 DisplayObject 必须是调用者的子对象 - 不确定如何修复
【发布时间】:2013-05-15 14:24:30
【问题描述】:

所以我收到一条错误消息,指出提供的 DisplayObject 必须是调用者的子对象。发生的情况是我的游戏第一次运行,点击'Play' 按钮调用startGame 函数并删除菜单以便显示游戏,但是在游戏结束时点击playAgainBtn,而不是简单地再次玩游戏/重新启动游戏,我得到了这个错误:

ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller. at flash.display::DisplayObjectContainer/removeChild()

具体指向这一行:

menuLayer.removeChild(mainMenu);

代码如下:

package  {
    import flash.display.MovieClip;
    import flash.display.LoaderInfo;
    import flash.display.Sprite;
    import flash.display.DisplayObject;
    import flash.display.Stage;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.events.TimerEvent;
    import flash.utils.Timer;
    import flash.ui.Mouse;
    import flash.media.Sound;
    import flash.media.SoundChannel;
    import flash.text.TextFormat;
    import flash.text.TextField;
    import flash.text.AntiAliasType;
    import flash.display.Loader;
    import flash.net.URLRequest;
    import flash.net.URLLoader;
    import flash.system.LoaderContext;
    import flash.display.Sprite;
    import flash.net.Socket;
    import caurina.transitions.Tweener;
    import flash.text.Font;

    public class Main extends MovieClip {

    public static var backgroundLayer:Sprite = new Sprite;
    public static var gameLayer:Sprite = new Sprite;
    public static var interfaceLayer:Sprite = new Sprite;
    public static var endGameLayer:Sprite = new Sprite;
    public static var menuLayer:Sprite = new Sprite;
    public static var gameOverLayer:Sprite = new Sprite;
    public static var howToLayer:Sprite = new Sprite;
    public static var scoresLayer:Sprite = new Sprite;
    public static var aboutLayer:Sprite = new Sprite;

    public var mainMenu:menuMain = new menuMain;
    public var gameEnd:endGame = new endGame;
    public var howtoPlay:howToPlay = new howToPlay;
    public var gameAbout:aboutGame = new aboutGame;
    public var intro:IntroSound = new IntroSound();
    public var soundControl:SoundChannel = new SoundChannel();

    public var gameTime:int;
    public var levelDuration:int;

    public var crosshair:crosshair_mc;
    static var score:Number;

    var enemyShipTimer:Timer;
    var enemyShipTimerMed:Timer;
    var enemyShipTimerSmall:Timer;

    static var scoreHeader:TextField = new TextField();
    static var scoreText:TextField = new TextField();
    static var timeHeader:TextField = new TextField();
    static var timeText:TextField = new TextField();

    static var scoreFormat = new TextFormat("Arial Rounded MT Bold", 20, 0xFFFFFF);
    public var gameOverscoreFormat = new TextFormat("Arial Rounded MT Bold", 32, 0xFFFFFF);

   public function Main()
   {
        addChild(gameLayer);
        addChild(backgroundLayer);
        addChild(interfaceLayer);
        addChild(menuLayer);

        menuLayer.addChild(mainMenu);
        interfaceLayer.addChild(howtoPlay);
        interfaceLayer.addChild(gameEnd);
        interfaceLayer.addChild(gameAbout);
        soundControl = intro.play(0, 100);
        addMenuListeners();
   }

   public function menuReturn(e:Event)
   {

        addChild(gameLayer);
        addChild(backgroundLayer);
        addChild(interfaceLayer);
        addChild(menuLayer);

        menuLayer.addChild(mainMenu);
        interfaceLayer.addChild(howtoPlay);
        interfaceLayer.addChild(gameEnd);
        interfaceLayer.addChild(gameAbout);
   }

   public function showAbout(e:Event)
   {
      menuLayer.removeChild(mainMenu);
      interfaceLayer.addChild(gameAbout);
   }

   public function startGame(e:Event)
   {
        removeMenuListeners();
        soundControl.stop();
        interfaceLayer.removeChild(howtoPlay);
        interfaceLayer.removeChild(gameAbout);
        interfaceLayer.removeChild(gameEnd);
        menuLayer.removeChild(mainMenu);

        levelDuration = 30;
        gameTime = levelDuration;
        var gameTimer:Timer = new Timer(1000,levelDuration);
        gameTimer.addEventListener(TimerEvent.TIMER, updateTime);
        gameTimer.addEventListener(TimerEvent.TIMER_COMPLETE, timeExpired)
        gameTimer.start();

        scoreHeader = new TextField();
        scoreHeader.text = String("Score: ");
        interfaceLayer.addChild(scoreHeader);
        scoreHeader.x = 5;
        scoreHeader.selectable = false;
        scoreHeader.embedFonts = true;
        scoreHeader.antiAliasType = AntiAliasType.ADVANCED;

        scoreText = new TextField();
        scoreText.text = String("0");
        interfaceLayer.addChild(scoreText);
        scoreText.x = 75;
        scoreText.y = 0;
        scoreText.selectable = false;
        scoreText.embedFonts = true;
        scoreText.antiAliasType = AntiAliasType.ADVANCED;

        timeHeader = new TextField();
        timeHeader.text = String("Time: ");
        interfaceLayer.addChild(timeHeader);
        timeHeader.x = 500;
        timeHeader.y = 0;
        timeHeader.selectable = false;
        timeHeader.embedFonts = true;
        timeHeader.antiAliasType = AntiAliasType.ADVANCED;

        timeText = new TextField();
        timeText.text = gameTime.toString();
        interfaceLayer.addChild(timeText);
        timeText.x = 558;
        timeText.y = 0;
        timeText.selectable = false;
        timeText.embedFonts = true;
        timeText.antiAliasType = AntiAliasType.ADVANCED;

        scoreHeader.setTextFormat(scoreFormat);
        scoreText.setTextFormat(scoreFormat);
        timeHeader.setTextFormat(scoreFormat);
        timeText.setTextFormat(scoreFormat);

        var timeScorebg:Sprite = new Sprite();
        backgroundLayer.addChild(timeScorebg);
        timeScorebg.graphics.beginFill(0x333333);
        timeScorebg.graphics.drawRect(0,0,600,30);
        timeScorebg.graphics.endFill();
        timeScorebg.y = 0;

        enemyShipTimer = new Timer(2000);
        enemyShipTimer.addEventListener("timer", sendEnemy);
        enemyShipTimer.start();

        enemyShipTimerMed = new Timer(2500);
        enemyShipTimerMed.addEventListener("timer", sendEnemyMed);
        enemyShipTimerMed.start();

        enemyShipTimerSmall = new Timer(2750);
        enemyShipTimerSmall.addEventListener("timer", sendEnemySmall);
        enemyShipTimerSmall.start();

        crosshair = new crosshair_mc();
        gameLayer.addChild(crosshair);

        crosshair.mouseEnabled = crosshair.mouseChildren = false;

        Mouse.hide();

        gameLayer.addEventListener(Event.ENTER_FRAME, moveCursor);
        resetScore();
    }

    function addMenuListeners():void
    {
        mainMenu.playBtn.addEventListener(MouseEvent.CLICK, startGame);
        mainMenu.howToPlayBtn.addEventListener(MouseEvent.CLICK, showInstructions);
        mainMenu.aboutBtn.addEventListener(MouseEvent.CLICK, showAbout);
        howtoPlay.backBtn.addEventListener(MouseEvent.CLICK, menuReturn);
        gameEnd.playagainBtn.addEventListener(MouseEvent.CLICK, startGame);
        gameAbout.backBtn.addEventListener(MouseEvent.CLICK, menuReturn);
    }

    function removeMenuListeners():void
    {
        mainMenu.playBtn.removeEventListener(MouseEvent.CLICK, startGame);
        mainMenu.howToPlayBtn.removeEventListener(MouseEvent.CLICK, showInstructions);
        mainMenu.aboutBtn.removeEventListener(MouseEvent.CLICK, showAbout);
        howtoPlay.backBtn.removeEventListener(MouseEvent.CLICK, menuReturn);
        gameEnd.playagainBtn.removeEventListener(MouseEvent.CLICK, startGame);
        gameAbout.backBtn.removeEventListener(MouseEvent.CLICK, menuReturn);
    }

    public function showInstructions(e:Event)
    {
        menuLayer.removeChild(mainMenu);
        interfaceLayer.addChild(howtoPlay);
    }

    function sendEnemy(e:Event)
    {
        var enemy = new EnemyShip();
        gameLayer.addChild(enemy);
        gameLayer.addChild(crosshair);
    }

    function sendEnemyMed(e:Event)
    {
        var enemymed = new EnemyShipMed();
        gameLayer.addChild(enemymed);
        gameLayer.addChild(crosshair);
    }

    function sendEnemySmall(e:Event)
    {
        var enemysmall = new EnemyShipSmall();
        gameLayer.addChild(enemysmall);
        gameLayer.addChild(crosshair);
    }

    static function updateScore(points)
    {
        score += points;
        scoreText.text = String(score);
        scoreHeader.setTextFormat(scoreFormat);
        scoreText.setTextFormat(scoreFormat);
    }

    static function resetScore()
    {
        score = 0;
        scoreText.text = String(score);
        scoreText.setTextFormat(scoreFormat);
    }

    function updateTime(e:TimerEvent):void
    {
        gameTime--;
        timeText.defaultTextFormat = scoreFormat;
        timeText.text = String(gameTime);
    }

    function timeExpired(e:TimerEvent):void
    {
        var gameTimer:Timer = e.target as Timer;
        gameTimer.removeEventListener(TimerEvent.TIMER, updateTime)
        gameTimer.removeEventListener(TimerEvent.TIMER, timeExpired)

        interfaceLayer.addChild(gameEnd);

        var thisFont:Font = new myFont();
        var myFormat:TextFormat = new TextFormat();
        myFormat.font = thisFont.fontName;

        scoreText = new TextField();
        scoreText.defaultTextFormat = myFormat;
        scoreText.text = String(score);
        interfaceLayer.addChild(scoreText);
        scoreText.x = 278;
        scoreText.y = 180;
        scoreText.selectable = false;
        scoreText.embedFonts = true;
        scoreText.antiAliasType = AntiAliasType.ADVANCED;
        scoreText.setTextFormat(gameOverscoreFormat);

        Mouse.show();
        removeChild(gameLayer);
        addMenuListeners();
    }

    function moveCursor(event:Event) 
    {
      crosshair.x=mouseX;
      crosshair.y=mouseY;
    }
    }
  }

我不太确定如何解决此问题,因此欢迎提供任何建议或解决方案。我无法让它按照我想要的方式工作而不会出错。

谢谢。

【问题讨论】:

    标签: actionscript-3 flash-cs6


    【解决方案1】:

    我相信问题是在第二次播放时调用menuLayer.removeChild(mainMenu); 会引发错误,因为您已经删除了一次。最快的解决方案是在尝试删除 menuLayer 之前检查以确保它包含 mainMenu:

    if(menuLayer contains mainMenu)
        menuLayer.removeChild(mainMenu);
    

    (请注意,我现在无法访问 IDE,但我认为这应该可以)

    更强大的解决方案是在从主菜单中单击播放按钮时调用不同的方法,从menuLayer 中删除mainMenu,然后调用startGame(其中playAgain 直接调用startGame )。

    编辑 好的,我明白你的意思了。也许是这样的:

    mainMenu.playBtn.addEventListener(MouseEvent.CLICK, playGame);
    gameEnd.playagainBtn.addEventListener(MouseEvent.CLICK, playGameAgain);
    ...
    public function playGame(e:Event)
    {
        menuLayer.removeChild(mainMenu);
        startGame();
    }
    ...
    public function playGameAgain(e:Event)
    {
        startGame();
    }
    ...
    public function startGame()
    

    【讨论】:

    • 嗯,我喜欢第二个想法,但不太确定参数是什么,因为 startGame() 本身不起作用
    • @Liam 参数为空。您不使用该事件,因此不需要它。或者你可以通过e?无论哪种方式,都无所谓。
    【解决方案2】:

    我不知道为什么你的代码不工作,但没有必要担心,试试:

     MovieClip(menuLayer.parent).removeChild(menuLayer);
    

    【讨论】:

    • TypeError:错误 #1009:无法访问空对象引用的属性或方法。在 Main/startGame()
    • 我还是没有。我想要“再次播放”按钮所做的只是将游戏重置为与关闭游戏并再次运行时相同的方式,即再次显示菜单并重置分数等。
    【解决方案3】:

    您删除了两个不同位置的mainMenu。我的猜测是它会被一次又一次地删除。

    if ( mainMenu.parent == menuLayer ) {
        menuLayer.removeChild( mainMenu );
    }
    

    这将在删除之前验证 mainMenu 实际上是 menuLayer 的子项。您不能从实际上不是其父级的父级中删除子级。想象一下,国家将一个孩子带走并从绑匪手中夺走他们的监护权。这不是最漂亮的比较,但它给出了正确的想法。

    【讨论】:

    • 虽然这是真的,但它的代码本质上只会在问题发生时处理问题,并允许允许它发生的错误逻辑继续存在。
    【解决方案4】:

    如果不查看游戏结束的处理方式,我无法验证这一点,但我认为潜在的问题是您没有在每次玩游戏时都删除事件侦听器。因此,当您返回主菜单并再次添加它们时,您现在有两个用于 playAgainBtn 的侦听器。

    因此,当您结束游戏并单击 playAgainBtn 时,startGame 被称为 TWICE。所以第一次它删除的东西很好,第二次 - 没有什么可以删除的。鉴于您当前的设计,您的所有事件侦听器都可能存在此问题。

    如果是这种情况,您只需在删除菜单时删除事件侦听器即可。

    我建议每当您激活菜单时添加侦听器,然后在隐藏时删除它们。也许有两个方法,addMenuListeners 和 removeMenuListeners

    您可以创建这两个函数并在适当的地方使用它们:

       function addMenuListeners():void
       {
            mainMenu.playBtn.addEventListener(MouseEvent.CLICK, startGame);
            mainMenu.howToPlayBtn.addEventListener(MouseEvent.CLICK, showInstructions);
            mainMenu.aboutBtn.addEventListener(MouseEvent.CLICK, showAbout);
            howtoPlay.backBtn.addEventListener(MouseEvent.CLICK, menuReturn);
            gameEnd.playagainBtn.addEventListener(MouseEvent.CLICK, startGame);
            gameAbout.backBtn.addEventListener(MouseEvent.CLICK, menuReturn);
       }
    
    function removeMenuListeners():void
    {
            mainMenu.playBtn.removeEventListener(MouseEvent.CLICK, startGame);
            mainMenu.howToPlayBtn.removeEventListener(MouseEvent.CLICK, showInstructions);
            mainMenu.aboutBtn.removeEventListener(MouseEvent.CLICK, showAbout);
            howtoPlay.backBtn.removeEventListener(MouseEvent.CLICK, menuReturn);
            gameEnd.playagainBtn.removeEventListener(MouseEvent.CLICK, startGame);
            gameAbout.backBtn.removeEventListener(MouseEvent.CLICK, menuReturn);
    }
    

    如果您遵循在不使用时始终删除事件侦听器的规则,则可以避免此问题。

    【讨论】:

    • 嗯,所以我认为无论在哪里使用menuLayer.addChild(mainMenu),我都会添加监听器,而在使用menuLayer.removeChild(mainMenu) 时,我会删除监听器吗?
    • 我更新了我的问题。我尝试实施您建议的解决方案,这是一个非常好的主意,但我的执行可能在某处有所欠缺,因为我仍然得到Supplied DisplayObject must be a child of the caller at Main/startGame()
    • 你没有按我说的做,我没有看到任何删除事件监听器的代码。
    • 糟糕,不小心更改了代码。我现在已经更新了,所以欢迎任何建议
    【解决方案5】:

    if( mainMenu.parent ){ mainmenu.parent.removeChild( mainMenu );} 或者它已经被删除/根本没有添加?

    【讨论】:

      【解决方案6】:

      改变这一行

      menuLayer.removeChild(mainMenu);
      

      到这个..

      if (mainMenu.parent != null && mainMenu.parent == menuLayer)
      {
        menuLayer.removeChild(mainMenu);
      }
      

      希望能解决。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-09-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-29
        • 1970-01-01
        • 2018-12-08
        • 2012-04-15
        相关资源
        最近更新 更多