Прерывистая анимация Flex 4.5.1 при использовании события MOUSE_MOVE для запуска анимации ‹s:Move› TileGroup внутри Canvas

В основном то, что я пытаюсь сделать, это изменить атрибуты horizontalCenter и verticalCenter компонента TileGroup обратно пропорционально движению мыши и использовать эффект искрового движения, чтобы сделать это движение плавным. TileGroup является дочерним элементом mx:Canvas, для которого установлено значение 100 % в ширину и 100 % в высоту. Их около 20 или около того BorderContainers внутри TileGroup.

Пример того, как это должно работать, см. на странице http://gallery.artofgregmartin.com/.

Моя версия движется точно так же, но не так плавно. Глядя на использование ЦП, как мое, так и его использование примерно одинаково (80-90%, когда идет движение), но мы различаемся по использованию графического процессора. Мой использует только около 4%, а его около 10%.

Вот мой код движения:

private function onMouseMove(event:MouseEvent):void{
    var stageCenterX:Number = this.stage.stageWidth/2;
    var stageCenterY:Number = this.stage.stageHeight/2;
    var sliderPanelCenterX:Number = sliderPanel.width/2;
    var sliderPanelCenterY:Number = sliderPanel.height/2;
    var mouseX:Number = event.stageX;
    var mouseY:Number = event.stageY;
    var offsetX:Number = 0;
    var offsetY:Number = 0;
    var padding:Number = 400;

    var multX:Number = (stageCenterX - mouseX)/stageCenterX;
    offsetX = (multX * sliderPanelCenterX);

    if(mouseX <= stageCenterX){
        offsetX = offsetX - Math.abs(multX * stageCenterX) + Math.abs(multX * padding);
    }
    else {
        offsetX = offsetX + Math.abs(multX * stageCenterX) - Math.abs(multX * padding);
    }

    var multY:Number = (stageCenterY - mouseY)/stageCenterY;
    offsetY = (multY * sliderPanelCenterY);

    if(mouseY <= stageCenterY){
        offsetY = offsetY - Math.abs(multY * stageCenterY) + Math.abs(multY * padding); 
    }
    else {
        offsetY = offsetY + Math.abs(multY * stageCenterY) - Math.abs(multY * padding);
    }

    panelHC = Math.round(offsetX);
    panelVC = Math.round(offsetY);

    movePanel.captureStartValues();
    sliderPanel.verticalCenter = panelVC;   //sliderPanel is the id for the TileGroup
    sliderPanel.horizontalCenter = panelHC;
    movePanel.play();
}

А вот и благоговейный код mxml:

<fx:Declarations>
    <s:Move id="movePanel" target="{sliderPanel}" />
</fx:Declarations>
<mx:Canvas width="100%" height="100%" backgroundColor="#111111" 
    horizontalScrollPolicy="off" 
    verticalScrollPolicy="off">
    <s:TileGroup id="sliderPanel" horizontalGap="2" verticalGap="2" width="2010" 
       horizontalCenter="0" verticalCenter="0" z="1" />
</mx:Canvas>

person Nigel    schedule 01.09.2011    source источник


Ответы (3)


Это может произойти:

Flash по умолчанию обновляет экран покадрово - после кадра. События мыши могут отправляться несколько раз за кадр. Обновление экрана использует только значения из последнего отправленного события мыши.

Вы можете убедить экран обновиться немедленно, вызвав метод события updateAfterEvent(). Если вы это сделаете, Flash поместит дополнительное обновление экрана прямо в ваш кадр.

Вы можете отслеживать обновления экрана, прослушивая событие RENDER любого объекта отображения. Вот тестовый класс, который показывает updateAfterEvent в действии. Есть 2 поля, которые вы можете навести мышью. В левом поле используется updateAfterEvent(). Правое поле обновляется при обычном обновлении экрана. Вы увидите, что левое поле сразу обновится. Вместо этого правое поле обновляется после завершения кадра. Поскольку частота кадров равна 0,5, это может занять до 2 секунд. Также попробуйте переместить мышь в оба поля. Левое поле будет обновляться немедленно, правое — только кадр за кадром.

package {
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.utils.getTimer;

    public class UpdateAfterEvent2 extends Sprite {
        public var box1 : Sprite;
        public var box2 : Sprite;

        public function UpdateAfterEvent2() {
            stage.frameRate = .5;

            box1 = new Sprite();
            box1.name = "box1";
            box1.x = 10;
            box1.y = 10;
            colorize(box1, 0xFF0000);
            box1.addEventListener(MouseEvent.MOUSE_OVER, mouseOver);
            box1.addEventListener(MouseEvent.MOUSE_OUT, mouseOut);
            box1.addEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
            addChild(box1);

            box2 = new Sprite();
            box2.name = "box2";
            box2.x = 70;
            box2.y = 10;
            colorize(box2, 0xFF0000);
            box2.addEventListener(MouseEvent.MOUSE_OVER, mouseOver);
            box2.addEventListener(MouseEvent.MOUSE_OUT, mouseOut);
            box2.addEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
            addChild(box2);

            addEventListener(Event.ENTER_FRAME, enterFrame);
            addEventListener(Event.EXIT_FRAME, exitFrame);
            addEventListener(Event.RENDER, render);
        }

        private function enterFrame(event : Event) : void {
            trace ("----------------enterFrame", getTimer());
        }

        private function exitFrame(event : Event) : void {
            trace ("----------------exitFrame", getTimer());
        }

        private function mouseMove(event : MouseEvent) : void {
            var box : Sprite = event.currentTarget as Sprite;
            trace ("move", box.name, getTimer());
            if (box == box1) {
                trace ("--------UPDATE_AFTER_EVENT");
                event.updateAfterEvent();
            }

            box.alpha = box.alpha == 1 ? .5 : 1;

            stage.invalidate();
        }

        private function mouseOut(event : MouseEvent) : void {
            var box : Sprite = event.currentTarget as Sprite;
            trace ("out", box.name, getTimer());
            if (box == box1) {
                trace ("--------UPDATE_AFTER_EVENT");
                event.updateAfterEvent();
            }
            colorize(box, 0xFF0000);

            stage.invalidate();
        }

        private function mouseOver(event : MouseEvent) : void {
            var box : Sprite = event.currentTarget as Sprite;
            trace ("over", box.name, getTimer());
            if (box == box1) {
                trace ("--------UPDATE_AFTER_EVENT");
                event.updateAfterEvent();
            }
            colorize(box, 0x0000FF);

            stage.invalidate();
        }

        private function render(event : Event) : void {
            trace ("--------RENDER", getTimer());
        }

        private function colorize(box : Sprite, color : uint) : void {
            with (box.graphics) {
                clear();
                beginFill(color);
                drawRect(0, 0, 50, 50);
            }
        }
    }
}
person Kaken Bok    schedule 01.09.2011
comment
Ну, я попробовал это, и, похоже, это имело противоположный эффект. Я добавил метод event.updateAferEvent() в обработчик события mouse_move, и все стало безумно прерывистым. - person Nigel; 01.09.2011

Возможно ли, что ваш эффект никогда не применяется?

В обработчике событий вы напрямую устанавливаете свойства verticalCenter и horizontalCenter для панели. Насколько я понимаю, панель здесь не анимирована, а жестко установлена ​​в новое положение.

Бьюсь об заклад, что комментируя:

// movePanel.captureStartValues();
sliderPanel.verticalCenter = panelVC;   //sliderPanel is the id for the TileGroup
sliderPanel.horizontalCenter = panelHC;
// movePanel.play();

не повлияет на вашу анимацию.

Для вашего movePanel не заданы значения анимации. Вы должны сделать что-то вроде:

movePanel.xBy = ...
movePanel.xTo = ...
movePanel.yBy = ...
movePanel.yTo = ...
...

Документы: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/effects/Move.html

person Kaken Bok    schedule 01.09.2011
comment
Да, эффект работал правильно, просто он был очень прерывистым. Вы могли видеть ослабление, как только вы переставали двигать мышь, панель продолжала скользить в нужное положение. Но я думаю, что могу найти что-то, используя библиотеку TweenMax. Я заменил все биты movePanel на tweenmax, и теперь он НАМНОГО плавнее. - person Nigel; 01.09.2011

Что ж, может показаться, что встроенные процедуры анимации не совсем оптимизированы. Я отключил все методы анимации для TweenMax ( http://www.greensock.com/tweenmax/ ), а также следовал некоторым советам по оптимизации на этом сайте, и теперь он работает как по маслу.

Спасибо за все полезные ответы!

-Найджел

Метод ТвинМакс:

Replaced

movePanel.captureStartValues();
movePanel.easer = powerEasing;
sliderPanel.verticalCenter = panelVC;
sliderPanel.horizontalCenter = panelHC;
movePanel.stop();
movePanel.play();

With

TweenMax.to(sliderPanel,2.5,
  {verticalCenter:panelVC,horizontalCenter:panelHC, ease:Back.easeOut});
person Nigel    schedule 01.09.2011