I'm working on a toy project to learn the basics of tkinter.
I have a Drone class with position and velocity in np.array
objects, that updates itself every delta.
The positions are floats between 0 and 1 , then multiplied by the height/width.
I now want to see this Drone to move across the screen, so I used the window.after()
and window.update()
methods.
This is the code I wrote :
import tkinter as tk
import numpy as np
def update_drone(canv, drone):
# update the coords of all the polygon objects with new position (scaled to screen dimensions)
canv.coords(canv.find_withtag("drone"), *([WIDTH, HEIGHT] * drone.position))
def game_loop(window, canvas, dr):
delta = 0.01
# function which updates drone's attributes
dr.update(delta)
# built in sleep
sleep(delta)
#update drone function from above
update_drone(canvas, dr)
canvas.pack()
# if the drone isnt below the screen, call the game loop next delta
if dr.position[1] < 1:
window.after(int(delta * 1000), game_loop, window, canvas, dr)
if __name__ == "__main__":
# set up window
window = tk.Tk()
window.maxsize(WIDTH, HEIGHT)
window.minsize(WIDTH, HEIGHT)
window.configure(bg="black")
# height and width are global variables i define
canvas = tk.Canvas(window, bg="black", height=HEIGHT, width=WIDTH)
# create Drone object
dr = Drone()
# call draw drone function which is defined below
draw_drone(canvas, dr)
window.after(0, game_loop, window, canvas, dr)
# main loop
window.mainloop()
The draw_drone
function I call above initializes two polygons :
def draw_drone(canv: tk.Canvas, drone: Drone) -> None:
pos_x, pos_y = WIDTH * drone.position[0], HEIGHT * drone.position[1]
# draw drone body
size = 20
canv.create_polygon(
[
pos_x - size,
pos_y - size,
pos_x - size,
pos_y size,
pos_x size,
pos_y size,
pos_x size,
pos_y - size,
],
outline="white",
fill="yellow",
width=3,
tags="drone",
)
canv.create_polygon(
[
pos_x,
pos_y 0.8 * size,
pos_x - 0.8 * size,
pos_y,
pos_x,
pos_y - 0.8 * size,
pos_x 0.8 * size,
pos_y,
],
outline="red",
fill="grey",
width=8,
tags="drone",
)
When I run the above code, the game loop is called (when I print out the values of the drone's position they are indeed updated accordingly) but the canvas is frozen on the first frame and never updates.
If anyone could give me an indication of what the problem is I would be very grateful !
EDIT :
Here is the rudimentary drone class I use:
class Drone:
def __init__(self):
self.position = np.array([0.5, 0.5])
self.velocity = np.array([0, 0])
self.forces = np.array([0, 0])
def update(self, dt):
self.velocity = dt * (self.forces np.array([0, 1])) # forces gravity
self.position = self.velocity * dt
CodePudding user response:
In the end my mistake was quite simple. I did not understand how canvas.coords
really worked. The correct code for my update_drone
function is actually :
for t in canvas.find_withtag("drone"):
canv.coords(t, *([WIDTH, HEIGHT] * drone.position))
instead of
canv.coords(canv.find_withtag("drone"), *([WIDTH, HEIGHT] * drone.position))
This correctly updates the coordinates.