为什么EventListeners在操作z-property和更改stage.quality后停止工作?

时间:2011-09-16 16:57:19

标签: flash actionscript-3 actionscript

目前,我们的一个团队遇到了一个非常奇怪的现象:在操纵z的{​​{1}}属性并改变舞台质量之后,一些嵌套MovieClip的事件监听器似乎消失了(或者至少不再对适当的事件做出反应。)

同时执行 时出现问题,更改舞台质量操纵MovieClips属性。

这是一个简单的课程,展示了这个问题:

z

任何人都可以给我一个指针在这里发生了什么?为什么package { import flash.display.StageScaleMode; import flash.display.StageAlign; import flash.display.Graphics; import flash.display.MovieClip; import flash.display.StageQuality; import flash.events.MouseEvent; public class StageQualityTestDemo extends MovieClip { private static const OVER_COLOR:uint = 0x13ff37; private static const OUT_COLOR:uint = 0x000000; private static const BACK_COLOR:uint = 0xdeadc0de; private var _qualitySetting:int = 0; private var _zoom:Number = 0.0; private var _mainsprite:MovieClip = new MovieClip(); private var _button:MovieClip = new MovieClip(); public function StageQualityTestDemo() { initDemo(); } private function initDemo():void { this.addChild(_mainsprite); _mainsprite.addChild(_button); this.stage.addEventListener(MouseEvent.MOUSE_WHEEL, handleMouseWheel); stage.quality = StageQuality.LOW; stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; drawButtonCircle(OUT_COLOR); drawMainBackground(BACK_COLOR); _button.addEventListener(MouseEvent.MOUSE_OVER, handleMouseOver); _button.addEventListener(MouseEvent.MOUSE_OUT, handleMouseOut); } private function handleMouseOver(event:MouseEvent):void { drawButtonCircle(OVER_COLOR); } private function handleMouseOut(event:MouseEvent):void { drawButtonCircle(OUT_COLOR); } private function drawMainBackground(color:uint):void { var g:Graphics = _mainsprite.graphics; g.clear(); g.beginFill(color); g.drawRect(0, 0, 500, 500); g.endFill(); } private function drawButtonCircle(color:uint):void { var g:Graphics = _button.graphics; g.clear(); g.beginFill(color); g.drawCircle(250, 250, 50); g.endFill(); } private function handleMouseWheel(event:MouseEvent):void { var motion:Number = event.delta * 5; _zoom += motion; _mainsprite.z = _zoom; if (_zoom < 0 && _qualitySetting != 0 ) { _qualitySetting = 0; trace("setting LOW"); stage.quality = StageQuality.LOW; } if (_zoom > 100 && _qualitySetting == 0 ) { _qualitySetting = 1; trace("setting HIGH"); stage.quality = StageQuality.HIGH; } } } } 上的事件监视器在缩小时停止工作,舞台质量为_button,但在放大并且舞台质量为HIGH时再次工作?救命?任何人吗?


[更新]

基于@Amy Blankenship的建议,我添加了一些LOW语句。结果是tracewillTrigger()都报告为true,但处理函数仍未被调用。

代码更改:

hasEventListener()

跟踪输出:

[...]

private var _counter:int;

[...]

private function initDemo():void {
    this.addChild(_mainsprite);
    _mainsprite.addChild(_button);
    this.stage.addEventListener(MouseEvent.MOUSE_WHEEL, handleMouseWheel);
    this.stage.addEventListener(MouseEvent.MOUSE_MOVE, handleMouseMove);
    stage.quality = StageQuality.LOW;
    stage.align = StageAlign.TOP_LEFT;
    stage.scaleMode = StageScaleMode.NO_SCALE;
    drawButtonCircle(OUT_COLOR);
    drawMainBackground(BACK_COLOR);
    _button.addEventListener(MouseEvent.MOUSE_OVER, handleMouseOver);
    _button.addEventListener(MouseEvent.MOUSE_OUT, handleMouseOut);
}

