简体   繁体   中英

Tkinter Python: Moving Multiple widget objects at once with OOP?

I am a python beginner working on creating a 2048 game with Tkinter. So far, I have been working on getting multiple tiles to have the same movement, following the same general behavior. In order to do this, I have defined a class, Tile, that defines how each tile can move. The idea is that I can add several tile objects, and they would all move in unison, just as in 2048. However, the issue is that each tile on the Tkinter Canvas is moving at random whenever I hit an arrow key. If I kit the "" arrow key three times, it would move three tiles individually, randomly choosing the next tile to move.

How could I fix this, allowing a single press of an arrow key to move all the tiles on the canvas?

Here is the canvas I defined:

from tkinter import * 
from tkinter.ttk import *

root = Tk()

w = 300
h = 300
my_canvas = Canvas(root, width=w, height=h, bg="white")

And below this code, I defined my class, such that is adds a rectangle to the canvas and defines movement in four directions

class Tile:
    def __init__(self, starting_x, starting_y):
        self.root = root
        self.x = 0
        self.y = 0
        self.starting_y = starting_y
        self.starting_x = starting_x
    self.tile = my_canvas.create_rectangle(starting_x, starting_y, starting_x + 25, starting_y + 25,fill="black")
    my_canvas.pack()



    self.movement()

def movement(self):
    root.bind("<Left>", self.left)
    root.bind("<Right>", self.right)
    root.bind("<Up>", self.up)
    root.bind("<Down>", self.down)

    my_canvas.move(self.tile, self.x, self.y)
    

    self.coordinates = []
    self.coordinates = my_canvas.coords(self.tile)
    if self.coordinates[0] == 0: self.x = 0
    if self.coordinates[2] == w: self.x = 0
    if self.coordinates[1] == 0: self.y = 0
    if self.coordinates[3] == h: self.y = 0
    my_canvas.after(1, self.movement)

def left(self, e):
    self.x = -1
    self.y = 0
    if self.coordinates[0] == 0:
        self.x = 0
        self.y = 0
def right(self, e):
    self.x = 1
    self.y = 0
    if self.coordinates[2] == w:
        self.x = 0
        self.y = 0
def up(self, e):
    self.x = 0
    self.y = -1
    if self.coordinates[1] == 0:
        self.x = 0
        self.y = 0
def down(self, e):
    self.x = 0
    self.y = 1
    if self.coordinates[3] == h:
        self.x = 0
        self.y = 0

Finally, here is when I create three Tile objects, followed by root.mainloop():

if __name__ == "__main__":
    tile1 = Tile(0,0)
    tile2 = Tile(50,50)
    tile3 = Tile(100,100)

root.mainloop()

As you can see, all three tiles are outputted, but they do not move in unison

看截图

Thanks in advance for the help!

The problem is, that the command my_canvas.move(self.tile, self.x, self.y) in movement does not know what tile to move. In order for this program to work, you will have to keep a collection of tiles that is accessible from the movement() function.

Specifically, I would suggest to create a global list of tiles that have the capacity to move in themselves and also know exactly what canvas they are on:

class Tile:
    def __init__(self, canv, starting_x, starting_y):
        self.root = root
        self.canvas = canv
        self.x = 0
        self.y = 0
        self.starting_y = starting_y
        self.starting_x = starting_x
        self.idx = canv.create_rectangle(starting_x, starting_y, starting_x + 25, starting_y + 25,fill="black")
        canv.update()

    def moveleft(self): ## Add more methods for other movements
        if self.starting_x>25:
            self.starting_x -= 25
            self.canvas.move(self.idx,self.starting_x,self.starting_y)    

Then, you can create the widget and a list of Tile objects that may move on the canvas. Spcify the bindings right at the beginning and not inside a function.

root = Tk()
w = 300
h = 300
my_canvas = Canvas(root, width=w, height=h, bg="white")
root.bind("<Left>", left)
root.bind("<Right>", right)
root.bind("<Up>", up)
root.bind("<Down>", down)


global tilelist
tilelist = []
tilelist.append(Tile(my_canvas,0,0))
tilelist.append(Tile(my_canvas,50,50))
tilelist.append(Tile(my_canvas,100,100))

You now have a list of movable tiles in a global list. Each tile is able to move in all four directions (if you completed the class). Now you just need a movement function that moves all of them:

def left():
    global tilelist
    for t in tilelist:
        t.moveleft()

This will move all your tiles.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM