psychopy.org | Reference | Downloads | Github

Drag and drop into correct box

OS - Win10
PsychoPy version 2020.1.3
Standard Standalone

I want to pick up an object and drop it into one of two boxes. I want to record which box it was dropped into and then determine if it is the correct one.

I have code that picks up the object and drops it off into the box and everything works great.
EXCEPT if i just click on the box instead of dropping the object there it also works. Not what I want.

I have the following code to handle the mouse and then use the mouse component to determine if the clickable stimuli were pressed to exit the routine. This detects if the mouse is clicked in one of the boxes. But it does not tell me if the object was in it when it was clicked. I introduced a variable ‘pickedup’ to determine if the object was picked up. I then tried to use it as a condition in the mouse component. However the mouse component never exits. I suspect it may be a scope issue but do not know.

Below is the code and the mouse component settings. Any help would be appreciated.

Phil

We can’t help much to suggest edits to code if it is locked in a screen shot. Please paste the relevant code in as text:

#code_7 begin routine
#note: definition of mouse must be the same name as the mouse component
def movePicked(picked, mouse2, grabbed):
    if grabbed is not None and mouse2.isPressedIn(grabbed):
        grabbed.pos = mouse2.getPos()
        return grabbed
    else:
        for piece in picked:
            if mouse2.isPressedIn(piece) and grabbed is None:
                return piece
                
picked = []
movingPiece = None
boxchosen = None
pickedup = 0
#code_7 each frame
if mouse2.isPressedIn(blueboat1) and movingPiece is None:
    picked.append(blueboat1)
    pickedup = 1
if mouse2.isPressedIn(leftbox1):
    boxchosen = 'left'
if mouse2.isPressedIn(rightbox1):
    boxchosen = 'right'
movingPiece = movePicked(picked, mouse2, movingPiece)
thisExp.addData('boxchosen', boxchosen)

Michael,

Thanks for your feedback. I have updated my posting accordingly.

Phil

That check needs to be conditional on two things then. I haven’t been able to follow through all of the logic in your code, but instead of:

if mouse2.isPressedIn(leftbox1):
    boxchosen = 'left'

it would be something like:

if mouse2.isPressedIn(leftbox1) and movingPiece is not None:
    boxchosen = 'left'

Hi Michael,

Thanks for your reply. The piece of code you referred to is just to capture the box chosen so that I can determine if it is the correct one in a later piece of code.

The piece of code:

pickedup = 1

I use to determine that the object has been picked up. I want to use that as a condition AND the clickable stimuli box in the mouse component to exit the routine.

If I just use the clickable stimuli box and no condition the routine, PracticeTrial, exits when I click on the left or right box. However I want to exit when the object has also been picked up. I thought using stop on condition $pickedup ==1 would do that. When I use both the routine, does not exit. It looks like the condition is not met.

I suppose exiting the routine could be done directly from the code but I thought using the mouse component, as described above, would also work.

So just incorporate that in your “each frame” code, by setting continueRoutine = False when the appropriate conditions are met.

From your screenshots, it just looks like you use that expression to terminate the mouse component. All that will do is stop the mouse doing anything beyond that point. As above, terminate the routine explicitly in your “each frame” code.

I changed the code as shown below. when the mouse moves over the rightbox1 or leftbox1 the routine exits immediately and looks very jerky. However, I want it to exit when the box is clicked, not when the box is entered. Which is what I thought mouse2.isPressedin would do.
I vaguely remember reading somewhere that if you already have something picked up that you could not click again. Is that true?
It is so close to a solution but not quite.
Thanks again for your help and any further suggestions would be greatly appreciated.

Phil

#each frame
if mouse2.isPressedIn(blueboat1) and movingPiece is None:
    picked.append(blueboat1)
    pickedup = 1
if mouse2.isPressedIn(leftbox1) and movingPiece is not None:
    boxchosen = 'left'
    continueRoutine = False
if mouse2.isPressedIn(rightbox1)and movingPiece is not None:
    boxchosen = 'right'
    continueRoutine = False
movingPiece = movePicked(picked, mouse2, movingPiece)
thisExp.addData('boxchosen', boxchosen)

The requirements here keep shifting so it is tricky to give good advice…

If you drag something into an object by holding the mouse button down then, then yes, mouse.isPressedIn will be True. So you just need to extend your code logic to achieve what you want. e.g. instead of immediately setting continueRoutine = False, set some other flag, like stimulus_dropped_in_leftbox = True (having set it to False at the start of the routine). You’ll also need to set some other flag like waiting_for_mouse_up = True. Then you need to wait until the mouse button is next not pressed, when you can set waiting_for_mouse_up = False.

Then you check for: mouse2.isPressedIn(leftbox1) and stimulus_dropped_in_leftbox and not waiting_for_mouse_up and only then set continueRoutine = False.

You will probably want to draw up a flowchart to get the logic correct.

Michael,

I got it working once the light came on that a mouse click is a pressed off and back on sequence. It took a while to get the logic right but it now works like a charm. Thanks for providing a sounding board it really helped.
The updated code and mouse component that works is below.

#begin routine
#note: definition of mouse must be the same name as the mouse component
def movePicked(picked, mouse2, grabbed):
    if grabbed is not None and mouse2.isPressedIn(grabbed):
        grabbed.pos = mouse2.getPos()
        return grabbed
    else:
        for piece in picked:
            if mouse2.isPressedIn(piece) and grabbed is None:
                return piece
                
picked = []
movingPiece = None
boxchosen = None
pickedup = 0
mousepressedstatus = []
mouseup = False
testcomplete = False
#Each Frame
if mouse2.isPressedIn(blueboat1): 
    boxchosen = None
    if movingPiece is None:
        picked.append(blueboat1)
if mouse2.isPressedIn(leftbox1) and movingPiece is not None:
    if mouseup == True:
        testcomplete = True
    boxchosen = 'left'
    thisExp.addData('boxchosen', boxchosen)
if mouse2.isPressedIn(rightbox1) and movingPiece is not None:
    if mouseup == True:
        testcomplete = True
    boxchosen = 'right'
    thisExp.addData('boxchosen', boxchosen)
if mouse2.getPressed()[0] == 0 and boxchosen is not None:
    mouseup = True
if testcomplete == True:
    #practice upto 3 times until they get it right
    thisExp.addData('boxchosen2', boxchosen)
    if boxchosen == PracticeAnswer:
        thisExp.addData('correct', '1')
        trials_2.finished = True # stop the loop
    else:
        thisExp.addData('correct', '0') #otherwise go around again
    continueRoutine = False
movingPiece = movePicked(picked, mouse2, movingPiece)

1 Like

Well done. This stuff is very tricky to get right but it is a good exercise in programming logic.