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
else:
# 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:
picked.append(piece)
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:
movingPiece.setPos(location)
``````

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.