psychopy.org | Reference | Downloads | Github

Drag 'n Drop & conditional continue button is only working for one (out of 2) image stimuli

Win10:
PsychoPy version : (v2020.1.3)
Standard Standalone? yes
What are you trying to achieve?:
Please bear in mind, that I am a newbie at programming and I quite literally pieced this script together with the help of lots of other topics, the reference manual and try and error, so the issue might be very simple (just not for me yet :smiley: )…

  • I am trying to create a drag and drop game in which participants have to indicate if the shown picture in the middle belongs to a category (via yes and no answers)
  • yes and no answers are indicated by dragging a red or a green circle (“redPiece”/ “greenPiece”) to the picture shown in the middle ( a polygon is hidden underneath it to help me code the responses)
  • when the participant has dragged one piece to the middle (doesn’s matter which one, either red or green is fine), a continue button in the right corner of the screen becomes visible and when pressed, the next picture is shown and so on (there is a loop of images)

So far, I have pieced together a script which works, but only for the greenPiece. If I move the greenPiece over the polygon/image, then as described, the continue botton becomes visible and I can click on it to show me the next picture. BUT if I do the same with the redPiece, this does not happen. I can move the redPiece around and over the image in the middle, but no button becomes visible.

Any idea, what the issue might be here?

Also on a side note, I want to make this experiment compatible with touchscreens and online experiments (pavlovia). Where and what do I have to insert into the script, so that the continue button can be touched with a single touch click instead of a double touch click? The circles seem fine and are touchscreen compatible…

#Begin Experiment:
def createPiece(piece, pos, name):
    return visual.ImageStim(win, image=piece.image, name=name, size=piece.size, pos=pos)

def drawPicked(picked):
    for each in picked:
        each.draw()

def movePicked(picked, mouseIndiv, grabbed):
    #move piece if it is already being moved 
    if grabbed is not None and mouseIndiv.isPressedIn(grabbed):
        grabbed.pos = mouseIndiv.getPos()
        return grabbed
    else: #move newly clicked piece
        for piece in picked:
            if mouseIndiv.isPressedIn(piece) and grabbed is None:
                return piece
              
ContinueButton = visual.ShapeStim(win, fillColor= 'lightblue', fillColorSpace= 'rgb', vertices=((-0.07, -0.05), (-0.07, 0.05), (0.07, 0.05), (0.07, -0.05)), closeShape=True, pos=(.75, -.45), name='ContinueButton')
ContinueButtonText = visual.TextStim(win, text='Weiter', height = 0.03, pos=(.75, -.45))
ContinueButtonSelected = False

--------------------------
#Begin Routine:
pieces = [redPiece, greenPiece]
picked = []
movingPiece = None
polygon.setFillColor(None)

ContinueButton.setAutoDraw(False)
ContinueButtonText.setAutoDraw(False)
ContinueButtonSelected = False
ContinueButtonOn = False

-------------------------------------
#Each frame:
for piece in pieces:
    if mouseIndiv.isPressedIn(piece) and movingPiece is None:
        picked.append(piece)
    
movingPiece = movePicked(picked, mouseIndiv, movingPiece)
drawPicked(picked)

#when mouse is pressed in one piece & piece is moved to polygon, store the information yes or no depending on which color piece was moved
if mouseIndiv.isPressedIn(piece):
    if polygon.contains(mouseIndiv) and mouseIndiv.isPressedIn(greenPiece):
        thisExp.addData('yes', 1)
    elif polygon.contains(mouseIndiv) and mouseIndiv.isPressedIn(redPiece):
        thisExp.addData('no', 0)
            
#enable button when mouse is moving piece into polygon & draw continue button
if polygon.contains(mouseIndiv) and mouseIndiv.isPressedIn(piece):
    ContinueButton.setAutoDraw(True)
    ContinueButtonText.setAutoDraw(True)
    ContinueButtonOn = True
    
#check for click in button when it is on:
if ContinueButtonOn and mouseIndiv.isPressedIn(ContinueButton):
    ContinueButtonSelected = True

#if activated button is pressed, proceed
if ContinueButtonSelected:
    continueRoutine = False

Thanks so much for any help!

I’m not sure why you can only use one piece to activate the continue button, but I’d recommend making changes to see if you can flip it to the other one such as changing the order in the array and changing the order of the components.

For touchscreen use I use the contains method, i.e. I respond to the location of the mouse, ignoring the state of the buttons. However, when the screen is not being touched then the mouse is continually being recorded at its last position so I require a change in location from the last recorded position to count as a new interaction. This is difficult to test with a mouse because the position changes slightly even when the user is trying to hold the pointer still.

Thank you for getting back to me so quickly!
I tried what you suggested and changed the order of everything around but I can’t seem to make it change so that the redPiece works as intended. This is so strange…

I’m adding a picture of my current Routine order and I changed the code in “Each frames” to the following, although it’s not much different than before… Maybe someone sees something I have overlooked somwhow.

#Each frame code fragment:
#when mouse is pressed in one piece & piece is moved to polygon, store the information yes or no
if mouseIndiv.isPressedIn(piece):
    if polygon.contains(mouseIndiv) and mouseIndiv.isPressedIn(redPiece):
        thisExp.addData('no', 0)
        ContinueButton.setAutoDraw(True)
        ContinueButtonText.setAutoDraw(True)
        ContinueButtonOn = True
    elif polygon.contains(mouseIndiv) and mouseIndiv.isPressedIn(greenPiece):
        thisExp.addData('yes', 1)
        ContinueButton.setAutoDraw(True)
        ContinueButtonText.setAutoDraw(True)
        ContinueButtonOn = True

!

I’m at a loss here…

Here is the part that’s causing you trouble:

#Each frame:
for piece in pieces:
    if mouseIndiv.isPressedIn(piece) and movingPiece is None:
        picked.append(piece)
# ...
if mouseIndiv.isPressedIn(piece):
    if polygon.contains(mouseIndiv) and mouseIndiv.isPressedIn(greenPiece):
        thisExp.addData('yes', 1)
    elif polygon.contains(mouseIndiv) and mouseIndiv.isPressedIn(redPiece):
        thisExp.addData('no', 0)

Note that you use if mouseIndiv.isPressedIn(piece) outside of any loop. This means that the variable piece will refer to the last value it referred to when used inside the loop, ie the last value in the iterable pieces. That value is your green piece.

To better understand what’s happening, let’s look at an isolated example:

for foo in [1, 3, 8]:
    print(foo)
# outputs 1 3 8

# now, outside of the loop:
print(foo)
# outputs 8, since that was the last value that foo was 
# made to represent/refer to inside the loop
1 Like

Thanks so much! I adjusted it and now it works! :partying_face:

1 Like