Python Turtle库turtle.Terminator报错排查及修复求助
Fixing
turtle.Terminator Exception in Your Python Turtle Game 我帮你分析下这个问题——你遇到的turtle.Terminator异常,本质是当Turtle图形窗口已经关闭后,代码还在尝试创建或操作Turtle对象导致的。结合你的代码和错误栈,我梳理出几个核心问题,以及对应的修复步骤:
1. 核心错误原因
- 循环内重复定义函数与创建Turtle/Screen对象:你的
Forme.draw()方法里有个while boucle循环,每次选"1. Jouer"时,都会重复定义setup_labyrinthe、scorefn,还会重新创建Screen、Stylo等对象。第一次退出游戏后窗口关闭,循环再次运行时,旧的Turtle上下文没清理,新对象创建就触发了异常。 - 未正确导入模块却使用
turtle.Pen():你只from turtle import Turtle, Screen,但代码里写了t = turtle.Pen(),这会导致NameError(虽然你的错误栈没显示,但这是隐藏隐患)。 - 全局变量使用混乱:
scorefn里用global score,但score是在循环内定义的,多次运行会导致作用域冲突。
2. 分步修复方案
(1)把函数移到循环外部,避免重复定义
将setup_labyrinthe、scorefn这些核心函数从while boucle里抽出来,明确变量传递逻辑:
from turtle import Turtle, Screen # 你的类定义保持不变:Stylo、Joueur、Tresor、Forme # 移到循环外的关卡初始化函数 def setup_labyrinthe(niveau, stylo, joueur, tresors, murs): for y in range(len(niveau)): for x in range(len(niveau[y])): caractere = niveau[y][x] ecran_x = -288 + (x * 24) ecran_y = 288 - (y * 24) if caractere == "X": stylo.goto(ecran_x, ecran_y) stylo.stamp() murs.append((ecran_x, ecran_y)) elif caractere == "J": joueur.goto(ecran_x, ecran_y) elif caractere == "T": tresors.append(Tresor(ecran_x, ecran_y)) # 移到循环外的得分函数,用参数传递替代全局变量 def scorefn(joueur, tresors, score, marker, police1, police2, screen): # 用切片遍历,避免修改列表时的迭代错误 for tresor in tresors[:]: if joueur.collision(tresor): tresor.destruction() tresors.remove(tresor) score += 100 marker.undo() marker.write(score, font=police1) if score == 1000 : marker.goto(-150, 0) marker.write("You Win !", font=police2) return score
(2)每次游戏创建全新的Turtle上下文
每次启动游戏时,都创建新的Screen和Turtle实例,避免复用已失效的窗口对象:
class Forme(object): def __init__(self, length, width, color, sides): self.length = length self.width = width self.color = color self.sides = sides def draw(self): # 替换turtle.Pen()为Turtle(),适配你的导入方式 t = Turtle() boucle=True while boucle: a=int(input("Choisissez la figure à réaliser avec Turtle :\n1. Jouer \n2. Leaderboard \n0. Sortir")) if a==1: # 每次游戏都创建全新的屏幕 game_screen = Screen() game_screen.bgcolor("black") game_screen.title("No Escape!") game_screen.setup(700, 700) # 加载游戏资源 IMAGES = ["right.gif", "left.gif", "face.gif", "back.gif", "tresor.gif", "mur.gif", "sol.gif"] for image in IMAGES: game_screen.addshape(image) POLICE1 = ('Arial', 24, 'bold') POLICE2 = ('Arial', 50, 'bold') NIVEAUX = [[ "XXXXXXXXXXXXXXXXXXXXXXXXX", "XJ X X X", "X X XXX X XXXXXXX X", "X X TX X X X", "X XXXXX X X XXXXXXX X", "XT X X X", "XXXXXXXX X XT X X X", "X X X XXXXXXXXXXXXXX X", "X X X X X X X", "X X XT X X X X XTX", "X X XXXX X X XXXXXX X XXX", "X X X X X TX X X", "X XXX XX XXXXXXXXXXXXXX", "X X X X", "XXXXXXXX XTX X X XXX X", "X X X XXX X X XT X", "X XXX X X X X XXXXX", "X XXT X X XXXXXXX X X X", "X XXXXX X X", "X XXXXXXXXXX X X", "XXXXX XXXXX X", "X X X X XX XXXXX", "X XXXXXXXX X XXX X XX", "X TX X XT X X X", "XXXXXXXXXXXXXXXXXXXXXXXXX"]] # 创建游戏对象 stylo = Stylo() joueur = Joueur() tresors = [] murs = [] # 初始化关卡 setup_labyrinthe(NIVEAUX[0], stylo, joueur, tresors, murs) # 初始化得分面板 score = 0 marker = Turtle(visible=False) marker.penup() marker.color('gray') marker.goto(-275, 305) marker.write("No Escape !", font=POLICE1) marker.goto(240, 305) marker.write(score, font=POLICE1) # 给玩家对象绑定游戏引用,方便调用得分函数 joueur.set_game_refs(tresors, marker, POLICE1, POLICE2, game_screen, murs) # 绑定按键事件 game_screen.onkeypress(joueur.gauche, "Left") game_screen.onkeypress(joueur.droite, "Right") game_screen.onkeypress(joueur.haut, "Up") game_screen.onkeypress(joueur.bas, "Down") # 自定义退出逻辑,确保窗口干净关闭 def quit_game(): game_screen.clear() game_screen.bye() game_screen.onkey(quit_game, "Escape") game_screen.listen() game_screen.tracer(True) game_screen.mainloop() # 阻塞直到窗口关闭 elif a==0: boucle=False # 退出时关闭所有残留窗口 Screen().bye()
(3)修改Joueur类,支持参数传递
给Joueur类添加方法,让它能访问游戏状态变量,调用得分函数:
class Joueur(Turtle): def __init__(self): Turtle.__init__(self, "face.gif") self.color("blue") self.penup() self.speed('fastest') # 初始化游戏引用 self.tresors = [] self.marker = None self.police1 = None self.police2 = None self.screen = None self.murs = [] self.score = 0 def set_game_refs(self, tresors, marker, police1, police2, screen, murs): self.tresors = tresors self.marker = marker self.police1 = police1 self.police2 = police2 self.screen = screen self.murs = murs def haut(self): move_to_x = self.xcor() move_to_y = self.ycor() + 24 self.shape("back.gif") if (move_to_x, move_to_y) not in self.murs: self.goto(move_to_x, move_to_y) self.score = scorefn(self, self.tresors, self.score, self.marker, self.police1, self.police2, self.screen) # 同理修改bas、gauche、droite方法,把murs换成self.murs,调用scorefn更新self.score def bas(self): move_to_x = self.xcor() move_to_y = self.ycor() - 24 self.shape("face.gif") if (move_to_x, move_to_y) not in self.murs: self.goto(move_to_x, move_to_y) self.score = scorefn(self, self.tresors, self.score, self.marker, self.police1, self.police2, self.screen) def gauche(self): move_to_x = self.xcor() - 24 move_to_y = self.ycor() self.shape("left.gif") if (move_to_x, move_to_y) not in self.murs: self.goto(move_to_x, move_to_y) self.score = scorefn(self, self.tresors, self.score, self.marker, self.police1, self.police2, self.screen) def droite(self): move_to_x = self.xcor() + 24 move_to_y = self.ycor() self.shape("right.gif") if (move_to_x, move_to_y) not in self.murs: self.goto(move_to_x, move_to_y) self.score = scorefn(self, self.tresors, self.score, self.marker, self.police1, self.police2, self.screen) def collision(self, other): return self.distance(other) < 5
3. 关键注意点
- 别用全局变量:全局变量很容易在循环场景下出问题,尽量用参数传递或类属性管理状态。
- 每次游戏都新建上下文:Turtle的窗口和对象绑定紧密,窗口关闭后对象就失效了,所以每次启动游戏都要创建新实例。
- 遍历列表时用切片:修改
tresors列表时,用tresors[:]创建切片遍历,避免迭代时修改原列表导致的错误。
这样修改后,应该就能解决turtle.Terminator异常,游戏逻辑也会更稳定清晰。
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

