Flash 在我将阶段引用到菜单类后,键盘事件未触发

Flash 在我将阶段引用到菜单类后,键盘事件未触发,flash,actionscript-3,Flash,Actionscript 3,我对我从中学习的菜单教程有问题。我已经完成并使用了该网站的大部分教程(如果不是全部的话) 无论如何,我的问题是他们的基本菜单类 package com.game.scripts.menu { import flash.display.MovieClip; import flash.display.Stage; import flash.events.Event; import com.caurina.transitions.Tweener; publi

我对我从中学习的菜单教程有问题。我已经完成并使用了该网站的大部分教程(如果不是全部的话)

无论如何,我的问题是他们的基本菜单类

package com.game.scripts.menu
{
    import flash.display.MovieClip;
    import flash.display.Stage;
    import flash.events.Event;

    import com.caurina.transitions.Tweener;

    public class BaseMenu extends MovieClip
    {
        public var stageRef:Stage;
        public var loadNext:BaseMenu;

        public function BaseMenu()
        {
            alpha = 0;
        }

        public function Unload(loadMe:BaseMenu = null):void
        {
            if(loadMe != null)
            {
                loadNext = loadMe;
            }

            Tweener.addTween(this, {alpha:0, time:0.7, onComplete:Remove});
        }

        public function Remove():void
        {
            //dispatchEvent(new Event("menuRemoved"));
            if(stageRef.contains(this))
            {
                stageRef.removeChild(this);
            }

            if(loadNext != null)
            {
                loadNext.Load();
            }
        }

        public function Load():void
        {
            stageRef.addChild(this);
            Tweener.addTween(this, {alpha:1, time:0.7});
        }
    }
}
每当我使用Remove函数时(卸载函数也使用该函数),我的stage.addEventListeners就会中断。特别是我的stage.addEventListenerKeyboardEvent.KEY_UP,另一个类中的KeyUpHandler根本不执行

有没有其他方法可以在不破坏舞台的情况下删除菜单?或者如果你知道一个更好的菜单教程,一个链接将不胜感激:D

编辑 我刚刚对Remove函数中的所有内容进行了注释,但密钥处理程序仍然不起作用

编辑2 第一次编辑只适用于我的主菜单,我的其他菜单似乎很好。我评论了这一部分

if(stageRef.contains(this))
{
    stageRef.removeChild(this);
}

我的键盘处理器工作正常。因此,我假设flash不会为我删除movieclips,或者我会没事,它会被删除吗?

我只能猜测,在调用remove之后,您为stageRef提供给菜单类的精灵没有引用,因此会被垃圾收集,因此您不再获得任何关键事件

两项建议:

确保为stageRef设置了适当的值 确保您在键盘侦听器中使用了强引用,以确保舞台未被清理。
编辑:想想看,如果你的基本菜单是从sprite或MovieClip派生出来的,我敢肯定你不需要这样做。所以只需将stageRef.removeChild更改为stage.removeChild

你的舞台并没有指向真正的舞台。有点

你也应该试着习惯使用添加到舞台上的活动

package src 
{
    import flash.display.Sprite;
    import flash.events.Event;

    public class MainDocument extends Sprite
    {
        private var myMenus:BaseMenu;

        public function MainDocument() 
        {
            addEventListener(Event.ADDED_TO_STAGE, initMain);
        }

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

            myMenus = new BaseMenu();
            addChild(myMenus);
        }

    }

}

package src 
{
    import flash.display.Sprite;
    import flash.events.Event;

    public class BaseMenu extends Sprite
    {
        public function BaseMenu() 
        {
            addEventListener(Event.ADDED_TO_STAGE, initBanseMenu);
        }

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

            trace(stage.stageHeight);
        }

    }

}
从跟踪中可以看到,无需引用即可访问阶段

这也应该很好。实际上,stage是“stage”而不是“stage”,因此请确保将“stage”发送给BaseMenu构造函数

public var stageRef:Stage;

public function BaseMenu(stageRef:Stage)
{
    this.stageRef = stageRef;
    alpha = 0;
}
好的,在这里,您可以将这些文件放在flashdevelop项目或任何您使用的项目中,并对其进行测试;-

