5/18/2011

Drag + Ease

startDrag and stopDrag are great methods for drag/drop in Flash BUT they do not provide easing. This post will teach you how. This would also make a great content scroller... with inertia!

Since we have to control the dragged object's movements for ease, we will not be using startDrag and stopDrag. We learned how to do movement with ease in a previous post, so we can adapt it for our usage here. The general code for easing is: obj.x -= (obj.x - destination.x) / speed; obj.y -= (obj.y - destination.y) / speed; In the above code, obj follows and eases to destination point. Applying this knowledge for our object dragging, we now just need to update the destination point on MOUSE_DOWN and stop updating it on MOUSE_UP. Something like: import flash.events.MouseEvent; import flash.geom.Point; import flash.events.Event; var destination:Point=new Point(); var dragging:Boolean=false; var speed:Number=5; obj.addEventListener(MouseEvent.MOUSE_DOWN,startdrag); stage.addEventListener(MouseEvent.MOUSE_UP,stopdrag); obj.addEventListener(Event.ENTER_FRAME,followmouse); function startdrag(e:MouseEvent):void{ dragging=true; } function stopdrag(e:MouseEvent):void{ dragging=false; } function followmouse(e:Event):void{ if(dragging){ destination.x=mouseX; destination.y=mouseY; } obj.x-=(obj.x-destination.x)/speed; obj.y-=(obj.y-destination.y)/speed; } As mentioned, we have a flag dragging to indicate whether the object is being dragged or not. It is set to true on mouse down and false on mouse up. If it is dragging, we update destination point to the mouse position so the object will move/follow there. Also notice that mouse up event is added to stage. That takes care of bugs involving mouse leaving the stage.

If you were to test the above code, you will immediately notice that the registration point moves to the destination point. This is like Flash's startDrag method with its first parameter lockCenter=true. To fix this, we need to record and apply an offset of where the object was pressed. Like so: import flash.events.MouseEvent; import flash.geom.Point; import flash.events.Event; var destination:Point=new Point(); var dragging:Boolean=false; var speed:Number=5; var offset:Point=new Point(); // our offset obj.addEventListener(MouseEvent.MOUSE_DOWN,startdrag); stage.addEventListener(MouseEvent.MOUSE_UP,stopdrag); obj.addEventListener(Event.ENTER_FRAME,followmouse); function startdrag(e:MouseEvent):void{ offset.x=obj.mouseX*obj.scaleX; // record offset (pt obj is dragged offset.y=obj.mouseY*obj.scaleY; dragging=true; } function stopdrag(e:MouseEvent):void{ dragging=false; } function followmouse(e:Event):void{ if(dragging){ destination.x=mouseX; destination.y=mouseY; } obj.x-=(obj.x-(destination.x-offset.x))/speed; // apply offset obj.y-=(obj.y-(destination.y-offset.y))/speed; } AND THAT'S IT! (drag around)


ADDING BOUNDARIES
For using it as a content scroller, you might want to put boundaries on the object. You can do so inside the ENTER_FRAME function. Something like: import flash.geom.Rectangle; var bounds:Rectangle=new Rectangle(0,0,stage.stageWidth,stage.stageHeight); function followmouse(e:Event):void{ if(dragging){ destination.x=mouseX; destination.y=mouseY; } obj.x-=(obj.x-(destination.x-offset.x))/speed; // apply offset obj.y-=(obj.y-(destination.y-offset.y))/speed; if(obj.x>bounds.left){ obj.x=bounds.left; } if(obj.x<-obj.width+bounds.right){ obj.x=-obj.width+bounds.right; } if(obj.y>bounds.top){ obj.y=bounds.top; } if(obj.y<-obj.height+bounds.bottom){ obj.y=-obj.height+bounds.bottom; } }

P.S. naturally, there are plenty of ways to optimize this code e.g. checking conditions whether a position update is necessary, etc

19 comments:

  1. Been looking for days to do this. Thanks so much.

    I have a question regarding boundaries.

    If I want to limit the boundaries for obj to lets say 50 px left and right on the x-axis and only 200 top and bottom on the y-axis, how would I achieve this?

    thanks.

    ReplyDelete
  2. Hi Micky
    Just set the boundaries to:

    var bounds:Rectangle=new Rectangle(-50,-200,100,400);

    If the object you are dragging is smaller than the bounded area and you want it to remain in that area, reverse the last 4 conditionals in the above code. (less than to more than, vice versa)

    ReplyDelete
  3. There's an issue with the code, I typed it exactly the same, and yet my symbol keeps returning to its original position when I want to drag it a second time.

    ReplyDelete
  4. Works fine when I copy+pasted the code. Probably will need to see your source to see what's going on

    ReplyDelete
  5. Hey, it's me again.
    I fixed it by changing the first two lines in startdrag to the following:

    offset.x = mouseX - obj.x;
    offset.y = mouseY - obj.y;

    I'm not sure why you were multiplying with the scale properties.

    ReplyDelete
  6. This is exactly what i have been searching for, THANK YOU SO MUCH!!!

    ReplyDelete
  7. Thanks heaps, this was really helpful

    ReplyDelete
  8. Hi and thanks for this! That was really helpful for me too.

    I wonder if someone tried to get it into an iPhone.
    I did, but it is too abrupt in the easing motion.

    When i test my app in my desktop is really smooth and fine.
    Have you some tips?
    Thanks!

    ReplyDelete
  9. P.S. I did it on AIR for iOS
    Thanks again

    ReplyDelete
  10. Hi there,

    Great script, very usefull. However I bumped into 1 little bug. I have a gameMap which I drag and inside the gameMap I placed a couple of building_mc movieclips. When the gameMap starts to slow down the building_mc's start to shake, but not in sync with the gameMap. Does anybody knows what can cause this? I could upload the .fla if you like.

    Thanks in advance!

    ReplyDelete
  11. Wonderful, thankyou

    ReplyDelete
  12. sorry guys, my file host is down... gimme a bit to get them back

    ReplyDelete
  13. Any chance you're willing to make an equivalent to this, but with zooming in/out? Thanks!

    ReplyDelete
  14. should be basically the same - just replace x,y with scaleX,scaleY

    ReplyDelete
  15. Awesome... Really helped me...

    ReplyDelete
  16. txh, you helped me a lot

    ReplyDelete
  17. Thanks! Really helped a lot

    ReplyDelete