You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python迷宫游戏重启功能实现报错,寻求解决方法

问题

我是Python初学者,开发迷宫游戏时无法实现重新开始游戏的功能,尝试多种方法均以报错告终。我尝试销毁承载迷宫的frame_top后调用new_game函数生成新迷宫,但触发了错误,相关代码及错误栈如下:

import tkinter as tk
import random
from tkinter import messagebox

global SIZE
global ROW
global COLUMN
SIZE = 10
COLUMN = 7
ROW = 7

departure = [[1, 1]]    
playerX = 1
playerY = 1
beforeX = 1
beforeY = 1

maze = []
for y in range(ROW) :
    sub = []
    for x in range(COLUMN) :
        if y==0 or y==ROW-1 or x==0 or x==COLUMN-1 :
            sub.append("WALL")
        else :
            sub.append("FIELD")
    maze.append(sub)

def dig(x, y) :
    maze[y][x] = "PATH"
    canMove = []
    if maze[y-1][x]=="FIELD" and maze[y-2][x]=="FIELD" :
        canMove.append("UP")
    if maze[y+1][x]=="FIELD" and maze[y+2][x]=="FIELD" :
        canMove.append("DOWN")
    if maze[y][x-1]=="FIELD" and maze[y][x-2]=="FIELD" :
        canMove.append("LEFT")
    if maze[y][x+1]=="FIELD" and maze[y][x+2]=="FIELD" :
        canMove.append("RIGHT")
    if len(canMove)==0 :
        return
    
    direction = random.choice(canMove)
    if direction=="UP" :
        maze[y-1][x]="PATH"
        maze[y-2][x]="PATH"
        y -= 2
    if direction=="DOWN" :
        maze[y+1][x]="PATH"
        maze[y+2][x]="PATH"
        y += 2
    if direction=="LEFT" :
        maze[y][x-1]="PATH"
        maze[y][x-2]="PATH"
        x -= 2
    if direction=="RIGHT" :
        maze[y][x+1]="PATH"
        maze[y][x+2]="PATH"
        x += 2
    departure.append([x, y])    
    dig(x, y)

def keyPress(event) :
    global playerX,playerY,beforeX,beforeY
    if event.keysym=="Up" and maze[playerY-1][playerX]=="PATH" :
        beforeX = playerX
        beforeY = playerY
        playerY -=1
    if event.keysym=="Down" and maze[playerY+1][playerX]=="PATH" :
        beforeX = playerX
        beforeY = playerY
        playerY +=1
    if event.keysym=="Left" and maze[playerY][playerX-1]=="PATH" :
        beforeX = playerX
        beforeY = playerY
        playerX -=1
    if event.keysym=="Right" and maze[playerY][playerX+1]=="PATH" :
        beforeX = playerX
        beforeY = playerY
        playerX +=1

def move() :
    can.create_oval(beforeX*SIZE+1, beforeY*SIZE+1, (beforeX+1)*SIZE-1, (beforeY+1)*SIZE-1, fill="white", width=0)
    can.create_oval(playerX*SIZE+2, playerY*SIZE+2, (playerX+1)*SIZE-2, (playerY+1)*SIZE-2, fill="blue")
    if playerX==COLUMN-2 and playerY==ROW-2 :
        messagebox.showinfo("INFORMATION", "CONGRATULATIONS!!!")
        frame_top.destroy()
        new_game()
    can.after(100, move)    

def new_game():
    
    departure = [[1, 1]]    
    playerX = 1
    playerY = 1
beforeX = 1
beforeY = 1
    maze = []
    canMove = []
    print (maze)
    for y in range(ROW) :
        sub = []
        for x in range(COLUMN) :
            if y==0 or y==ROW-1 or x==0 or x==COLUMN-1 :
                sub.append("WALL")
            else :
                sub.append("FIELD")
        maze.append(sub)
    while len(departure)!=0 :   
        start = departure.pop(0)
        x = start[0]
        y = start[1]
        dig(x, y)
        print(x)
        print(y)
        
    for y in range(ROW):        
        for x in range(COLUMN):
            if maze[y][x]=="PATH" :
                color = "white"
            else :
                color = "black"
            can.create_rectangle(x*SIZE, y*SIZE, (x+1)*SIZE, (y+1)*SIZE, fill=color, width=0)
    
    can.create_rectangle((COLUMN-2)*SIZE, (ROW-2)*SIZE, (COLUMN-1)*SIZE, (ROW-1)*SIZE ,fill="red")
        
    move()

