0

所以我得到一个错误,说提供的 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;
    }
    }
  }

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

谢谢。

4

6 回答 6

1

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

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

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

mainMenu一个更健壮的解决方案是在从删除的主菜单中单击播放按钮时调用不同的方法menuLayer,然后调用startGame(其中 as直接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()
于 2013-05-15T14:51:52.253 回答
0

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

于 2013-05-15T17:47:01.157 回答
0

更改此行

menuLayer.removeChild(mainMenu);

对这个..

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

希望它会解决。

于 2013-08-01T07:23:42.583 回答
0

您在两个不同的位置删除mainMenu。我的猜测是它会在片刻之后一次又一次地被删除。

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

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

于 2013-05-15T15:51:44.057 回答
0

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

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

于 2013-05-15T17:16:23.290 回答
0

我不知道为什么您的代码不起作用,但是无需担心,请尝试:

 MovieClip(menuLayer.parent).removeChild(menuLayer);
于 2013-05-15T14:27:56.900 回答