Drag and Drop Puzzle

I have a simple drag and drop code for a “puzzle” experiment. Participants listen to excerpts of melodies and are asked to arrange the pieces in the correct order.

I want to have the coloured circles “snap” into place when the participant drags a piece to a designated space, but still be able to move the piece afterwards to a different space. Any ideas on how I’ll might be able to do that?

This is the code I have so far:

Begin Experiment

def movePicked(picked, mouse, grabbed):
    # Move piece if we already moving that piece
    if grabbed is not None and mouse.isPressedIn(grabbed):
        grabbed.pos = mouse.getPos()
        return grabbed
        # Move newly clicked piece
        for piece in picked:
            if mouse.isPressedIn(piece) and grabbed is None:
                return piece

Begin Routine

picked = []
movingPiece = None

Each Frame

for piece in pieces:
   if mouse.isPressedIn(piece) and movingPiece is None:
movingPiece = movePicked(picked, mouse, movingPiece)

Short version, create a list of coordinates corresponding to each of the “snapped-to” locations in your begin experiment code, and then when the mouse is released, compute distance of the center of the moving piece from the center of each of those four locations, and if the distance is less than some amount, set the position of the object to that location.

I don’t fully understand your code because the code formatting got stripped (please put three ` symbols above and below code to get it to render as a code block), but it would be something like this:

Begin experiment

locations = [[x1,y1],[x2,y2],[x3,y3],[x4,y4]]
def distanceCalc(pos1, pos2):
    return math.sqrt((pos1[0]-pos2[0])**2 +(pos1[1]-pos2[1])**2)

# Some number below which you want the "snap" to occur
snapThresh = 100 

Each frame

# The if statements are just to try to identify when the mouse was released
if movingPiece is not None:
    if not mouse.isPressedIn(movingPiece):
         for location in locations:
               if distanceCalc(movingPiece.pos, location) < snapThresh:

Something along those lines should work.

Thanks for the suggestion!
I actually want the pieces to snap into place while the mouse is still clicked, but the problem is that in this case once the snapping happen the participant can’t move the piece anymore…

If you use the code above but remove the “if not mouse.isPressedIn” condition, then it will just snap to one of the locations whenever the object is within that threshold, and if not, it should snap back to the mouse’s location. So they can move it around until they release it.