【问题标题】:Python-Turtle - Moving the turtle by holding down a key: releasing the key moves the turtle back instead of stopping itPython-Turtle - 通过按住一个键来移动海龟:释放键会移动海龟而不是停止它
【发布时间】:2021-05-18 05:38:04
【问题描述】:

我正在编写一个程序,通过按下箭头键将海龟向不同方向移动。我希望能够通过按住相应的箭头键而不是反复按下它来将其移动到特定方向。但是,当我在按住箭头键几秒钟后松开箭头键时,乌龟会向后移动一点,而不是立即停止。它向后移动的量取决于我按住键移动它的时间。

你能帮我解决这个问题或建议用turtle模块实现这个问题的另一种方法吗?

注意:我观察到当我按住键时,直到我松开它才会画线。我不确定它是否与此问题有关。

注意 2:我正在使用 onkeypress 方法来处理“按住键”事件。我尝试使用 onkeyrelease(None, arrow_key) 方法来解决这个问题,但它也不起作用。

这是我的代码:

from turtle import Turtle, Screen


def move_right():
    turtle.setheading(0)
    turtle.forward(25)


def move_up():
    turtle.setheading(90)
    turtle.forward(25)


def move_left():
    turtle.setheading(180)
    turtle.forward(25)


def move_down():
    turtle.setheading(270)
    turtle.forward(25)

turtle = Turtle()
screen = Screen()

screen.onkeypress(move_right, "Right")
screen.onkeypress(move_up, "Up")
screen.onkeypress(move_left, "Left")
screen.onkeypress(move_down, "Down")
screen.listen()
screen.exitonclick()

【问题讨论】:

    标签: python python-3.x turtle-graphics python-turtle


    【解决方案1】:

    花了一分钟才弄清楚。不知道为什么turtle.forward() 释放后会恢复到以前的位置。 Python 的 Turtle 模块有问题。它应该留在你放的地方,但无论出于何种原因,它都在冒泡。

    这会如你所愿。

    #! /usr/bin/python3
    
    from turtle import Turtle, Screen
    
    turtle = Turtle()
    screen = Screen()
    
    ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    def right():
        turtle.setx( turtle.pos()[0] +25 )
    
    def up():
        turtle.sety( turtle.pos()[1] +25 )
    
    def left():
        turtle.setx( turtle.pos()[0] -25 )
    
    def down():
        turtle.sety( turtle.pos()[1] -25 )
    
    screen.onkeypress( right, "Right")
    screen.onkeypress( up, "Up")
    screen.onkeypress( left, "Left")
    screen.onkeypress( down, "Down")
    
    screen.listen()
    screen.exitonclick()
    
    ##  eof  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    

    编辑:哦,是 setheading() 函数重复导致挂断。
    首先测试海龟的航向,然后仅在需要时设置它。

    #! /usr/bin/python3
    
    from turtle import Turtle, Screen
    
    turtle = Turtle()
    screen = Screen()
    
    ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    def right():
        if turtle.heading() != 0:  turtle.setheading(0)
        turtle.forward(25)
    
    def up():
        if turtle.heading() != 90:  turtle.setheading(90)
        turtle.forward(25)
    
    def left():
        if turtle.heading() != 180:  turtle.setheading(180)
        turtle.forward(25)
    
    def down():
        if turtle.heading() != 270:  turtle.setheading(270)
        turtle.forward(25)
    
    screen.onkeypress( right, "Right")
    screen.onkeypress( up, "Up")
    screen.onkeypress( left, "Left")
    screen.onkeypress( down, "Down")
    
    screen.listen()
    screen.exitonclick()
    
    ##  eof  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    

    【讨论】:

    • 在使用您建议的代码时,有时我仍然会遇到这个问题。但是,它不像以前那样经常发生。当我按住键超过 2 秒时,尤其会发生这种情况。至少它比我的有所改进。使用 setx() 和 sety() 方法的代码的第一个版本比第二个版本执行得更好。顺便说一句,它解决了在我释放键之前不绘制线的问题。
    【解决方案2】:

    您可以通过将screen.tracer() 方法设置为0 来使用它。这样,您还需要在每次海龟移动时更新屏幕:

    from turtle import Turtle, Screen
    
    def move_right():
        turtle.setheading(0)
        turtle.forward(25)
        screen.update()
    
    def move_up():
        turtle.setheading(90)
        turtle.forward(25)
        screen.update()
    
    def move_left():
        turtle.setheading(180)
        turtle.forward(25)
        screen.update()
    
    def move_down():
        turtle.setheading(270)
        turtle.forward(25)
        screen.update()
    
    turtle = Turtle()
    screen = Screen()
    screen.tracer(0)
    screen.onkeypress(move_right, "Right")
    screen.onkeypress(move_up, "Up")
    screen.onkeypress(move_left, "Left")
    screen.onkeypress(move_down, "Down")
    
    screen.listen()
    screen.exitonclick()
    

    您还可以使用lambda 函数来缩短您的代码:

    from turtle import Turtle, Screen
    
    def f(num):
        turtle.setheading(num)
        turtle.forward(25)
        screen.Screen.update()
    
    turtle = Turtle()
    screen = Screen()
    screen.tracer(0)
    screen.onkeypress(lambda: f(0), "Right")
    screen.onkeypress(lambda: f(90), "Up")
    screen.onkeypress(lambda: f(180), "Left")
    screen.onkeypress(lambda: f(270), "Down")
    
    screen.listen()
    screen.exitonclick()
    

    请注意,将Turtle 对象命名为turtle 并不是最佳选择,因为它可能会与turtle 模块混淆。

    【讨论】:

    • 您的回答完美。感谢您提出改进代码的建议。我遇到了一种解决此问题的方法,方法是在进入函数时删除键绑定并在退出函数时重新绑定键。但是您的解决方案使乌龟移动更顺畅,我猜不断地取消绑定和重新绑定关键事件效率不高。