我正试图用Python编写一个程序来模拟一个"旧"在线游戏,在这个游戏中,你可以通过键盘的一些输入在屏幕上驱动蠕虫。
import turtle
# Set screen and background
wn = turtle.Screen()
wn.title("Turn with Left and Right buttons your keyboard. Click on screen to EXIT.")
wn.bgcolor("black")
# Snake settings
snake = turtle.Turtle()
snake.color("purple")
snake.shape("circle")
snake.shapesize(0.25,0.25)
snake.pensize(5)
snake.speed(10)
t = 0
# Define Go loop, turn Left and Right
def go():
t = 0
while t < 1000:
snake.forward(1)
t += 1
def left():
snake.circle(1,8)
go()
def right():
snake.circle(1,-8)
go()
# Inputs and Exit on click
wn.onkey(right, "Right")
wn.onkeypress(right, "Right")
wn.onkey(left, "Left")
wn.onkeypress(left, "Left")
wn.listen()
wn.exitonclick()
turtle.done()
这里的问题是,在一些移动之后,程序崩溃返回:
RecursionError: maximum recursion depth exceeded while calling a Python object.
我还是个初学者,所以我不明白我做错了什么。如何修复错误?
您所经历的是由于事件堆叠而导致的伪递归。然而,您的代码设计:
while t < 1000:
snake.forward(1)
t += 1
实际上依赖于事件堆叠!也就是说,您希望在事件处理程序的go()
部分中输入左右命令,以保持乌龟移动。这是一个有问题的设计。让我们使用事件计时器来重新编写代码:
from turtle import Screen, Turtle
def go():
snake.forward(1)
screen.ontimer(go, 50)
def left():
screen.onkeypress(None, 'Left') # disable handler inside handler
snake.circle(1, 8)
screen.onkeypress(left, 'Left') # reenable handler
def right():
screen.onkeypress(None, 'Right')
snake.circle(1, -8)
screen.onkeypress(right, 'Right')
screen = Screen()
screen.title("Turn with Left and Right buttons your keyboard. Click on screen to EXIT.")
screen.bgcolor('black')
snake = Turtle()
snake.color('purple')
snake.shape('circle')
snake.shapesize(0.25)
snake.pensize(5)
snake.speed('fastest')
screen.onkeypress(left, 'Left')
screen.onkeypress(right, 'Right')
screen.listen()
go()
screen.exitonclick()
通过测试,显而易见的是,如果您的go
函数尚未完成,并且您仍在按住一个键,则会再次调用它,这意味着现在调用堆栈上有两个go
函数(加上一堆其他函数,如eventfun
和update
(。因为持有密钥每秒调用go
函数多次,而go
函数需要8秒以上的时间才能完成,所以调用堆栈中充满了对go
的调用,从而导致崩溃。调用堆栈就是这样反复出现的:
update, __init__.py:1314
_update, turtle.py:561
_update, turtle.py:2663
_goto, turtle.py:3197
_go, turtle.py:1606
forward, turtle.py:1638
go, script.py:21
left, script.py:26
eventfun, turtle.py:700
__call__, __init__.py:1892
即使只按住左侧3秒钟,我的调用堆栈也会增长到600多个,这真的很高。
要解决此问题,您可以将其设置为在该键仍处于按下状态时不能再次调用left
或right
。这是一种可能的方式。