package src 
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.ui.Keyboard;

    public class MainDocument extends Sprite
    {
        public var myMenuTest:BaseMenu;
        public var mySubMenuTest:SubMenu; 

        public function MainDocument() 
        {
            addEventListener(Event.ADDED_TO_STAGE, initMain);
        }

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

            myMenuTest = new BaseMenu(stage);
            myMenuTest.x = stage.stageWidth / 2;
            myMenuTest.y = stage.stageHeight / 2;
            //myMenuTest.Load(); // we can load our Main menu now if we want.

            mySubMenuTest = new SubMenu(stage);
            mySubMenuTest.x = 100;
            mySubMenuTest.y = 100;

            stage.addEventListener(KeyboardEvent.KEY_UP, handleKeyUp);
        }

        // for testing purposes.
        private function handleKeyUp(e:KeyboardEvent):void 
        {
            if (e.keyCode == Keyboard.UP)
                myMenuTest.Unload(mySubMenuTest);
            else if (e.keyCode == Keyboard.DOWN)
                mySubMenuTest.Unload(myMenuTest);
            else
                trace(e.keyCode);
        }
    }
}

package src 
{
    import flash.display.Sprite;
    import flash.display.Stage;

    public class BaseMenu extends Sprite
    {
        public var stageRef:Stage;
        public var loadNext:BaseMenu;

        public function BaseMenu(stageRef:Stage) 
        {
            this.stageRef = stageRef;
        }

        public function Unload(loadMe:BaseMenu = null):void
        {
            if (loadMe != null)
            {
                loadNext = loadMe;
            }
            Remove(); // add your tween.
        }

        public function Load():void
        {
            // this is just so we can have something to see for the test.
            drawTest();
            stageRef.addChild(this);
            // add your tween
        }

        public function Remove():void
        {
            if (stageRef.contains(this))
                stageRef.removeChild(this);

            if (loadNext != null)
                loadNext.Load();
        }

        protected function drawTest():void
        {
            graphics.clear();
            graphics.lineStyle(1, 0);
            graphics.beginFill(0xccccff);
            graphics.drawCircle(0, 0, 20);
            graphics.endFill();
        }
    }
}

package src 
{
    import flash.display.Stage;

    public class SubMenu extends BaseMenu
    {
        public function SubMenu(stageRef:Stage) 
        {
            super(stageRef);
        }
    }
}
这应该可以解释我的意思是如何起作用的。 要测试这个程序,只需在调试模式下加载它,并使用向上或向下箭头键在两个菜单类之间切换。无论菜单是什么,按任何其他键都会将键代码跟踪到标准输出。调试输出窗口。 显然每个文件有一个类。
希望这能澄清问题。

这是一个相当糟糕的教程。这是一个关于构建完整游戏的非常好的例子。我终于解决了这个问题。出于某种原因,除非我在加载新菜单后单击屏幕,否则key-up处理程序不会注册。基本菜单构造函数不接受参数,因为扩展基本菜单的类会得到一个错误,因为它们的构造函数带有stage参数。Event.ADDED_TO_STAGE已在我的main.as文件中使用。我是否需要在每个类中执行该检查?使用ADDED_TO_STAGE将确保在您尝试使用它之前,舞台上确实存在某些内容。这通常不是问题,但如果您不小心,可能会出现一些难以调试的问题。必须以某种方式引用stageRef。你不能只说var stageRef:Stage它必须指向某个东西。最快的方法是在创建对象时发送该引用。扩展BaseMenu的所有内容也需要有该引用。如果你走另一条路,使用added_to_stage,因为baseMenu扩展了Sprite/MovieClip,它已经有了一个与我上面的stage类似的stage的内部引用。stage heights这是你唯一可以对stage进行干净引用的两个选项。我知道我试图对BaseMenu类进行更改,但从扩展菜单类得到了一个空引用。如果我按照你建议的方式做,我会重做整个菜单系统。我更新了我的问题,指出我使用stageRef删除菜单的if语句是问题所在,是否有方法继续删除它,或者有其他方法删除movieclip。强引用是什么意思?addEventListener中的第5个参数是UseWeakRaference:Boolean,如果您将其设置为false,那么您将获得一个强引用,从而确保您正在侦听的对象在侦听时也不会被垃圾收集:为密钥处理程序提供一个强引用仍然不能解决问题。我真的不明白的是,为什么只有键处理程序受到影响,其他一切似乎都正常工作。