嵌套循环键盘事件处理求助:停止信号反应任务编程
解决Stop Signal Response Task中的Pygame键盘响应卡顿与记录问题
嘿,我看了你这个停止信号任务的代码问题,核心是Pygame的事件处理逻辑没捋顺,还有几个小的时间计算笔误,咱们一步步来搞定它:
先修正几个明显的逻辑笔误
- 你代码里的
while time.time() < SSD应该是while time.time() < StopSignalTime,因为SSD是延迟时长,StopSignalTime = starttime + SSD才是蜂鸣触发的具体时间点 - 调整SSD的代码里
SSD = SSD = 0.05是笔误,按照停止信号任务的规则,应该是SSD = SSD - 0.05(被试没抑制住反应时,缩短下一次的SSD)
Pygame键盘事件的正确打开方式
之所以会出现“无法记录响应”或“程序卡顿”,是因为你没正确处理Pygame的事件队列,而且用了忙等的循环(一直占用CPU)。正确的做法是:
- 初始化Pygame时必须创建窗口(哪怕后台运行,Pygame需要窗口才能捕获输入)
- 用事件队列处理按键,而不是直接检测按键状态(避免重复触发)
- 用帧率控制减少CPU占用,防止卡顿
完整的试次循环代码示例
先放初始化代码:
import pygame import time # 初始化Pygame核心模块 pygame.init() # 创建窗口(可以设置为全屏:pygame.display.set_mode((0,0), pygame.FULLSCREEN)) screen = pygame.display.set_mode((800, 600)) # 禁止按键重复触发(避免按住键时多次记录) pygame.key.set_repeat(0) # 用于控制帧率的时钟对象 clock = pygame.time.Clock() # 假设你已经定义了这些变量: beeplist = [1, 0, 1, 0] # 示例蜂鸣列表 SSD = 0.3 # 初始停止信号延迟 trial_ST = [] # 存储试次开始时间 response = [] # 存储响应(按键+反应时间) SSDlist = [] # 存储每次试次的SSD
然后是单个试次的核心处理逻辑:
# 遍历试次(这里用i作为示例索引) for i in range(len(beeplist)): starttime = time.time() trial_ST.append(starttime) end_time = starttime + 1.250 # 试次总时长1.25秒 StopSignalTime = starttime + SSD # 蜂鸣触发的时间点 presses = None # 存储首次按键 rt = None # 存储反应时间 ss_played = False # 标记蜂鸣是否已播放 # 试次主循环:持续到试次结束时间 while time.time() < end_time: # 处理所有Pygame事件(必须做,否则程序会卡顿) for event in pygame.event.get(): # 处理窗口关闭事件,防止程序卡死 if event.type == pygame.QUIT: pygame.quit() exit() # 仅在未记录过按键时,处理按键按下事件 if event.type == pygame.KEYDOWN and presses is None: # 只记录目标按键z或/ if event.key == pygame.K_z: presses = 'z' rt = time.time() - starttime elif event.key == pygame.K_SLASH: presses = '/' rt = time.time() - starttime # 检查是否需要播放蜂鸣(仅播放一次) if beeplist[i] == 1 and not ss_played and time.time() >= StopSignalTime: # 这里假设tone是你已经初始化好的pygame.mixer.Sound对象 tone.play() ss_played = True # 控制帧率为60帧/秒,减少CPU占用,避免卡顿 clock.tick(60) # 将响应存入列表(按键+反应时间,无按键则存None) response.append((presses, rt)) # 记录本次试次的SSD SSDlist.append(SSD) # 根据表现调整SSD if beeplist[i] == 1: if presses is None: # 成功抑制反应,增加SSD SSD += 0.05 else: # 未抑制住反应,减少SSD(修正你的笔误) SSD -= 0.05 # 限制SSD的范围,避免不合理值 SSD = max(0.0, min(SSD, 1.25)) print("end of block iteration") # 你的blockiteration和restblock()逻辑 # blockiteration += 1 # restblock()
关键细节解释
- 事件队列处理:用
pygame.event.get()遍历所有事件,只在KEYDOWN且presses为None时记录按键,确保只捕获首次响应,不会重复记录。 - 蜂鸣播放控制:用
ss_played标记,避免在循环中多次触发蜂鸣播放(因为循环会每秒运行60次,不标记的话会重复播放)。 - 帧率控制:
clock.tick(60)让循环每秒最多运行60次,既保证按键检测的灵敏度,又不会让CPU跑满导致卡顿。 - 反应时间计算:在按键按下的瞬间计算
time.time() - starttime,确保反应时间的准确性。 - SSD范围限制:用
max(0.0, min(SSD, 1.25))保证SSD不会小于0(蜂鸣提前播放)或大于试次时长(蜂鸣不会触发)。
内容的提问来源于stack exchange,提问作者Richard Summers
相关产品推荐
相关产品推荐

