Home > other >  Python Tkinter : How do I get the canvas to update polygon coordinates every frame? [solved]
Python Tkinter : How do I get the canvas to update polygon coordinates every frame? [solved]

Time:12-22

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.

  • Related