def test_StaticPeriod(): static = StaticPeriod() static.start(0.1) wait(0.05) assert static.complete()==1 static.start(0.1) wait(0.11) assert static.complete()==0 win = Window(autoLog=False) static = StaticPeriod(screenHz=60, win=win) static.start(.002) assert win.recordFrameIntervals is False static.complete() assert static._winWasRecordingIntervals == win.recordFrameIntervals win.close() # Test if screenHz parameter is respected, i.e., if after completion of the # StaticPeriod, 1/screenHz seconds are still remaining, so the period will # complete after the next flip. refresh_rate = 100.0 period_duration = 0.1 timer = CountdownTimer() win = Window(autoLog=False) static = StaticPeriod(screenHz=refresh_rate, win=win) static.start(period_duration) timer.reset(period_duration ) static.complete() assert np.allclose(timer.getTime(), 1.0/refresh_rate, atol=0.001) win.close()
class StaticPeriod(object): """A class to help insert a timing period that includes code to be run. Typical usage:: fixation.draw() win.flip() ISI = StaticPeriod(screenHz=60) ISI.start(0.5) #start a period of 0.5s stim.image = 'largeFile.bmp' #could take some time ISI.complete() #finish the 0.5s, taking into account one 60Hz frame stim.draw() win.flip() #the period takes into account the next frame flip #time should now be at exactly 0.5s later than when ISI.start() was called """ #NB - this might seem to be more sensible in the clock.py module, but that creates a circular reference # with the logging module. def __init__(self, screenHz=None, win=None, name='StaticPeriod'): """ :param screenHz: the frame rate of the monitor (leave as None if you don't want this accounted for) :param win: if a visual.Window is given then StaticPeriod will also pause/restart frame interval recording :param name: give this StaticPeriod a name for more informative logging messages """ self.status=NOT_STARTED self.countdown = CountdownTimer() self.name = name self.win = win if screenHz is None: self.frameTime = 0 else: self.frameTime = 1.0/screenHz def start(self, duration): """Start the period. If this is called a second time, the timer will be reset and starts again """ self.status = STARTED self.countdown.reset(duration) #turn off recording of frame intervals throughout static period if self.win: self.win.recordFrameIntervals = False self._winWasRecordingIntervals = self.win.recordFrameIntervals def complete(self): """Completes the period, using up whatever time is remaining with a call to wait() :return: 1 for success, 0 for fail (the period overran) """ self.status=FINISHED timeRemaining = self.countdown.getTime() if self.win: self.win.recordFrameIntervals = self._winWasRecordingIntervals if timeRemaining<0: logging.warn('We overshot the intended duration of %s by %.4fs. The intervening code took too long to execute.' %(self.name, abs(timeRemaining))) return 0 else: wait(timeRemaining) return 1
def __init__(self, screenHz=None, win=None, name='StaticPeriod'): """ :param screenHz: the frame rate of the monitor (leave as None if you don't want this accounted for) :param win: if a visual.Window is given then StaticPeriod will also pause/restart frame interval recording :param name: give this StaticPeriod a name for more informative logging messages """ self.status = NOT_STARTED self.countdown = CountdownTimer() self.name = name self.win = win if screenHz is None: self.frameTime = 0 else: self.frameTime = 1.0 / screenHz
def test_StaticPeriod_screenHz(): """Test if screenHz parameter is respected, i.e., if after completion of the StaticPeriod, 1/screenHz seconds are still remaining, so the period will complete after the next flip. """ refresh_rate = 100.0 period_duration = 0.1 timer = CountdownTimer() win = Window(autoLog=False) static = StaticPeriod(screenHz=refresh_rate, win=win) static.start(period_duration) timer.reset(period_duration) static.complete() assert np.allclose(timer.getTime(), 1.0 / refresh_rate, atol=0.001) win.close()
def __init__(self, screenHz=None, win=None, name='StaticPeriod'): """ :param screenHz: the frame rate of the monitor (leave as None if you don't want this accounted for) :param win: if a visual.Window is given then StaticPeriod will also pause/restart frame interval recording :param name: give this StaticPeriod a name for more informative logging messages """ self.status=NOT_STARTED self.countdown = CountdownTimer() self.name = name self.win = win if screenHz is None: self.frameTime = 0 else: self.frameTime = 1.0/screenHz
class StaticPeriod(object): """A class to help insert a timing period that includes code to be run. Typical usage:: fixation.draw() win.flip() ISI = StaticPeriod(screenHz=60) ISI.start(0.5) #start a period of 0.5s stim.image = 'largeFile.bmp' #could take some time ISI.complete() #finish the 0.5s, taking into account one 60Hz frame stim.draw() win.flip() #the period takes into account the next frame flip #time should now be at exactly 0.5s later than when ISI.start() was called """ #NB - this might seem to be more sensible in the clock.py module, but that creates a circular reference # with the logging module. def __init__(self, screenHz=None, win=None, name='StaticPeriod'): """ :param screenHz: the frame rate of the monitor (leave as None if you don't want this accounted for) :param win: if a visual.Window is given then StaticPeriod will also pause/restart frame interval recording :param name: give this StaticPeriod a name for more informative logging messages """ self.status = NOT_STARTED self.countdown = CountdownTimer() self.name = name self.win = win if screenHz is None: self.frameTime = 0 else: self.frameTime = 1.0 / screenHz def start(self, duration): """Start the period. If this is called a second time, the timer will be reset and starts again """ self.status = STARTED self.countdown.reset(duration) #turn off recording of frame intervals throughout static period if self.win: self.win.recordFrameIntervals = False self._winWasRecordingIntervals = self.win.recordFrameIntervals def complete(self): """Completes the period, using up whatever time is remaining with a call to wait() :return: 1 for success, 0 for fail (the period overran) """ self.status = FINISHED timeRemaining = self.countdown.getTime() if self.win: self.win.recordFrameIntervals = self._winWasRecordingIntervals if timeRemaining < 0: logging.warn( 'We overshot the intended duration of %s by %.4fs. The intervening code took too long to execute.' % (self.name, abs(timeRemaining))) return 0 else: wait(timeRemaining) return 1
def main(): # I set up my siplay size and background colour DISPSIZE = (1400, 800) BGC = (-1, -1, -1) # for my game I need to create some variables: score = 0 lives = 3 level = 1 mouse_x = 0 mouse_y = 0 # I create some objects: win = Window(size=DISPSIZE, units='pix', fullscr=False, color=BGC) mouse = Mouse(win) target = ImageStim(win, 'target.png', size=(420, 420)) # I will display three text stimuli to the player while playing the game: lives_count = TextStim( win, text=f'Lives = {lives}', height=35, color=(1, 0.2, 0.6), pos=(100, 330), ) score_count = TextStim(win, text=f'Score = {score}', height=35, color=(0.2, 0.2, 0.8), pos=(450, 330)) level_count = TextStim(win, text=f'Level = {level}', height=35, color=(1, -0.5, 1), pos=(850, 330)) # I define the messages to show the player the outcome of the game: you_have_lost = TextStim( win, text='Boo! Not a great game, pal... Get it together!', height=35, color=(0.2, 0.2, 0.8), pos=(250, 230)) you_have_won = TextStim(win, text='Yey! Well done, champ! Time to celebrate!', height=35, color=(0.2, 0.2, 0.8), pos=(250, 230)) # These are the images I use for the winning and loosing scenarios: looser = ImageStim(win, 'failed.jpg', pos=(0, -100), size=(420, 420)) winner = ImageStim(win, 'tiny_trash.jpg', pos=(0, -100), size=(420, 420)) # I introduce this dialog to save the user's ID: user_id_dialog = gui.Dlg(title="Target Game") user_id_dialog.addText('Please write your subject ID: a 4-digit code') user_id_dialog.addField('Subject ID:') ok_data = user_id_dialog.show() # show dialog and wait for OK or Cancel if not user_id_dialog.OK: print('user cancelled') # NOW THE GAME WILL START: # If enabled, intro will play: enable_intro = True if enable_intro: show_intro(win) # We create this list to save our results into target_hits_per_level = [ [], [], [], [], ] move_target_at_random_pos( target) # first the target is shown on the screen lives_timer = CountdownTimer( 5) # Level 1 starts with 5 sec to hit the target mouse_click_clock = Clock() reaction_time_clock = Clock() change_target = False while level < 4 and lives > 0: target.draw() target_x, target_y = target.pos lives_count.draw() score_count.draw() level_count.draw() win.flip() keys_pressed = getKeys() if 'q' in keys_pressed: break mouse_is_pressed = mouse.getPressed()[0] == True mouse_x, mouse_y = mouse.getPos() level_count.setText(f'Level = {level}') #if the player does not click, the target moves and the player looses a life if lives_timer.getTime() <= 0: lives -= 1 lives_count.setText(f'Lives = {lives}') mouse_in_target = None mouse_in_target_x = None mouse_in_target_y = None change_target = True # Check for a mouse click every 0.2s, so that we don't accept more than 1 # press on mouse hold if mouse_is_pressed and mouse_click_clock.getTime() > 0.2: mouse_click_clock.reset() change_target = True if mouse_clicked_in_target(mouse, target): mouse_in_target = True mouse_in_target_x = mouse_x - target_x mouse_in_target_y = mouse_y - target_y score += 1 score_count.setText(f'Score = {score}') else: lives -= 1 lives_count.setText(f'Lives = {lives}') mouse_in_target = False mouse_in_target_x = None mouse_in_target_y = None if change_target: mouse_click = { 'mouse_x': mouse_in_target_x, 'mouse_y': mouse_in_target_y, 'reaction_time': reaction_time_clock.getTime(), 'mouse_in_target': mouse_in_target, } target_hits_per_level[level - 1].append( mouse_click) # inddexes start from 0 --> level - 1 if score == 5: lives_timer.reset(3) level = 2 elif score == 10: lives_timer.reset(1) level = 3 elif score == 15: level = 4 move_target_at_random_pos(target) lives_timer.reset() reaction_time_clock.reset() change_target = False # Here we display the outcome of the game: if level == 4: you_have_won.draw() winner.draw() else: you_have_lost.draw() looser.draw() win.flip() wait(3) # Finally, we draw the overwivew for thr player draw_overview_target( win=win, level=1, target_pos=(-450, 0), text_pos=(50, 300), mouse_clicks_all_levels=target_hits_per_level, ) draw_overview_target( win=win, level=2, target_pos=(0, 0), text_pos=(450, 300), mouse_clicks_all_levels=target_hits_per_level, ) draw_overview_target( win=win, level=3, target_pos=(450, 0), text_pos=(850, 300), mouse_clicks_all_levels=target_hits_per_level, ) win.flip() wait(4) # The user has not clicked Cancel on the subject ID window if ok_data is not None: write_results(target_hits_per_level, 'results-' + ok_data[0] + '.csv') win.close()