Python Turtle模块没有回应要发出的击键
到目前为止,我的蛇游戏还可以。一个问题是,由于某种原因,“乌龟”没有回应击键,我真的不知道为什么。我尝试了很多不同的东西,但这都是毫无用处的。主要问题是我不完全确定主要问题在哪里。我确定的是,问题很可能来自我的代码,但我似乎找不到。如果您可以协助我解决这个问题,那将是很棒的。
import time
from turtle import Screen, Turtle
STARTING_X_POSITIONS = [0, -20, -40]
MOVEMENT_DISTANCE = 20
class Snake:
def __init__(self):
self.segments = []
self.create_snake()
self.head = self.segments[0]
def create_snake(self):
for i in range(3):
new_snake = Turtle('square')
new_snake.color('RoyalBlue')
new_snake.penup()
new_snake.goto(STARTING_X_POSITIONS[i], 0)
self.segments.append(new_snake)
def move(self):
# We Want The Loop To Start At Index (2) And Decrease Itself Till It Reaches Zero (Excluded)
for snake_index in range(len(self.segments) - 1, 0, -1):
x_pos = self.segments[snake_index - 1].xcor()
y_pos = self.segments[snake_index - 1].ycor()
self.segments[snake_index].goto(x_pos, y_pos)
self.segments[0].forward(MOVEMENT_DISTANCE)
def up(self):
self.head.setheading(90)
def down(self):
self.head.setheading(270)
def left(self):
self.head.setheading(180)
def right(self):
self.head.setheading(0)
def setup_screen(screen):
screen.bgcolor('black')
screen.title('Snake Game')
screen.setup(width=600, height=600)
screen.tracer(0)
def start_game(screen, snake):
setup_screen(screen)
game_on = True
while game_on:
screen.update()
time.sleep(0.1)
snake.move()
def control_snake(screen, snake):
screen.listen()
screen.onkey(key='Up', fun=snake.up)
screen.onkey(key='Down', fun=snake.down)
screen.onkey(key='Left', fun=snake.left)
screen.onkey(key='Right', fun=snake.right)
screen.exitonclick()
def main():
screen = Screen()
snake = Snake()
start_game(screen, snake)
control_snake(screen, snake)
if __name__ == '__main__':
main()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是调试时最小化代码的重要性的一个很好的例子。在此处考虑代码:
main
调用start_game
,但是start_game
在其中循环中具有无限。
game_on
永远不会设置为false
,因此control_snake
永远不会达到。尝试在之前添加关键的侦听器您进入无限渲染循环,而不是之后。
移动
control_snake
start_game
引入了一个新问题,即screen.exitonclick()
是control> control> control_snake
的一部分。 ,但是如果control_snake
在start_game
之前调用,则screet.exitonclick()
blocks and blocks并预防start_game
从运行中。因此,我们需要删除screen.exitonClick()
。但是,触发重复事件的方法比
更好,而
/sleep
是 screen.exitonclick()呼叫上阻止。 这篇文章显示了一个示例。退后一步,这里还有一些其他提示,这些技巧解决了错误的误解和根本原因。
从
start_game
调用setup_screen
有点奇怪。我会从main
中调用setup_screen
将其解除。我可以想象一个情况下,我们想设置一次屏幕,但是在蛇死后多次重新启动游戏。通常,在您拥有基本代码工作之前,我不必担心将事情分解为功能。不要仅仅因为您听说过功能超过5或6行很差而写抽象。这些函数应该具有明确的奇异目的,并避免奇怪的依赖性。
例如,
control_snake
应真正称为add_snake_controls_then_block_until_exit
或类似的东西,因为它不仅添加了蛇控件(它并不是真正“控制蛇”注册执行此操作的控件,还可以阻止整个脚本并运行Turtle的内部更新循环,直到用户单击窗口。这听起来可能是ped的,但是如果您将此功能命名为准确说明其所做的事情,那么该错误将更加明显,并且通常会带来更清晰的代码的辅助益处。您的游戏循环代码:
遵循有点混乱。通常的渲染顺序是:
我建议更清楚的
另一个提示/经验法则是在小块中工作,经常运行代码。看来您编写了大量代码,然后第一次运行它,不确定在哪里开始调试。如果我正在写蛇游戏,则我不必担心尾巴逻辑,直到我设置头并确定它有效。
如果您尽了最大的努力,请使用很多代码和错误,请系统地添加打印件,以查看达到控制权的位置。如果您在
control_snake
中添加了打印,您会发现它永远不会被调用,这几乎会散发出问题(因此是其解决方案)。另一个调试策略是删除代码,直到问题消失,然后将最后一块返回,以确切查看问题是什么。
话虽如此,您的
蛇
类似乎有目的且写得很好。这是我的重写建议:
由于没有重新启动条件或随附的逻辑,因此可能需要重新分配以允许“游戏上的游戏”屏幕并重置蛇或类似的东西,但至少没有稳固的必须提出推论的过早抽象。
This is a good example of the importance of minimizing the code when you debug. Consider the code here:
main
callsstart_game
, butstart_game
has an infinitewhile
loop in it.game_on
is never set toFalse
, and socontrol_snake
will never be reached.Try adding key listeners before you go into your infinite rendering loop, not after.
Moving
control_snake
ahead ofstart_game
introduces a new problem, which is thatscreen.exitonclick()
is part ofcontrol_snake
, but ifcontrol_snake
is called beforestart_game
, then thescreen.exitonclick()
blocks and preventsstart_game
from running. So we need to removescreen.exitonclick()
.But there's a better way to trigger repeated events than
while
/sleep
, which isscreen.ontimer
. This lets you defer control back to your main loop and block on ascreen.exitonclick()
call. This post shows an example.Taking a step back, here are a few other tips that address underlying misconceptions and root causes of your bugs.
It's a bit odd that
setup_screen
is called fromstart_game
. I'd callsetup_screen
frommain
to decouple these. I can imagine a case where we want to set up the screen once, but restart the game multiple times, for example, after the snake dies.In general, I'd worry less about breaking things out into functions until you have the basic code working. Don't write abstractions just because you've heard that functions longer than 5 or 6 lines are bad. The functions should have a clear, singular purpose foremost and avoid odd dependencies.
For example,
control_snake
should really be calledadd_snake_controls_then_block_until_exit
or something like that, because not only does it add snake controls (it doesn't really "control the snake" exactly, it registers the controls that do so), it also blocks the whole script and runs turtle's internal update loop until the user clicks the window. This might sound pedantic, but if you'd named this function to state exactly what it does, the bug would be much more obvious, with the side benefit of clearer code in general.Your game loop code:
is a bit confusing to follow. The usual rendering sequence is:
I suggest the clearer
Another tip/rule of thumb is to work in small chunks, running your code often. It looks like you wrote a huge amount of code, then ran it for the first time and weren't sure where to begin debugging. If I were writing a snake game, I wouldn't worry about the tail logic until I've set up the head and established that it works, for example.
If you do wind up with a lot of code and a bug in spite of your best efforts, systematically add prints to see where control is reached. If you added a print in
control_snake
, you'd see it never gets called, which pretty much gives away the problem (and therefore its solution).Another debugging strategy is to remove code until the problem goes away, then bring back the last chunk to see exactly what the problem was.
All that said, your
Snake
class seems purposeful and well-written.Here's my rewrite suggestion:
Since there's no restarting condition or accompanying logic, this will probably need to be refactored to allow for a "game over" screen and resetting the snake or something like that, but at least it's solid and there aren't a lot of premature abstractions to have to reason about.
我的工作如下
I got it working as follows