How to control display time using a custom function in the builder

Hello everyone!

So, my roblem is very simple: for my quantity judgement task, I created functions to create a point-based stim and a mask, I want the stim to appear precisely 0.3 seconds and my mask precisely 0.2 seconds from the end of the stim. However, with my current method and all the others I’ve tested, I can’t manage to measure the display time accurately at all. Could you help or guide me in solving my problem? Thank you in advance :slight_smile:

Here is the current code :

Begin experiment:

# Define the squares
square1 = visual.Rect(win, width=2, height=2, pos=(-2, 0), lineWidth=0.2, lineColor="black", 
fillColor="black")
square2 = visual.Rect(win, width=2, height=2, pos=(2, 0), lineWidth=0.2, lineColor="black", 
fillColor="black")

# Create the points (here, just white circles)
dots = [visual.Circle(win, radius=0.04, fillColor="white", lineColor="white") for _ in range(800)]  # 
20x20 for each square, so 20*20*2 = 800

# Create the fixation cross
fixation_cross_dot_task = visual.ShapeStim(
        win=win, vertices='cross',
        size=(0.5, 0.5),
        ori=0.0, pos=(0, 0), anchor='center',
        lineWidth=0.6, colorSpace='rgb',  lineColor='white', fillColor='white',
        opacity=None, depth=-1.0, interpolate=True)

# Generate possible positions for each square
step = 2 / 20  # now 2 units divided by 20 points
positions1 = [(x, y) for x in np.arange(-3 + step/2, -1 + step/2, step) for y in np.arange(-1 + step/2, 1 + step/2, step)]
positions2 = [(x, y) for x in np.arange(1 + step/2, 3 + step/2, step) for y in np.arange(-1 + step/2, 1 + step/2, step)]


def dot_stim_staircase():
    #draw squares"
    square1.draw()
    square2.draw()

    #place and draw dots in the first square
    for i, (x, y) in enumerate(positions_square1):
        dots[i].pos = (x, y)
        dots[i].draw()
    
    #place and draw dots in the second square
    for i, (x, y) in enumerate(positions_square2):
        dots[i+dots_in_square1].pos = (x, y)
        dots[i+dots_in_square1].draw()

    #draw the fixation cross
    fixation_cross_dot_task.draw()

    # Disp all items
    win.flip()

def mask():
    # Draw squares
    square1.draw()
    square2.draw()

    # Place all dots for the mask
    for i, (x, y) in enumerate(positions1 + positions2):
        dots[i % 800].pos = (x, y)
        dots[i % 800].draw()    
    
    #draw the fixation cross
    fixation_cross_dot_task.draw()

    #disp everything
    win.flip()

Begin routine:

# stim state
dot_stimulus_state = 0
# stim state
dot_mask_state = 0

Each Frame:

if dot_stimulus_state == 0:
    timer = core.Clock()

while timer.getTime() < 0.3:  # Keep looping until timer exceeds 0.3 seconds
    if dot_stimulus_state == 0:
    
        dot_stim_staircase()
    
        dot_stimulus_state = 1  # Change stim state

# Once the loop exits (i.e., time exceeds 0.3 seconds)

while timer.getTime() < 0.5:  # Keep looping until timer exceeds 0.5 seconds
    if dot_mask_state == 0:
    
        mask()
    
        dot_mask_state = 1  # Change stim state

# Once the loop exits (i.e., time exceeds 0.3 seconds)
win.flip()

Step 1

Remove all while loops from your Each Frame code

Step 2

Remove all win.flip() statements

Step 3

Do not create a new timer in Each Frame. Reset it in Begin Routine or use t (automatic routine timer)

Step 4

Consider using compoents for your simpler objects (like the fixation cross)

1 Like