Pygame游戏随机无响应问题排查求助
Pygame随机无响应问题排查(菜单状态处理相关)
我是Pygame开发新手,遇到难以稳定复现的随机无响应问题,怀疑问题出在菜单状态处理环节。该问题最常出现在按ESC键进入暂停菜单时(过去快速切换菜单也会触发,添加冷却机制后此场景已解决)。游戏99%时间运行正常,但偶尔会窗口冻结无响应,往往需半小时反复尝试才能复现一次。
相关代码片段
游戏循环
while settings.RUNNING: settings.EVENTS = pygame.event.get() if (settings.MUSIC_MUTED): pygame.mixer.music.set_volume(0) else: pygame.mixer.music.set_volume(int(settings.MUSIC_VOLUME) / 100) if not (settings.GAME_PAUSED): for event in settings.EVENTS: if event.type == pygame.QUIT: settings.RUNNING = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: settings.MENU_STATE = 'pause' pause_start = pygame.time.get_ticks() settings.MENU_CD = pygame.time.get_ticks() settings.GAME_PAUSED = True if settings.FINISHED: settings.FINISHED = False level = Level(settings) pygame.mixer.music.unpause() level.draw() elif (settings.GAME_PAUSED): #Some other code pygame.display.update() GAME_CLOCK.tick(60) pygame.quit() sys.exit()
暂停事件处理
for event in settings.EVENTS: if event.type == pygame.QUIT: settings.RUNNING = False if settings.MENU_STATE == "main": if event.type == pygame_gui.UI_TEXT_ENTRY_CHANGED and event.ui_object_id == "#name_input_field" and (pygame.time.get_ticks() - settings.MENU_CD) >= 175: settings.PLAYER_NAME = event.text NAME_INPUT.process_events(event) if settings.MENU_STATE == "keybinds" and waiting_input: if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: if waiting_for == "left": left_button.image = settings.MENU_ASSETS["buttons"]["button"] if waiting_for == "right": right_button.image = settings.MENU_ASSETS["buttons"]["button"] if waiting_for == "jump": jump_button.image = settings.MENU_ASSETS["buttons"]["button"] waiting_for = "" waiting_input = False elif event.key not in [settings.KEYBINDS['left'], settings.KEYBINDS['right'], settings.KEYBINDS['jump']]: if waiting_for == "left": save_settings({ 'left' : event.key, 'right': settings.KEYBINDS['right'], 'jump': settings.KEYBINDS['jump'] }) left_button.image = settings.MENU_ASSETS["buttons"]["button"] elif waiting_for == "right": save_settings({ 'left' : settings.KEYBINDS['left'], 'right': event.key, 'jump': settings.KEYBINDS['jump'] }) right_button.image = settings.MENU_ASSETS["buttons"]["button"] elif waiting_for == "jump": save_settings({ 'left' : settings.KEYBINDS['left'], 'right': settings.KEYBINDS['right'], 'jump': event.key }) jump_button.image = settings.MENU_ASSETS["buttons"]["button"] set_keybinds(settings) waiting_input = False waiting_for = ""
暂停菜单代码
if (settings.MENU_STATE == 'pause'): print("pause menu", settings.GAME_PAUSED, settings.RUNNING) pygame.mixer.music.pause() title_image = pygame.image.load('./assets/menu/title/title.png').convert_alpha() SCREEN.blit(title_image, ((settings.SCREEN_WIDTH/2 - title_image.get_width()/2),(settings.SCREEN_HEIGHT/4 - title_image.get_height() * 3 / 4))) if resume_button.draw(SCREEN) and (pygame.time.get_ticks() - settings.MENU_CD) >= 175: settings.GAME_PAUSED = False level.pause_time += (pygame.time.get_ticks() - pause_start) pause_start = 0 continue if settings_button.draw(SCREEN) and (pygame.time.get_ticks() - settings.MENU_CD) >= 175: settings.PREVIOUS_MENU = "pause" settings.MENU_STATE = "settings" settings.MENU_CD = pygame.time.get_ticks() continue if mainmenu_button.draw(SCREEN) and (pygame.time.get_ticks() - settings.MENU_CD) >= 175: settings.MENU_STATE = "main" settings.MENU_CD = pygame.time.get_ticks() continue
补充信息:Python版本为3.9.13
可能的问题点及修复建议
1. 重复加载图片导致阻塞
暂停菜单中每次进入pause状态都会调用pygame.image.load加载图片,磁盘IO是阻塞操作,偶尔会因系统资源调度引发卡顿甚至冻结。解决方法:将图片加载移至初始化阶段,避免重复IO:
# 初始化阶段(比如游戏启动时)提前加载 title_image = pygame.image.load('./assets/menu/title/title.png').convert_alpha() # 暂停菜单中直接使用已加载的图片 if (settings.MENU_STATE == 'pause'): print("pause menu", settings.GAME_PAUSED, settings.RUNNING) pygame.mixer.music.pause() SCREEN.blit(title_image, ((settings.SCREEN_WIDTH/2 - title_image.get_width()/2),(settings.SCREEN_HEIGHT/4 - title_image.get_height() * 3 / 4))) # 后续按钮逻辑...
2. continue语句跳过关键循环步骤
暂停菜单按钮逻辑中使用continue,会直接回到游戏循环开头,跳过当前周期的pygame.display.update(),导致画面无法更新,看起来像窗口冻结。解决方法:移除continue,用状态变量切换代替:
if resume_button.draw(SCREEN) and (pygame.time.get_ticks() - settings.MENU_CD) >= 175: settings.GAME_PAUSED = False level.pause_time += (pygame.time.get_ticks() - pause_start) pause_start = 0 # 移除continue,让循环正常执行到display.update if settings_button.draw(SCREEN) and (pygame.time.get_ticks() - settings.MENU_CD) >= 175: settings.PREVIOUS_MENU = "pause" settings.MENU_STATE = "settings" settings.MENU_CD = pygame.time.get_ticks() # 移除continue # 同理处理mainmenu_button
3. 暂停状态下事件处理不完整
当前GAME_PAUSED分支中,暂停菜单状态未处理QUIT事件和ESC键的二次响应,可能导致事件队列堆积或无法正常退出。解决方法:在暂停菜单的事件处理中补充关键事件逻辑:
elif (settings.GAME_PAUSED): for event in settings.EVENTS: if event.type == pygame.QUIT: settings.RUNNING = False # 处理暂停状态下的ESC键(比如直接恢复游戏) if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE and (pygame.time.get_ticks() - settings.MENU_CD) >= 175: settings.GAME_PAUSED = False level.pause_time += (pygame.time.get_ticks() - pause_start) pause_start = 0 # 暂停菜单绘制逻辑...
4. 设置保存的阻塞风险
检查save_settings函数,如果涉及同步文件IO,长时间阻塞主线程会导致游戏无响应。解决方法:将设置保存改为异步操作,或确保IO操作足够轻量化,避免阻塞游戏循环。
5. 全局变量的竞态风险
如果存在异步操作修改settings模块的全局变量(如RUNNING、GAME_PAUSED),可能引发竞态条件导致死锁。解决方法:确保所有全局变量的修改都在主线程中进行,或添加线程同步机制。
内容的提问来源于stack exchange,提问作者Anze
相关产品推荐
相关产品推荐

