Random walk on turtle graphics pause/resume function

Viewed 214

Rookie here! I modified a random walk assignment from an online course I'm taking, and I'm trying to make a function that will pause the program and when called again will resume it. It currently pauses, but I can't seem to make it resume; or to be precise, once it's paused I can't get any reaction - as if the screen stopped listening for events.

I already tried:

  • Creating a separate function for resume - The function works if I call it before I pause but after it pauses I can't call it
  • I could add an else clause for the if go condition where I declare a variable as screen.textinput and according the input the program will either resume or end, but I want it to be as simple as pausing.
  • I tried adding a screen.listen() call after the if go breaks as an else clause but it doesn't seem to work...
  • I tried setting go=False as default and then starting it by calling a function to set it to True, but that too doesn't work.

P.S: I'm new to programming so if you have further remarks and advice I'd truly appreciate it.

Thanks a lot!

attaching my code with comments in relevant lines:

from turtle import Turtle, colormode, Screen
from random import choice, randint

colormode(255)
tim = Turtle('circle')
tim.speed('fastest')
tim.width(10)
screen = Screen()
go = True  # Boolean to initialize line 31


def pause():  # Currently it pauses, but doesn't resume.
    """Pause the program by setting go to False, and resume it if it was paused"""
    global go
    if go:
        go = False
    else:
        go = True


def random_color():
    """Return a random color"""
    r = randint(0, 255)
    g = randint(0, 255)
    b = randint(0, 255)
    generated_color = (r, g, b)
    return generated_color


screen.listen()  # Starts listening for events
screen.onkey(fun=pause, key='p')  # Event - when the 'p' key is pressed, the 'pause' function is called.

while True:  # Outer loop to prevent the code from ending when 'go' is set to False by pressing 'p' the first time
    if go:  # As default is True, after pausing can't restart it...
        if 200 > tim.xcor() > -200 and 200 > tim.ycor() > -200:
            tim.color(random_color())
            tim.forward(choice(range(50)))
            tim.setheading(choice(range(360)))
        else:
            tim.goto(0, 0)
1 Answers

The problem is that, in your implementation, when go is False, there is no function running to get the keyboard events (since you are not running the main event loop). A non-elegant way of fixing it is to add a dummy action when go == False. Change your final loop to this:

while True:  # Outer loop to prevent the code from ending when 'go' is set to False by pressing 'p' the first time
    if go:  # As default is True, after pausing can't restart it...
        if 200 > tim.xcor() > -200 and 200 > tim.ycor() > -200:
            tim.color(random_color())
            tim.forward(choice(range(50)))
            tim.setheading(choice(range(360)))
        else:
            tim.goto(0, 0)
    else:
        tim.setheading(0)

And it will work.

Another (better) way of doing it is to use an event to move the turtle. In the variation below, I used the screen.ontimer method to call the move function after a given time. After every call of move, it reschedules itself to run after some time (in the example 50 ms). In this way, you always have an event loop running and receiving the keyboard events.

from turtle import Turtle, colormode, Screen
from random import choice, randint

colormode(255)
tim = Turtle('circle')
tim.speed('fastest')
tim.width(10)
screen = Screen()
go = True  # Boolean to initialize line 31


def pause():  # Currently it pauses, but doesn't resume.
    """Pause the program by setting go to False, and resume it if it was paused"""
    global go
    if go:
        go = False
    else:
        go = True


def random_color():
    """Return a random color"""
    r = randint(0, 255)
    g = randint(0, 255)
    b = randint(0, 255)
    generated_color = (r, g, b)
    return generated_color

def move():
    if go:  # As default is True, after pausing can't restart it...
        if 200 > tim.xcor() > -200 and 200 > tim.ycor() > -200:
            tim.color(random_color())
            tim.forward(choice(range(50)))
            tim.setheading(choice(range(360)))
        else:
            tim.goto(0, 0)
    screen.ontimer(fun=move, t=50)   # Move every 0.05 s

screen.listen()  # Starts listening for events
screen.onkey(fun=pause, key='p')  # Event - when the 'p' key is pressed, the 'pause' function is called.
screen.ontimer(fun=move, t=0)   # Schedule the first movement
screen.mainloop()
Related