global win
win = tk.Tk()
frame_top = tk.Frame(win)
frame_top.pack()

global can
can = tk.Canvas(frame_top, width=COLUMN*SIZE, height=ROW*SIZE)
can.pack()
m = tk.Menu(win)
win.config(menu=m)

om = tk.Menu(m, tearoff=0)
m.add_cascade(label='Options', menu=om)
om.add_command(label='New Game',command= new_game )
om.add_command(label='Settings', )

while len(departure)!=0 :   
    start = departure.pop(0)
    x = start[0]
    y = start[1]
    dig(x, y)
    print(x)
    print(y)

for y in range(ROW):        
    for x in range(COLUMN):
        if maze[y][x]=="PATH" :
            color = "white"
        else :
            color = "black"
        can.create_rectangle(x*SIZE, y*SIZE, (x+1)*SIZE, (y+1)*SIZE, fill=color, width=0)

can.create_rectangle((COLUMN-2)*SIZE, (ROW-2)*SIZE, (COLUMN-1)*SIZE, (ROW-1)*SIZE ,fill="red")  

move()      
win.bind("<Any-KeyPress>", keyPress)    

win.mainloop()

main()

错误栈:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 1921, in __call__
    return self.func(*args)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", 
line 839, in callit
    func(*args)
  File "C:/Users/Admin/AppData/Local/Programs/Python/Python310/fileend.py", 
