|
-
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.
-
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.
-
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).
-
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.
-
 Originally Posted by 5TonsOfFlax
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?
-
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.
-
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?
-
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?
-
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|