Reputation: 13
I'm trying to make this oval move fluidly on this canvas using tkinter, but despite having a fixed speed, it seems to accelerate the more I move it. Even when debugging I've noticed that my speed variables do not increase above the desired values. I can't manage to identify what is causing this acceleration, can someone please point out what's going on?
Here's my code:
from tkinter import*
window = Tk()
canvas = Canvas(window, width = 300, height = 300, bg ='white')
canvas.focus_set()
speedx = 0
speedy = 0
speed = 1
x1=40
y1=40
oval=canvas.create_oval(x1-10,y1-10,x1+10,y1+10,width=2,fill='orange')
def key_press(event):
global x1, y1
global speedx, speedy, speed
button = event.keysym
if button == 'Up':
speedx = 0
speedy = -speed
elif button == 'Down':
speedx = 0
speedy = speed
elif button == 'Right':
speedx = speed
speedy = 0
elif button == 'Left':
speedx = -speed
speedy = 0
move()
def move():
global x1,y1
global oval
global speedx, speedy
x1 += speedx
y1 += speedy
canvas.delete(oval)
oval = canvas.create_oval(x1+10,y1-10,x1-10,y1+10,width=2,fill='orange')
window.after(10, move)
def key_release(event):
global speedx, speedy
speedx = 0
speedy = 0
canvas.bind('<KeyPress>', key_press)
canvas.bind("<KeyRelease>", key_release)
canvas.pack(padx =5, pady =5)
window.mainloop()
Upvotes: 1
Views: 166
Reputation: 10572
The problem is that you call window.after(10, move)
from within your move
function without ever cancelling it again. This generates a never ending loop of calls to move
for every <KeyPress>
event.
What you could do is to save the after
call to a variable. With this you can make sure that move
isn't called again from outside this loop, plus you can use it to cancel the after
call on the key's release:
from tkinter import *
window = Tk()
canvas = Canvas(window, width = 300, height = 300, bg ='white')
canvas.focus_set()
speedx = 0
speedy = 0
speed = 1
# Make variable to store after call object
after_obj = None
x1=40
y1=40
oval=canvas.create_oval(x1-10,y1-10,x1+10,y1+10,width=2,fill='orange')
def key_press(event):
global x1, y1
global speedx, speedy, speed
global after_obj
button = event.keysym
if button == 'Up':
speedx = 0
speedy = -speed
elif button == 'Down':
speedx = 0
speedy = speed
elif button == 'Right':
speedx = speed
speedy = 0
elif button == 'Left':
speedx = -speed
speedy = 0
# Only call move from here if there is no after scheduled
if after_obj is None:
move()
def move():
global x1,y1
global oval
global speedx, speedy
global after_obj
x1 += speedx
y1 += speedy
canvas.delete(oval)
oval = canvas.create_oval(x1+10,y1-10,x1-10,y1+10,width=2,fill='orange')
# Save the after call object
after_obj = window.after(10, move)
def key_release(event):
global speedx, speedy
global after_obj
# When pressing multiple buttons at the same time you can get a key release without an after_obj, so check if it exists then cancel it
if after_obj:
window.after_cancel(after_obj)
# Reset after_obj to None so move can be called from key_press again
after_obj = None
speedx = 0
speedy = 0
canvas.bind('<KeyPress>', key_press)
canvas.bind("<KeyRelease>", key_release)
canvas.pack(padx =5, pady =5)
window.mainloop()
Upvotes: 1