dcsimg
A Flash Developer Resource Site

Results 1 to 9 of 9

Thread: AS3 drag w/ avoiding objects

  1. #1
    Junior Member
    Join Date
    Jan 2011
    Posts
    6

    AS3 drag w/ avoiding objects

    He guys,

    Here's my problem - I want to create a function in which I can drag an object (movieclip) which will bump into other objects (other movieclips) on screen without overlapping them (i.e. the object cannot be dragged over or through other movieclips).

    I'd also appreciate a way to move the other objects rather than block the dragged objects (e.g. when dragged object is bumping into another object, the other objects is pushed in the same direction).

    Please advise (rather desperate here). Thanks.

  2. #2
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    You'll have to use an enter frame or mouse move listener to test for the dragged object intersecting the other objects. If you detect that, then you'll need to calculate a new position for your other object. Just determine the minimum distance that your objects need to be apart, and the angle between their centers, and move the other object to the minimum distance on that angle.

  3. #3
    Junior Member
    Join Date
    Jan 2011
    Posts
    6
    The only problem I'm still facing is that if I drag the object too fast, it goes "into" the other object. The dragging stops, but then the dragged object is positioned "on" the collided one. Is there a way around that?

    If drag is too fast, the dragged object gets "stuck" over the collided object. I can drag it back and I can't drag it further in (the desired effect), but it should stop just at the border. of the collided object, not on it (this doesn't happen if I drag slowly).

  4. #4
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    I don't know what you're doing, but it's not what I described. Here's some code that does do what I described.
    Code:
    package 
    {
    	import flash.display.Sprite;
    	import flash.events.Event;
    	import flash.events.MouseEvent;
    	
    	public class Main extends Sprite 
    	{
    		private var draggable:Sprite;
    		private var pushables:Vector.<Sprite> = new Vector.<Sprite>();
    		
    		public function Main():void 
    		{
    			if (stage) init();
    			else addEventListener(Event.ADDED_TO_STAGE, init);
    		}
    		
    		private function init(e:Event = null):void 
    		{
    			removeEventListener(Event.ADDED_TO_STAGE, init);
    			// entry point
    			for (var i:int = 0; i < 10; i++) {
    				var p:Sprite = makePushable();
    				addChild(p);
    				pushables.push(p);
    			}
    			addEventListener(Event.ENTER_FRAME, doFrame);
    		}
    		
    		private function makePushable():Sprite {
    			var p:Sprite = new Sprite();
    			p.graphics.beginFill(Math.random() * 0xffffff);
    			p.graphics.drawCircle(0, 0, 5 + Math.random() * 20);
    			p.graphics.endFill();
    			p.addEventListener(MouseEvent.MOUSE_DOWN, beginDrag);
    			p.addEventListener(MouseEvent.MOUSE_UP, endDrag);
    			p.x = Math.random() * stage.stageWidth;
    			p.y = Math.random() * stage.stageHeight;
    			return p;
    		}
    		
    		private function doFrame(e:Event):void {
    			if (draggable) {
    				for (var i:int = 0; i < pushables.length; i++) {
    					var p:Sprite = pushables[i];
    					if (p == draggable) {
    						continue;  //don't compare to self
    					}
    					if (draggable.hitTestObject(p)) {
    						var angle:Number = Math.atan2(p.y - draggable.y, p.x - draggable.x);
    						var widthsum:Number = (draggable.width + p.width)/2;
    						p.x = draggable.x + Math.cos(angle) * widthsum;
    						p.y = draggable.y + Math.sin(angle) * widthsum;
    					}
    				}
    			}
    		}
    		
    		private function beginDrag(e:MouseEvent):void {
    			if (draggable) {
    				draggable.stopDrag();
    			}
    			draggable = Sprite(e.currentTarget);
    			draggable.startDrag();
    		}
    		
    		private function endDrag(e:MouseEvent):void {
    			draggable.stopDrag();
    			draggable.stopDrag();
    		}
    		
    	}
    	
    }
    Note that this does not prevent one object from being pushed into another, but you could extend the enterframe to compare each object with each other object to do that but it would be an n^2 process rather than n.

  5. #5
    Junior Member
    Join Date
    Jan 2011
    Posts
    6
    Quote Originally Posted by 5TonsOfFlax View Post
    Note that this does not prevent one object from being pushed into another, but you could extend the enterframe to compare each object with each other object to do that but it would be an n^2 process rather than n.
    Thank you.
    How do I extend the enterframe, like you suggested?
    What are the implications of going to n^2 instead of n?

  6. #6
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Basically, instead of doing a single loop and checking everything against the dragging instance, you'll do a nested loop and test everything against everything else. Even that won't resolve all overlaps in a single frame since one interaction may push an object into another interaction, but over time they should resolve.

    The difference between n^2 and n means that on each frame, the amount of work done depends on the square of the number of items rather than just the number of items. If you had 4 items, n = 4, and n^2 = 16. This sort of analysis is called Big-O, and it's a way of comparing the complexity of algorithms. O(1) is constant, O(n) is linear, and O(n^2) is quadratic.

    If you have 100 objects, n = 100, and n^2 = 10000. An O(n) algorithm can probably handle 100 objects in a frame, but an O(n^2) algorithm will do the same amount of work at only 10 objects.

  7. #7
    Junior Member
    Join Date
    Jan 2011
    Posts
    6
    If I cannot completely eliminate the "drag over" side effect, maybe I should look into some 2D engines. The problem is that I don't want to start messing with Flex Builder and complicated projects. I just want to have my one file. What would you recommend?

  8. #8
    Junior Member
    Join Date
    Jan 2011
    Posts
    6
    Maybe I can limit the dragging to follow the frames, so that you cannot drag it more than a pixel-per-frame. Do you have any idea how I could do that?

  9. #9
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    I wouldn't do that, it's a very slow rate.

    Basically, I wouldn't worry about the instantaneous drag-over problem, since it should resolve itself in just a few frames anyway. You can always do more than one reconciliation cycle per frame, if necessary, too.

    If you do want to use an existing physics engine, box2d is the standard.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center