private function handleMouseMove(event:MouseEvent):void {
    if (_counter++ % 50 == 0) {
        trace("_button.willTrigger(MouseEvent.MOUSE_OVER): " + _button.willTrigger(MouseEvent.MOUSE_OVER));
        trace("_button.willTrigger(MouseEvent.MOUSE_OUT): " + _button.willTrigger(MouseEvent.MOUSE_OVER));
        trace("_button.hasEventListener(MouseEvent.MOUSE_OVER): " + _button.hasEventListener(MouseEvent.MOUSE_OVER));
        trace("_button.hasEventListener(MouseEvent.MOUSE_OUT): " + _button.hasEventListener(MouseEvent.MOUSE_OUT));
    }
}

private function handleMouseOver(event:MouseEvent):void {
    trace("handleMouseOver");
    drawButtonCircle(OVER_COLOR);
}

private function handleMouseOut(event:MouseEvent):void {
    trace("handleMouseOut");
    drawButtonCircle(OUT_COLOR);
}

[...]

[/更新]

4 个答案:

答案 0 :(得分:3)

我发现使用stage.quality = StageQuality.MEDIUM;而不是HIGH工作。 我知道flash z转换实际上是通过将剪辑转换为位图来实现的。而且这些位图不是InteractiveObjects。我想你找到了一个flash播放器的bug。 但是,希望使用中等质量的放大项目将为您提供“足够好”的质量来完成您的项目。

答案 1 :(得分:2)

我也不知道为什么正在发生这种行为,但我找到了一种解决方法。

重建显示列表可让您再次获取鼠标事件。我不知道这对你的情况有多实际;你提到这是你问题的简化版本。无论如何,这是我正在运行的代码。我仍然可以在处理鼠标事件的同时放大并改变舞台的质量:

