Turtle graphics – screen updates with tracer not working as expected

Question:

I’m trying to put in scheduled refreshes for a pong game, so the screen updates after a time interval so the paddles (which I have segmented) move in sync on the screen. What is the functional difference between these two blocks of code? I was trying to get the first one to work but wasn’t able to get it to do what I wanted but after some experimenting I landed at the second one which does:

pongscreen.tracer(0)

def balltiming():

    pongscreen.update()
    time.sleep(0.5)

    balltiming()


balltiming()
pongscreen.listen()
pongscreen.mainloop()

This second one works, but functionally they seem pretty much the same in what they’re doing. Why doesn’t the first one work but this does?

pongscreen.tracer(0)

def balltiming():

    pongscreen.update()
    pongscreen.ontimer(balltiming, 300)


balltiming()
pongscreen.listen()
pongscreen.mainloop()
Asked By: Dragnipur

||

Answers:

The first block is genuinely recursive, so it’ll blow the call stack after ~1000 frames on a typical CPython implementation.

The second block isn’t recursive; the initial balltiming function is completely cleared from the call stack after it sets an ontimer event. Turtle internally calls the next iteration of balltiming that has been registered as a callback to ontimer without unbounded stack growth.

If you want to use sleep manually, use a while loop rather than recursion. However, sleep blocks the thread and is less amenable to precise framerate control, so generally ontimer is used.

A consequence of the blocking recursive calls and sleep is that in the first code block, pongscreen.listen() and pongscreen.mainloop() won’t be reached, while in the second version, both will be reached and the main thread will block at pongscreen.mainloop(); the typical flow for a turtle program.

Answered By: ggorlen