cdlane has an awesome idea here of using ontimer
and a set of currently-pressed keys, but I thought I'd try to extend and refine it a bit.
The problem with a secondary loop with ontimer
is that it seems to fight the main turtle loop, both in terms of computation and also in terms of thread safety/interleaving, where you can begin iterating the key pressed set and find that a handler has pulled a key out during iteration, raising an error.
The (seemingly poorly-named) tracer(0)
function lets you disable turtle's loop so you can call it manually from within the hand-rolled ontimer
loop using update()
. This reduces some of the choppiness of the competing loops, although I imagine the timer resolution on rolling your own loop with repeated calls to ontimer
is less precise than the built-in loop. But I haven't really looked at the source yet -- feel free to leave a comment if you have any insight.
Here's the proof of concept:
from turtle import Screen, Turtle
def tick():
for action in keys_pressed:
actions[action]()
win.update()
win.ontimer(tick, frame_delay_ms)
t = Turtle()
win = Screen()
win.tracer(0)
frame_delay_ms = 1000 // 30
step_speed = 10
actions = dict(
Left=lambda: t.left(step_speed),
Right=lambda: t.right(step_speed),
Up=lambda: t.forward(step_speed),
)
keys_pressed = set()
def bind(key):
win.onkeypress(lambda: keys_pressed.add(key), key)
win.onkeyrelease(lambda: keys_pressed.remove(key), key)
for key in actions:
bind(key)
win.listen()
tick()
win.exitonclick()
Ultimately, though, if you want to go much further into realtime graphics and games, Pygame is better equipped.
cdlane has a few good posts on tracer
: 1, 2, 3.
key_up = True
andkey_right = True
and if you pressrigth
and you already havekey_up == True
then you have two keys combination. The same: if you pressup
and you already havekey_right == True
then you also have your combination.And remember to use onkeyrelease to set variablesFalse
– Curable