如何使用ActionScript拖动图像以在屏幕上平滑移动



我原以为这是一项简单的任务,但我错了。

我使用了一个精灵来显示图像,当用户拖动它时(MOUSE_DOWN和MOUSE_MOVE),我得到了MOUSE_MOVE中的位置,并计算了偏移:

 var current: Point = new Point(event.localX, event.localY);
 sprite.x = current.x - start.x;
 sprite.y = current.y - start.y;

它很有效,但并不顺利。有更好的解决方案吗?


更新

经过一天的调试,我终于找到了原因。

更大的fps可以使其更平滑,但这不是这个问题的关键。

关键是我应该使用stage来监听MOUSE_MOVE,而不是图像本身。在获取鼠标位置时,我应该使用event.stageX/Y(或stage.mouseX/Y),而不是event.localX/Y。运动图像中的event.localX/Y既不稳定也不平滑,这导致了我的问题。

以下是我的工作代码,请尽情享受:)

package {
    import flash.display.Bitmap;
    import flash.display.Loader;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.net.URLRequest;
    import flash.text.TextField;
    public class DragIssue extends Sprite {
        private static const URL: String = "assets/m1.jpg";
        private var self: DragIssue;
        private var sprite: Sprite;
        private var startPoint: Point;
        private var offsetX: Number = 0;
        private var offsetY: Number = 0;
        public function DragIssue() {
            self = this;
            init();
            loadImage();
        }
        protected function init(): void {
            if (stage == null) {
                this.addEventListener(Event.ADDED_TO_STAGE, on_addedToStage);
            } else {
                stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
            }
            function on_addedToStage(event: Event): void {
                self.removeEventListener(Event.ADDED_TO_STAGE, on_addedToStage);
                stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
            }
        }
        public function loadImage(): void {
            var loader: Loader = new Loader();
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoaded);
            loader.load(new URLRequest(URL));
            function imageLoaded(event: Event): void {
                var bitmap: Bitmap = event.target.content as Bitmap;
                self.sprite = new Sprite();
                sprite.addChild(bitmap);
                self.addChild(sprite);
                sprite.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
                sprite.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
            }
        }
        private function onMouseMove(event: MouseEvent): void {
            if (startPoint) {
                sprite.x = offsetX + event.stageX - startPoint.x;
                sprite.y = offsetY + event.stageY - startPoint.y;
            }
        }
        private function onMouseUp(event: MouseEvent): void {
            startPoint = null;
            offsetX = sprite.x;
            offsetY = sprite.y;
        }
        private function onMouseDown(event: MouseEvent): void {
            startPoint = new Point(event.stageX, event.stageY);
        }
    }
}

在这里,试试这个。这只是一个简单的黑色方块,但它看起来很好,直到你真的开始拖动它。如前所述,将帧速率设置为更高的值是理想的。在这种情况下,出于内存原因,我决定在MOUSE_DOWN中将帧速率提高到60fps,在MOUSE_up中将其降低到24。很明显,你可以随心所欲地改变这一点。

import flash.display.*;
import flash.events.*;

var startX:Number;
var startY:Number;
var shape:Sprite = new Sprite();
shape.graphics.beginFill(0x000000);
shape.graphics.drawRect(0,0,50,50);
shape.graphics.endFill();
this.addChild(shape);
shape.addEventListener(MouseEvent.MOUSE_DOWN,this.mouseDown);
function mouseDown(e:MouseEvent = null):void{
    stage.frameRate = 60;
    startX = stage.mouseX - shape.x;
    startY = stage.mouseY - shape.y;
    stage.addEventListener(MouseEvent.MOUSE_MOVE,this.mouseMove);
    shape.addEventListener(MouseEvent.MOUSE_UP,this.mouseUp);
}
function mouseMove(e:MouseEvent = null):void{
    shape.x = stage.mouseX - startX;
    shape.y = stage.mouseY - startY;
}
function mouseUp(e:MouseEvent = null):void{
    shape.removeEventListener(MouseEvent.MOUSE_UP,this.mouseUp);
    stage.removeEventListener(MouseEvent.MOUSE_MOVE,this.mouseMove);
    stage.frameRate = 24;
}

确保您正在删除MOUSE_UP上的MOUSE_MOVE事件。这是关键。否则,您将在每个MOUSE_DOWN上重新添加事件,并最终同时重复运行相同的代码。对不起,我的语法不是100%正确;我在CS5.5中很快就完成了这项工作,而不是在Flash Builder中完成。

如果你想获得流畅的拖动体验,这里有一个方法可以使用:(假设你拖动的东西被称为"dragee",这个代码在dragee的父级范围内)

function startDragging():void {
    dragee.addEventListener(Event.ENTER_FRAME,dragUpdate);
}
function stopDragging():void {
    dragee.removeEventListener(Event.ENTER_FRAME,dragUpdate);
}
var decay:Number = .25; //1 is no decay, .1 would be cazy slow
function dragUpdate(e:Event):void {
    dragee.x += decay * (mouseX - dragee.x);
    dragee.y += decay * (mouseY - dragee.y);
}

必须使用高帧速率才能实现平滑移动。最佳帧速率为60fps,因为它是大多数LCD显示器的默认帧速率。

我手头没有代码,所以我把代码放在这里(未测试)

yourClip.addeventListenner(MouseEvent.MOUSE_DOWN, startDrag);
function startDrag(e:MouseEvent = null):void{
    // record positon of the mouse relative to the clip
    deltaX=stage.mouseX-yourClip.x;
    deltaY=stage.mouseY-yourClip.y;
    // attach on mouse move event
    yourClip.addeventListenner(MouseEvent.MOUSE_MOVE, updateDrag);
    // attach stop event (on Stage)
    Stage.addeventListenner(MouseEvent.MOUSE_UP, stopDrag);
    }
function updateDrag(e:MouseEvent = null):void{
    yourClip.x=stage.mouseX-deltaX
    yourClip.y=stage.mouseY-deltaY
}
function stopDrag(e:MouseEvent = null):void{
   yourClip.removeEventListenner(MouseEvent.MOUSE_MOVE, updateDrag);
   stage.removeEventListenner(MouseEvent.MOUSE_UP, stopDrag);
}

尝试在拖动处理程序中调用event.updateAfterEvent()。函数告诉Flash立即重新绘制舞台,而不是等到下一帧。

最新更新