基于Pygame的打字游戏用户输入无响应问题修复请求
问题描述
我正在开发一款打字游戏,通关条件为用户输入指定提示文本且打字速度≥35WPM。先完成了控制台运行版本,后续基于Pygame开发GUI版本,但GUI版本中用户输入文本后,代码未执行文本匹配与通关判断逻辑。我怀疑是if user_text == displayprompt:判断失效,尝试调整缩进、用列表存储字符对比等方法仍未解决,请求修复代码错误。
控制台版本代码
from time import time from random import randint def typingErrors(prompt): global iwords words = prompt.split() errors = 0 for i in range(len(iwords)): if i in (0, len(iwords)-1): if iwords[i] == words[i]: continue else: errors +=1 else: if iwords[i] == words[i]: if (iwords[i+1] == words[i+1]) & (iwords[i-1] == words[i-1]): continue else: errors += 1 else: errors += 1 return errors def typingSpeed(iprompt, stime, etime): global time global iwords iwords = iprompt.split() twords = len(iwords) speed = twords / time return speed def timeElapsed(stime, etime): time = etime - stime return time def GeneratePrompt(): with open(r"C:\Users\adarshrsm\Desktop\prompts.txt", 'r') as file: prompts=file.readlines() for i in prompts: if len(i)>=10 and len(i)<30: try: index = randint(0,(len(prompts))) finalprompt=prompts[index] except IndexError: GeneratePrompt() return finalprompt if __name__ == '__main__': #prompt = input("Enter Prompt: ") prompt=GeneratePrompt() print("Type this to open the chest:- '", prompt, "'") input("press ENTER when you are ready!") stime = time() iprompt = input() etime = time() time = round(timeElapsed(stime, etime), 2) speed = typingSpeed(iprompt, stime, etime) errors = typingErrors(prompt) accuracy = ((len(iwords)-errors)/len(iwords))*100 wpm = round(speed,2)*60 if accuracy == 100 and wpm >= 35: print("You have passed") else: print("You have failed")
GUI版本原始代码
import pygame from sys import exit from time import time from random import randint #import RPGtext #--------------------------Functions-------------------------------- def GeneratePrompt(): with open(r"C:\Users\adarshrsm\Desktop\prompts.txt", 'r') as file: prompts=file.readlines() for i in prompts: if len(i)>=10 and len(i)<25: try: index = randint(0,(len(prompts))+1) finalprompt=prompts[index] except IndexError or UnboundLocalError: GeneratePrompt() return finalprompt def typingSpeed(iprompt, stime, etime): global time global iwords iwords = iprompt.split() twords = len(iwords) speed = twords / time return speed def timeElapsed(stime, etime): time = etime - stime return time #-------------------------GUI and main game loop----------------------------------- pygame.init() Win = pygame.display.set_mode((1000,900)) clock = pygame.time.Clock() chest_left_tilt = pygame.image.load(r"C:\Users\adarshrsm\Downloads\chest_left_tilt.png") chest_right_tilt = pygame.image.load(r"C:\Users\adarshrsm\Downloads\right tilt.png") chest_no_tilt = pygame.image.load(r"C:\Users\adarshrsm\Downloads\no tilt.png") display_textbox = pygame.image.load(r"C:\Users\adarshrsm\Downloads\final textbox.png") display_textbox.set_alpha(100) txtf = pygame.font.Font(r"C:\Users\adarshrsm\Downloads\game font.ttf",40) snip = txtf.render('',True,(0,0,0)) EnterPrompt = txtf.render("Enter this code to open the chest: ",True,(0,0,0)) EnterPrompt.set_alpha(200) EnterLine = "Press Enter to start" counter = 0 speed = 3 TextRendered = False imgtick = 1 displayprompt = GeneratePrompt() text = txtf.render(displayprompt,True,(0,0,0)) user_text = '' GameStatus = True while GameStatus == True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit() if imgtick%100 == 0: Win.blit(chest_left_tilt,(0,0)) imgtick+=1 elif imgtick%100 != 0: Win.blit(chest_right_tilt,(0,0)) imgtick+=1 Win.blit(display_textbox,(100,50)) Win.blit(EnterPrompt,(150,100)) if counter < speed * len(displayprompt): counter+=1 elif counter >= speed * len(displayprompt): done = True snip = txtf.render(displayprompt[0:counter//speed],True,(0,0,0)) EnterLineRender = txtf.render(EnterLine[0:counter//speed],True,(0,0,0)) EnterLineRender.set_alpha(200) Win.blit(snip,(150,150)) Win.blit(EnterLineRender,(150,200)) user_text_list = [] for event in pygame.event.get(): if event.type == pygame.KEYDOWN: if event.key == pygame.K_BACKSPACE: user_text = user_text[:-1] elif event.key == pygame.K_ESCAPE: pygame.quit() exit() elif event.key == pygame.K_RETURN: stime = time() else: user_text += event.unicode if user_text == displayprompt: iprompt = user_text etime = time() time = round(timeElapsed(stime, etime), 2) speed = typingSpeed(iprompt, stime, etime) wpm = round(speed,2)*60 if wpm >=35: snip_win = txtf.render('',True,(0,0,0)) counter_win = 0 result_win = "You have unlocked the chest ! " if counter_win < speed * len(result_win): counter_win+=1 elif counter_win >= speed * len(result_win): done = True snip_win = txtf.render(result_win[0:counter_win//speed],True,(0,0,0)) Win.blit(snip_win,(150,350)) else: snip_lose = txtf.render('',True,(0,0,0)) counter_lose = 0 result_lose = "You have failed to unlock the chest ! " if counter_lose < speed * len(result_lose): counter_lose+=1 elif counter_lose >= speed * len(result_lose): done = True snip_lose = txtf.render(result_lose[0:counter_lose//speed],True,(0,0,0)) Win.blit(snip_lose,(150,350)) user_text_surface = txtf.render(user_text,True,(0,0,0)) Win.blit(user_text_surface, (150,250)) pygame.display.update() clock.tick(100)
问题分析与修复代码
核心问题点
- 事件队列重复处理:主循环中存在两个
pygame.event.get()调用,第一个会取走所有QUIT事件,第二个可能无法获取完整的键盘输入事件,导致stime未正确记录、用户输入不完整。 - 提示文本换行符问题:
readlines()读取的每行文本末尾包含\n换行符,用户输入不会包含该字符,直接对比永远不相等。 - 通关逻辑缩进错误:胜利/失败的判断逻辑缩进错误,导致失败分支永远不会执行;结果文本渲染仅执行一次,无法显示动画效果。
- 未初始化计时变量:若用户未按Enter就输入文本,
stime未定义会引发报错。 - 提示文本生成逻辑缺陷:原函数可能选中不符合长度要求的文本,递归调用未返回结果。
修复后的完整GUI代码
import pygame from sys import exit from time import time from random import randint #--------------------------Functions-------------------------------- def GeneratePrompt(): with open(r"C:\Users\adarshrsm\Desktop\prompts.txt", 'r') as file: # 先过滤符合长度要求的提示文本,再随机选择 valid_prompts = [p.rstrip('\n') for p in file.readlines() if 10 <= len(p.strip()) <=25] if not valid_prompts: raise ValueError("No valid prompts found in the file") index = randint(0, len(valid_prompts)-1) return valid_prompts[index] def typingSpeed(iprompt, stime, etime): global iwords iwords = iprompt.split() twords = len(iwords) elapsed_time = etime - stime # 避免除以0 if elapsed_time <=0: return 0 speed = twords / elapsed_time return speed #-------------------------GUI and main game loop----------------------------------- pygame.init() Win = pygame.display.set_mode((1000,900)) clock = pygame.time.Clock() # 加载资源(路径请根据实际情况调整) chest_left_tilt = pygame.image.load(r"C:\Users\adarshrsm\Downloads\chest_left_tilt.png") chest_right_tilt = pygame.image.load(r"C:\Users\adarshrsm\Downloads\right tilt.png") display_textbox = pygame.image.load(r"C:\Users\adarshrsm\Downloads\final textbox.png") display_textbox.set_alpha(100) txtf = pygame.font.Font(r"C:\Users\adarshrsm\Downloads\game font.ttf",40) # 初始化变量 EnterPrompt = txtf.render("Enter this code to open the chest: ",True,(0,0,0)) EnterPrompt.set_alpha(200) EnterLine = "Press Enter to start" counter = 0 text_speed = 3 # 重命名避免和打字速度变量冲突 imgtick = 1 displayprompt = GeneratePrompt() user_text = '' GameStatus = True stime = None # 初始化计时开始时间 game_result = None # 存储游戏结果:"win"或"lose" result_counter = 0 result_text = "" while GameStatus == True: # 统一处理所有事件 for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit() if event.type == pygame.KEYDOWN: if event.key == pygame.K_BACKSPACE: user_text = user_text[:-1] elif event.key == pygame.K_ESCAPE: pygame.quit() exit() elif event.key == pygame.K_RETURN: if stime is None: # 第一次按Enter开始计时 stime = time() EnterLine = "Start typing!" else: # 按Enter提交输入(可选,也可自动匹配) pass else: user_text += event.unicode # 绘制背景和静态元素 if imgtick % 100 == 0: Win.blit(chest_left_tilt,(0,0)) else: Win.blit(chest_right_tilt,(0,0)) imgtick +=1 Win.blit(display_textbox,(100,50)) Win.blit(EnterPrompt,(150,100)) # 绘制提示文本动画 if counter < text_speed * len(displayprompt): counter +=1 displayed_prompt = displayprompt[0:counter//text_speed] snip = txtf.render(displayed_prompt,True,(0,0,0)) Win.blit(snip,(150,150)) # 绘制提示行 EnterLineRender = txtf.render(EnterLine,True,(0,0,0)) EnterLineRender.set_alpha(200) Win.blit(EnterLineRender,(150,200)) # 绘制用户输入 user_text_surface = txtf.render(user_text,True,(0,0,0)) Win.blit(user_text_surface, (150,250)) # 游戏结果判断逻辑 if game_result is None and stime is not None: if user_text == displayprompt: etime = time() speed = typingSpeed(user_text, stime, etime) wpm = round(speed *60, 2) if wpm >=35: game_result = "win" result_text = "You have unlocked the chest ! " else: game_result = "lose" result_text = "You have failed to unlock the chest ! " # 绘制结果动画 if game_result is not None: if result_counter < text_speed * len(result_text): result_counter +=1 displayed_result = result_text[0:result_counter//text_speed] result_surface = txtf.render(displayed_result,True,(0,0,0)) Win.blit(result_surface,(150,350)) pygame.display.update() clock.tick(100)
关键修改说明
- 合并事件处理:将所有事件处理放在一个
for event in pygame.event.get()循环中,确保所有输入事件被正确捕获。 - 处理换行符:在
GeneratePrompt中用rstrip('\n')去掉文本末尾的换行符,同时过滤掉空行和不符合长度的文本。 - 修复计时逻辑:初始化
stime为None,仅在第一次按Enter时开始计时,避免未计时就触发判断。 - 重构结果渲染:将结果动画逻辑移到主循环中,确保每一帧都更新渲染状态,显示完整的打字动画。
- 变量名冲突修复:将原
speed变量重命名为text_speed,避免和打字速度计算的speed变量冲突。 - 优化提示文本生成:先过滤有效提示再随机选择,避免选中不符合要求的文本,同时移除无效的递归调用。
内容的提问来源于stack exchange,提问作者adarsh
相关产品推荐
相关产品推荐