line 92, in move
    new_game()
  File "C:/Users/Admin/AppData/Local/Programs/Python/Python310/fileend.py", line 128, in new_game
    can.create_rectangle(x*SIZE, y*SIZE, (x+1)*SIZE, (y+1)*SIZE, fill=color, width=0)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 2835, in create_rectangle
    return self._create('rectangle', args, kw)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 2805, in _create
    return self.tk.getint(self.tk.call(
_tkinter.TclError: invalid command name ".!frame.!canvas"
解决方案

错误根源

  1. 销毁frame_top后,内部的Canvas组件can被彻底删除,但new_game仍尝试调用该组件的绘图方法,触发无效命令错误。
  2. move函数通过after持续循环,即使组件销毁,循环仍会执行,引发后续错误。
  3. new_game中未声明全局变量,导致局部变量覆盖全局状态,逻辑混乱。
  4. 存在缩进错误、按键绑定转义错误、多余函数调用等语法问题。

修复后的关键修改

  1. 保留Canvas组件:用can.delete("all")清空画布内容,替代销毁frame_top,避免组件失效。
  2. 终止循环:新增after_id变量保存after的ID,在new_game中用can.after_cancel(after_id)终止之前的move循环。
  3. 全局变量声明:在new_game中添加全局变量声明,确保修改的是全局状态而非局部变量。
  4. 修复语法问题:修正beforeX的缩进错误,将&lt;Any-KeyPress&gt;改为<Any-KeyPress>,移除多余的main()调用。

完整修复代码

import tkinter as tk
import random
from tkinter import messagebox

SIZE = 10
COLUMN = 7
ROW = 7

departure = [[1, 1]]    
playerX = 1
playerY = 1
beforeX = 1
beforeY = 1
after_id = None

maze = []
for y in range(ROW) :
    sub = []
    for x in range(COLUMN) :
        if y==0 or y==ROW-1 or x==0 or x==COLUMN-1 :
            sub.append("WALL")
        else :
            sub.append("FIELD")
    maze.append(sub)

def dig(x, y) :
    maze[y][x] = "PATH"
    canMove = []
    if maze[y-1][x]=="FIELD" and maze[y-2][x]=="FIELD" :
        canMove.append("UP")
    if maze[y+1][x]=="FIELD" and maze[y+2][x]=="FIELD" :
        canMove.append("DOWN")
    if maze[y][x-1]=="FIELD" and maze[y][x-2]=="FIELD" :
        canMove.append("LEFT")
    if maze[y][x+1]=="FIELD" and maze[y][x+2]=="FIELD" :
        canMove.append("RIGHT")
    if len(canMove)==0 :
        return
    
    direction = random.choice(canMove)
    if direction=="UP" :
        maze[y-1][x]="PATH"
        maze[y-2][x]="PATH"
        y -= 2
    if direction=="DOWN" :
        maze[y+1][x]="PATH"
        maze[y+2][x]="PATH"
        y += 2
    if direction=="LEFT" :
        maze[y][x-1]="PATH"
        maze[y][x-2]="PATH"
        x -= 2
    if direction=="RIGHT" :
        maze[y][x+1]="PATH"
        maze[y][x+2]="PATH"
        x += 2
    departure.append([x, y])    
    dig(x, y)

def keyPress(event) :
    global playerX, playerY, beforeX, beforeY
    if event.keysym=="Up" and maze[playerY-1][playerX]=="PATH" :
        beforeX = playerX
        beforeY = playerY
        playerY -=1
    if event.keysym=="Down" and maze[playerY+1][playerX]=="PATH" :
        beforeX = playerX
        beforeY = playerY
        playerY +=1
    if event.keysym=="Left" and maze[playerY][playerX-1]=="PATH" :
        beforeX = playerX
        beforeY = playerY
        playerX -=1
    if event.keysym=="Right" and maze[playerY][playerX+1]=="PATH" :
        beforeX = playerX
        beforeY = playerY
        playerX +=1

def move() :
    global after_id
    can.create_oval(beforeX*SIZE+1, beforeY*SIZE+1, (beforeX+1)*SIZE-1, (beforeY+1)*SIZE-1, fill="white", width=0)
    can.create_oval(playerX*SIZE+2, playerY*SIZE+2, (playerX+1)*SIZE-2, (playerY+1)*SIZE-2, fill="blue")
    if playerX==COLUMN-2 and playerY==ROW-2 :
        messagebox.showinfo("INFORMATION", "CONGRATULATIONS!!!")
        new_game()
    after_id = can.after(100, move)    

def new_game():
    global departure, playerX, playerY, beforeX, beforeY, maze, after_id
    
    # 终止之前的move循环
    if after_id is not None:
        can.after_cancel(after_id)
    
    # 清空画布所有内容
    can.delete("all")
    
    # 重置游戏状态
    departure = [[1, 1]]    
    playerX = 1
    playerY = 1
    beforeX = 1
    beforeY = 1
    maze = []
    
    # 重新生成迷宫初始矩阵
    for y in range(ROW) :
        sub = []
        for x in range(COLUMN) :
            if y==0 or y==ROW-1 or x==0 or x==COLUMN-1 :
                sub.append("WALL")
            else :
                sub.append("FIELD")
        maze.append(sub)
    
    # 重新挖迷宫
    while len(departure)!=0 :   
        start = departure.pop(0)
        x = start[0]
        y = start[1]
        dig(x, y)
    
    # 绘制新迷宫
    for y in range(ROW):        
        for x in range(COLUMN):
            color = "white" if maze[y][x]=="PATH" else "black"
            can.create_rectangle(x*SIZE, y*SIZE, (x+1)*SIZE, (y+1)*SIZE, fill=color, width=0)
    
    # 绘制终点
    can.create_rectangle((COLUMN-2)*SIZE, (ROW-2)*SIZE, (COLUMN-1)*SIZE, (ROW-1)*SIZE, fill="red")
        
    # 重新启动移动循环
    move()

# 初始化界面
win = tk.Tk()
frame_top = tk.Frame(win)
frame_top.pack()

can = tk.Canvas(frame_top, width=COLUMN*SIZE, height=ROW*SIZE)
can.pack()

# 菜单设置
m = tk.Menu(win)
win.config(menu=m)
om = tk.Menu(m, tearoff=0)
m.add_cascade(label='Options', menu=om)
om.add_command(label='New Game', command=new_game)
om.add_command(label='Settings')

# 初始生成迷宫
while len(departure)!=0 :   
    start = departure.pop(0)
    x = start[0]
    y = start[1]
    dig(x, y)

# 绘制初始迷宫
for y in range(ROW):        
    for x in range(COLUMN):
        color = "white" if maze[y][x]=="PATH" else "black"
        can.create_rectangle(x*SIZE, y*SIZE, (x+1)*SIZE, (y+1)*SIZE, fill=color, width=0)

# 绘制初始终点
can.create_rectangle((COLUMN-2)*SIZE, (ROW-2)*SIZE, (COLUMN-1)*SIZE, (ROW-1)*SIZE, fill="red")  

# 启动移动循环
after_id = can.after(100, move)      
win.bind("<Any-KeyPress>", keyPress)    

win.mainloop()

内容的提问来源于stack exchange,提问作者UNTAKEU

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 15:55:33