如何使用onkey退出turtle库中控制蛇移动的while循环?
Turtle贪吃蛇游戏:解决按键退出循环的错误
错误原因分析
你遇到的AttributeError: 'Turtle' object has no attribute 'done'是因为done()是turtle库中屏幕(Screen)对象或者模块级别的方法,不是Turtle实例(你的snake)的方法,所以调用snake.done()完全错误。
除此之外,原代码还有几个逻辑问题:
- 嵌套的
while True循环和turtle.mainloop()冲突,mainloop()本身就是事件循环,手动写的while True会阻塞事件处理,导致按键响应异常。 if window.onkey(exit,"e"):的写法无效,onkey()是用来注册按键触发的函数,不会返回布尔值,这种判断没有意义。- 在循环中重复注册按键事件是冗余操作,只需要注册一次即可。
修正方案
- 用
window.bye()替代错误的snake.done(),bye()是Screen对象的方法,用来关闭窗口并结束程序。 - 使用turtle的
ontimer()方法实现蛇的持续移动,避免手动写while True阻塞事件循环。 - 统一在初始化阶段注册所有按键事件,包括退出的'e'键。
- 设置全局变量控制蛇的移动状态,方便退出时终止移动循环。
修正后的完整代码
import turtle # 初始化屏幕和蛇 window = turtle.Screen() snake = turtle.Turtle() snake.speed(0) snake.penup() # 全局标志:控制蛇是否继续移动 is_moving = False def forward(): global is_moving is_moving = True move_snake_continuously() def move_snake_continuously(): if is_moving: snake.forward(0.8) # 每隔10毫秒调用一次,实现非阻塞的持续移动 window.ontimer(move_snake_continuously, 10) def left(): snake.left(90) def right(): snake.right(90) def back(): global is_moving is_moving = True snake.back(0.8) window.ontimer(lambda: snake.back(0.8) if is_moving else None, 10) def exit_game(): global is_moving is_moving = False window.bye() # 关闭窗口,结束程序 # 一次性注册所有按键事件 window.listen() window.onkey(forward, "w") window.onkey(left, "a") window.onkey(right, "d") window.onkey(back, "s") window.onkey(exit_game, "e") # 启动turtle事件循环 window.mainloop()
代码说明
is_moving全局变量用来控制蛇的移动状态,按下'e'键时会将其设为False,终止后续的移动调用。move_snake_continuously()通过ontimer()实现非阻塞的持续移动,不会影响按键事件的响应。exit_game()函数负责停止移动并关闭窗口,彻底替代了原错误的snake.done()。- 所有按键事件仅注册一次,放在
mainloop()之前,避免冗余操作。
内容的提问来源于stack exchange,提问作者Augustus
相关产品推荐
相关产品推荐