package
{
    import flash.display.Graphics;
    import flash.display.MovieClip;
    import flash.display.StageAlign;
    import flash.display.StageQuality;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.utils.getTimer;

    public class AS3Playground extends MovieClip
    {
        private static const OVER_COLOR:uint = 0x13ff37;
        private static const OUT_COLOR:uint = 0x000000;
        private static const BACK_COLOR:uint = 0xdeadc0de;
        private var _qualitySetting:int = 0;
        private var _zoom:Number = 0.0;
        private var _mainsprite:MovieClip;
        private var _button:MovieClip;

        private var _lastKnownStageQuality:String;

        private var _counter:int;

        public function AS3Playground()
        {
            trace("AS3Playground() @"+getTimer());
            initDemo();
        }

        private function maintainDisplayOrder():void
        {
            addChild(_mainsprite);
            _mainsprite.addChild(_button);
        }

        private function initDemo():void
        {
            trace("initDemo() @"+getTimer());

            _mainsprite  = new MovieClip();
            _mainsprite.graphics.clear();
            _mainsprite.graphics.beginFill(BACK_COLOR);
            _mainsprite.graphics.drawRect(0, 0, 500, 500);
            _mainsprite.graphics.endFill();

            _button = new MovieClip();
            _button.graphics.clear();
            _button.graphics.beginFill(OUT_COLOR);
            _button.graphics.drawCircle(250, 250, 50);
            _button.graphics.endFill();

            maintainDisplayOrder();

            stage.quality = StageQuality.LOW;
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;

            _lastKnownStageQuality = stage.quality;

            stage.addEventListener(MouseEvent.MOUSE_WHEEL, handleMouseWheel);
            _button.addEventListener(MouseEvent.MOUSE_OVER, handleMouseOver);
            _button.addEventListener(MouseEvent.MOUSE_OUT, handleMouseOut);
            addEventListener(Event.ENTER_FRAME, onEnterFrame, false, 0, true);
        }

        private function onEnterFrame(event:Event):void
        {
            if (_counter++ % 50 == 0)
            {
                trace("onEnterFrame(event) @"+getTimer());
                trace("_button.willTrigger(MouseEvent.MOUSE_OVER): " + _button.willTrigger(MouseEvent.MOUSE_OVER));
                trace("_button.willTrigger(MouseEvent.MOUSE_OUT): " + _button.willTrigger(MouseEvent.MOUSE_OVER));
                trace("_button.hasEventListener(MouseEvent.MOUSE_OVER): " + _button.hasEventListener(MouseEvent.MOUSE_OVER));
                trace("_button.hasEventListener(MouseEvent.MOUSE_OUT): " + _button.hasEventListener(MouseEvent.MOUSE_OUT));
                trace("mouse: @("+mouseX+", "+mouseY+")");

                var buttonStageRect:Rectangle = new Rectangle();
                var buttonStageCoordinate:Point = _button.localToGlobal(new Point(0, 0));
                buttonStageRect.x = buttonStageCoordinate.x;
                buttonStageRect.y = buttonStageCoordinate.y;

                trace("_button stage area: @("+buttonStageRect.x+", "+buttonStageRect.y+") "+_button.width+"x"+_button.height);
                trace("hitTest? "+_button.hitTestPoint(mouseX, mouseY));
            }

            if (_lastKnownStageQuality != stage.quality)
            {
                trace("stage quality changed!");    
                maintainDisplayOrder();
                _lastKnownStageQuality = stage.quality;
            }
        }

        private function handleMouseOver(event:MouseEvent):void
        {
            trace("handleMouseOver(event) @"+getTimer());
            drawButtonCircle(OVER_COLOR);
        }

        private function handleMouseOut(event:MouseEvent):void
        {
            trace("handleMouseOut(event) @"+getTimer());
            drawButtonCircle(OUT_COLOR);
        }

        private function drawButtonCircle(color:uint):void
        {
            _button.graphics.clear();
            _button.graphics.beginFill(color);
            _button.graphics.drawCircle(250, 250, 50);
            _button.graphics.endFill();
        }

        private function handleMouseWheel(event:MouseEvent):void
        {
            trace("handleMouseWheel(event) @"+getTimer());
            var motion:Number = event.delta * 5;
            _zoom += motion;
            _mainsprite.z = _zoom;

            if (_zoom < 0 && _qualitySetting != 0 )
            {
                _qualitySetting = 0;
                trace("setting LOW");
                stage.quality = StageQuality.LOW;
            }
            if (_zoom > 100 && _qualitySetting == 0 )
            {
                 _qualitySetting = 1;
                 trace("setting HIGH");
                 stage.quality = StageQuality.HIGH;
            }

            maintainDisplayOrder();
        }
    }
}

答案 2 :(得分:1)

我相信这可能是你的问题。 Flash不支持MOUSE_WHEEL事件。

使用javascript代码和ExternalInterface有一种解决方法。 本质上,javascript拦截鼠标滚轮事件并将其传递给光标下的flash对象。

以下是解决此问题的源代码(包括评论: http://code.google.com/p/contentdisplay/source/browse/trunk/source/com/earthbrowser/ebutils/MacMouseWheelHandler.as?r=20

答案 3 :(得分:1)

在最初发生错误的团队进行了更多测试和调查后,问题自行解决了。我在我的问题中提到,所显示的代码只是该问题的简化演示。

原始产品是Flex 4.1应用程序并使用矢量图形。在地图上进行缩放或平移时,我们将stage.quality切换为LOW,因为差异几乎不明显,但质量较低,整体速度明显加快。

这个bug给团队造成了很多麻烦,因为它碰巧弹出窗口中的一些按钮没有响应,这基本上破坏了游戏的一些核心功能。然而,这个问题显然与这些弹出窗口的一些淡入效应有关。团队取消了淡入淡出,现在一切正常...... o_O

“Flash Player,你没有像普通软件一样工作吗?”

reported the issue to Adobe并且确认它是一个错误。我已经要求我们的其他团队详细报告该bug出现在附加到跟踪的bug上的情况,所以有些人会在下周获得有关该问题的更多信息。

谢谢大家的意见和建议。 :)