Search code examples
pythonpython-3.xturtle-graphicspython-turtle

Python-Turtle - Moving the turtle by holding down a key: releasing the key moves the turtle back instead of stopping it


I'm writing a program that moves the turtle in different directions by pressing down the arrow keys. I want the ability to move it in a particular direction by holding down the respective arrow key instead of pressing it repeatedly. However, when I release the arrow key after holding it down for few seconds, the turtle is moving back a bit instead of stopping immediately. The amount by which it moves back depends on how long I held down the key to move it.

Can you help me to solve this issue or suggest another way to implement this with the turtle module?

Note: I observed that when I hold down the key, the line is not drawn until I release it. I'm not sure if it's expected or related to this issue.

Note 2: I'm using the onkeypress method for handling the "holding down the key" event. I tried using the onkeyrelease(None, arrow_key) method to solve this, but it doesn't work either.

Here is my code:

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()

Solution

  • You can use the screen.tracer() method by setting it to 0. With that you'll also need to update the screen every time the turtle makes a move:

    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()
    

    You can also use lambda functions to shorten your code:

    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()
    

    Do note that it's not optimal to name your Turtle object turtle, as it can be confused as the turtle module.