基于Python Tkinter的Simon Says游戏开发问题求助
问题解决与代码修改
问题1:CPU标签无法逐个切换图像
Tkinter中直接使用time.sleep()会阻塞主事件循环,导致界面无法实时更新,看不到图像切换效果。需要用Tkinter的after()方法实现延迟动作,让每个图像显示后等待一段时间再切换下一个。
修改思路:
- 先生成完整的CPU动作列表
- 用递归方式,通过
after()逐个显示每个动作的图像,最后恢复初始图像
问题2:对比CPU与用户的动作列表
Python中列表支持直接用==判断是否完全一致(元素顺序和内容都相同)。需要在用户输入完所有动作后触发对比逻辑。
修改思路:
- 添加
check_answer()方法处理对比逻辑 - 用户每次点击按钮后检查输入长度是否等于CPU动作长度,达到后自动触发对比
修改后的完整代码
import random from tkinter import * from PIL import ImageTk, Image class Gui: def __init__(self, window): # Image variables self.listofdirect = ['up', 'down', 'left', 'right'] self.player_image = ImageTk.PhotoImage(Image.open("images/mavs.png")) self.caller_img = ImageTk.PhotoImage(Image.open("images/durango.png")) self.right_image = ImageTk.PhotoImage(Image.open("images/right.png")) self.left_image = ImageTk.PhotoImage(Image.open("images/left.png")) self.up_image = ImageTk.PhotoImage(Image.open("images/up.png")) self.down_image = ImageTk.PhotoImage(Image.open("images/down.png")) self.window = window # Caller Frame self.frame_one = Frame(self.window) self.caller_lbl = Label(self.frame_one, image=self.caller_img, width=180) self.score_lbl = Label(self.frame_one, text="Score: 0") self.caller_lbl.pack(side='left') self.score_lbl.pack(side="top") self.frame_one.pack() self.frame_one2 = Frame(self.window) # spacer self.label_age = Label(self.frame_one2, text="---------", width=6) self.label_age.pack(side='left') self.frame_one2.pack() # Age Frame self.frame_two = Frame(self.window) self.user_lbl = Label(self.frame_two, image=self.player_image, width=180) self.user_lbl.pack(side='left') self.frame_two.pack() # Arrow Keys self.direct_button = Frame(self.frame_two) self.label_stat = Label(self.direct_button, text="Options") """Buttons: Up, Down, Left, Right """ self.upButton = Button(self.direct_button, text="⇧", command=self.upClick, state=DISABLED) self.downButton = Button(self.direct_button, text="⇩", command=self.downClick, state=DISABLED) self.leftButton = Button(self.direct_button, text="⇦", command=self.leftClick, state=DISABLED) self.rightButton = Button(self.direct_button, text="⇨", command=self.rightClick, state=DISABLED) self.upButton.pack(side="top") self.downButton.pack(side="bottom") self.leftButton.pack(side="left") self.rightButton.pack(side="right") self.direct_button.pack() # Save Button (Start Game) self.save_btn = Frame(self.window) self.button_save = Button(self.save_btn, text='Start Game', width=10, command=self.submit) self.button_save.grid(row=0, column=2) self.save_btn.pack() self.reset_btn = Frame(self.window) self.button_reset = Button(self.reset_btn, text="Reset", command=self.reset, state=DISABLED) self.reset_btn.pack() self.button_reset.pack() # Direction Label self.direct = Frame(self.window) self.label_direct = Label(self.direct, text='Click Start Game to begin') self.label_direct.pack(side='left') self.direct.pack() self.caller_list = [] self.player_list = [] self.DIRECTIONS = ["up", "down", "left", "right"] self.MOVE_LENGTH = random.randint(1, 5) self.WAIT_TIME = 1000 # 延迟时间,单位毫秒 self.SCORE = 0 self.ATTEMPT = 0 def rightClick(self): self.user_lbl.config(image=self.right_image) self.player_list.append("right") self.check_input_length() def leftClick(self): self.user_lbl.config(image=self.left_image) self.player_list.append("left") self.check_input_length() def upClick(self): self.user_lbl.config(image=self.up_image) self.player_list.append("up") self.check_input_length() def downClick(self): self.user_lbl.config(image=self.down_image) self.player_list.append("down") self.check_input_length() def check_input_length(self): # 检查用户输入是否完成 if len(self.player_list) == self.MOVE_LENGTH: self.check_answer() def show_cpu_move(self, moves, index=0): # 递归显示CPU的每个动作 if index >= len(moves): # 所有动作显示完毕,恢复初始图像 self.caller_lbl.config(image=self.caller_img) self.label_direct.config(text="Now repeat the sequence!") return move = moves[index] # 设置对应图像 if move == "up": self.caller_lbl.config(image=self.up_image) elif move == "down": self.caller_lbl.config(image=self.down_image) elif move == "left": self.caller_lbl.config(image=self.left_image) elif move == "right": self.caller_lbl.config(image=self.right_image) # 延迟后显示下一个动作 self.window.after(self.WAIT_TIME, self.show_cpu_move, moves, index+1) def game(self): self.computer_list = [] # 生成随机动作列表 for _ in range(self.MOVE_LENGTH): move = random.choice(self.DIRECTIONS) self.computer_list.append(move) print(f"CPU sequence: {self.computer_list}") # 开始显示动作序列 self.show_cpu_move(self.computer_list) def check_answer(self): # 对比两个列表 if self.player_list == self.computer_list: self.SCORE += 1 self.label_direct.config(text=f"Correct! Score: {self.SCORE}") self.score_lbl.config(text=f"Score: {self.SCORE}") # 下一轮增加难度(最多5个动作) self.MOVE_LENGTH = min(self.MOVE_LENGTH + 1, 5) else: self.label_direct.config(text=f"Wrong! Correct sequence was: {self.computer_list}") # 禁用方向按钮,等待重置 self.upButton.config(state=DISABLED) self.downButton.config(state=DISABLED) self.leftButton.config(state=DISABLED) self.rightButton.config(state=DISABLED) self.button_reset.config(state=NORMAL) def submit(self): self.button_save.config(state=DISABLED) self.button_reset.config(state=DISABLED) # 启用方向按钮 self.upButton.config(state=NORMAL) self.downButton.config(state=NORMAL) self.leftButton.config(state=NORMAL) self.rightButton.config(state=NORMAL) self.player_list = [] self.label_direct.config(text="Watch the sequence!") self.game() def reset(self): self.button_reset.config(state=DISABLED) self.button_save.config(state=NORMAL) self.player_list = [] self.computer_list = [] self.caller_lbl.config(image=self.caller_img) self.user_lbl.config(image=self.player_image) self.label_direct.config(text='Click Start Game to begin') # 禁用方向按钮直到下一轮开始 self.upButton.config(state=DISABLED) self.downButton.config(state=DISABLED) self.leftButton.config(state=DISABLED) self.rightButton.config(state=DISABLED) if __name__ == "__main__": window = Tk() window.title("Simon Says") app = Gui(window) window.mainloop()
关键修改说明
CPU图像切换修复:
- 新增
show_cpu_move()递归方法,通过after()实现每个动作的延迟显示,避免阻塞主循环 - 每个动作显示后等待1秒(可通过
WAIT_TIME调整),自动切换下一个动作,最后恢复初始图像
- 新增
列表对比逻辑:
- 新增
check_answer()方法,直接用==对比player_list和computer_list,判断顺序和内容是否完全一致 - 新增
check_input_length()方法,用户每次点击按钮后检查输入长度,达到CPU动作长度时自动触发对比
- 新增
交互优化:
- 游戏开始前禁用方向按钮,避免误操作
- 对比完成后禁用方向按钮,需点击重置才能开始新游戏
- 增加分数更新和提示信息,提升用户体验
内容的提问来源于stack exchange,提问作者Kawinthida Haase
相关产品推荐
相关产品推荐

