Flash AS3 - Drag and drop multiple objects to multiple targets

前端 未结 2 1847
刺人心
刺人心 2021-01-26 10:32

I have multiple objects to drag to multiple targets. I have a code without error. I am using multiple functions. But I wonder if I pass the objects and the specific target with

相关标签:
2条回答
  • 2021-01-26 10:44

    Despite the fact Vesper's answer is already accepted, I think it to be far too brief and insufficient, on top of that it doesn't actually answer how to design a system where any number of objects could be dropped to any number of targets, without substantial changes to the code.

    // Unlike the Object class, that allows String keys only
    // the Dictionary class allows you to store and
    // access data by the object instance.
    var theValids:Dictionary = new Dictionary;
    
    // We'll store the original (x,y) coordinates here.
    var theOrigin:Point = new Point;
    
    // The Sprite class is the superclass of MovieClip, furthermore,
    // the startDrag method defined for Sprite class, so unless you
    // create your own dragging code, you are bound to use Sprites,
    // while you cannot drag SimpleButtons and TextFields this way.
    // We'll store the current dragged object here.
    var theObject:Sprite;
    
    // This first argument is the object you want to be draggable.
    // The "...targets:Array" means you can call this method with
    // any number of arguments, the first one is mandatory, the
    // rest will be passed in a form of Array (empty Array if you
    // call this method with a single argument).
    function setupDraggable(source:Sprite, ...targets:Array):void
    {
        // Make the object draggable.
        source.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
        source.mouseChildren = false;
        source.mouseEnabled = true;
        source.buttonMode = true;
    
        // Keep the list of the object's targets so it can be
        // retrieved later by the key of the object itself.
        theValids[source] = targets;
    }
    
    // Ok, let's setup the objects and link them to their designated
    // targets. The whole point of the rest of the code is to make
    // this one part as simple as it possible: you just edit
    // these lines to tell which one objects go where.
    
    // This object can be dropped to a single target.
    setupDraggable(obj_1 , target1);
    
    // These objects can go to two targets each.
    setupDraggable(obj_10, target1, target10);
    setupDraggable(obj_2 , target2, target20);
    
    // This one object can be dropped to any of targets.
    setupDraggable(obj_20, target1, target10, target2, target20);
    
    // The MOUSE_DOWN event handler.
    function onDown(e:MouseEvent):void
    {
        // Get the reference to the object under the mouse.
        theObject = e.currentTarget as Sprite;
    
        // Keep the object's initial position.
        theOrigin.x = theObject.x;
        theOrigin.y = theObject.y;
    
        // Put the dragged object on top of anything else.
        // We are operating in the parent context of all these
        // objects here so there's no need to address anObj.parent.
        setChildIndex(theObject, numChildren - 1);
    
        // Start dragging.
        theObject.startDrag(true);
    
        // Listen to the MOUSE_UP event, which could happen offstage
        // and out of the dragged object, so the only reliable
        // way is to listen it from the Stage. That's why we
        // are keeping theObject reference as an additional
        // variable, without relying on event's data.
        stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
    }
    
    // The MOUSE_UP event handler.
    function onUp(e:MouseEvent):void
    {
        // Unsubscribe the MOUSE_UP event handler.
        stage.removeEventListener(MouseEvent.MOUSE_UP, onUp);
    
        // Stop the dragging process.
        theObject.stopDrag();
    
        // Let's assume there could be more than a single collision.
        // We need to figure the one target that is closest.
        var theTarget:DisplayObject;
        var theDistance:int = 100000;
    
        // Store the dragged object position so we can
        // measure distances to the valid collisions, if any.
        var thePlace:Point = theObject.localToGlobal(new Point);
    
        // Now, the magic. Lets browse through the
        // valid targets and see if there's a collision.
        for each (var aTarget:DisplayObject in theValids[theObject])
        {
            if (theObject.hitTestObject(aTarget))
            {
                // Let's see if the current collision is closer
                // to the dragged object, than the previous one
                // (if any, that's what initial 100000 for).
                var aPlace:Point = aTarget.localToGlobal(new Point);
                var aDistance:int = Point.distance(aPlace, thePlace);
    
                if (aDistance < theDistance)
                {
                    theTarget = aTarget;
                    theDistance = aDistance;
                }
            }
        }
    
        // If there's at least one collision,
        // this variable will not be empty.
        if (theTarget)
        {
            // Make the object non-interactive.
            theObject.removeEventListener(MouseEvent.MOUSE_DOWN, onDown);
            theObject.mouseEnabled = false;
            theObject.buttonMode = false;
    
            // Glue the dragged object to the center of the target.
            theObject.x = theTarget.x;
            theObject.y = theTarget.y;
        }
        else
        {
            // If we're here, that means there was no valid collisions,
            // lets return the object to its designated place.
            theObject.x = theOrigin.x;
            theObject.y = theOrigin.y;
        }
    
        // Clean-up. Remove the reference, the object is no longer
        // being dragged, so you won't need to keep it.
        theObject = null;
    }
    

    P.S. I didn't test it, but I think I put enough comments to explain the whole idea.

    0 讨论(0)
  • 2021-01-26 11:05

    You should somehow make your draggable objects know their targets, thus when your SWF registers an end drag event, the object that was being dragged would check against its target and if not colliding, then float/jump back. Since your objects derive from MovieClips, it's possible to add custom properties to them without doing any declarations, but be sure to check if there is something in a custom property before using it. Let's say you have assigned each draggable object a desiredTarget as whatever target you need them to be dragged. Then, you can do like this:

    function dropIt(e:MouseEvent):void {
        var desiredTarget:MovieClip=e.target.desiredTarget as MovieClip; // get where this should be placed
        e.target.stopDrag(); // we still need to release the dragged object
        if (!desiredTarget) return; // no target - nothing to do (also helps with debug)
        if (e.target.hitTestObject(desiredTarget)) {
            e.target.buttonMode=false;
            e.target.x=desiredTarget.x;
            e.target.y=desiredTarget.y;
        } else {
            // move dragged object back to starting position
            e.target.x=e.target.startX;
            e.target.y=e.target.startY;
        }
    }
    
    0 讨论(0)
提交回复
热议问题