【问题标题】:How to check if two objects touch each other in python tkinter?如何在python tkinter中检查两个对象是否相互接触?
【发布时间】:2020-03-01 10:17:44
【问题描述】:

我正在尝试创建一个函数,告诉我两个画布对象(在我的代码中,rec 和 block)是否在 Tkinter 中相互接触。我试图用他们的坐标信息来做到这一点,但它似乎不起作用。你能帮帮我吗?

该函数将用于我在下面的代码中创建的snake,所以不要问我为什么代码这么长。

函数在第119行,same_poz

这是我的代码:

from tkinter import *
import time
import random
import threading

root = Tk()
root.title('Snake')
x, y = 484, 484
recX, recY = x // 2, y // 2
recW, recH = recX + 22, recY + 22
randoms = []
for i in range(484):
    if i % 11 == 0:
        randoms.append(i)
blockX, blockY = random.choice(randoms), random.choice(randoms)
blockW, blockH = blockX + 22, blockY + 22
c = Canvas(root, bg='black', width=x, height=y)
c.pack()



class Snake(threading.Thread):
    def __init__(self, c, x, y, recX, recY, recW, recH, blockX, blockY, blockW, blockH):
        super(Snake, self).__init__()
        self.c = c
        self.x = x
        self.y = y
        self.recX = recX
        self.recY = recY
        self.recW = recW
        self.recH = recH
        self.blockW = blockW
        self.blockH = blockH
        self.rec = c.create_rectangle(recX, recY, recW, recH, fill='red', outline='white')
        self.blockX = blockX
        self.blockY = blockY
        self.block = c.create_rectangle(blockX, blockY, blockW, blockH, fill='green', 
        outline='white')
        self.moving_right = False
        self.moving_left = False
        self.moving_up = False
        self.moving_down = False
        self.moving = False

    def movingright(self):
        self.moving_right = True
        self.moving_left = False
        self.moving_up = False
        self.moving_down = False
        self.moving = True
        c.move(self.rec, 11, 0)
        self.after4 = root.after(150, self.movingright)

    def movingleft(self):
        self.moving_left = True
        self.moving_left = False
        self.moving_up = False
        self.moving_down = False
        self.moving = True
        c.move(self.rec, -11, 0)
        self.after3 = root.after(150, self.movingleft)

    def movingup(self):
        self.moving_up = True
        self.moving_right = False
        self.moving_left = False
        self.moving_up = False
        self.moving = True
        c.move(self.rec, 0, -11)
        self.after = root.after(150, self.movingup)

    def movingdown(self):
        self.moving_down = True
        self.moving_right = False
        self.moving_left = False
        self.moving_down = False
        self.moving = True
        c.move(self.rec, 0, 11)
        self.after2 = root.after(150, self.movingdown)

    def stop(self):
        self.moving_right = False
        self.moving_left = False
        self.moving_up = False
        self.moving_down = False
        self.moving = False

        try:
            root.after_cancel(self.after)
        except AttributeError:
            pass
        try:
            root.after_cancel(self.after2)
        except AttributeError:
            pass
        try:
            root.after_cancel(self.after3)
        except AttributeError:
            pass
        try:
            root.after_cancel(self.after4)
        except AttributeError:
            pass

    def move(self, n):
        if n.keysym == 'Up':
            self.stop()
            self.movingup()
        if n.keysym == 'Down':
            self.stop()
            self.movingdown()
        if n.keysym == 'Right':
            self.stop()
            self.movingright()
        if n.keysym == 'Left':
            self.stop()
            self.movingleft()

    def same_poz(self):
        if self.blockY == self.recY:
            self.helpY = random.randint(10, self.y - self.blockY)
            self.c.move(self.block, 0, self.helpY)
        if self.blockX == self.recY:
            self.helpX = random.randint(10, self.x - self.blockX)
            self.c.move(self.block, 0, self.helpX)
        if self.blockW == self.recW:
            self.helpW = random.randint(10, self.x - self.blockW)
            self.c.move(self.block, 0, self.helpW)
        if self.blockH == self.recH:
            self.helpH = random.randint(10, self.y - self.blockH)
            self.c.move(self.block, 0, helpH)



cube = Snake(c, x, y, recX, recY, recW, recH, blockX, blockY, blockW, blockH)
cube.start()




cube.c.bind_all('<Key>', cube.move, cube.stop)
cube.c.bind_all('<Key>', cube.moving_left, cube.moving_right)
cube.c.bind_all('<Key', cube.moving_up, cube.moving_down)
cube.c.bind(cube.same_poz)
root.mainloop()

【问题讨论】:

    标签: python-3.x multithreading canvas tkinter collision


    【解决方案1】:

    您提供的代码存在太多问题。当您仍然缺乏 Python 的基础知识时,我不知道您为什么要使用 Tkinter 进行编程。 (不要刻薄)

    1. 我不知道你为什么决定继承 threading.Thread 的时候 你对Thread 提供的任何东西都没有任何用处 类。
    2. 您根本不用的实例参数太多,每次都必须更改的实例参数太多。
    3. 不使用elif,而是不断使用if
    4. 如果您使用线程来处理主循环之外的 Tkinter 更改,则无需使用 .after,因为它基本上就是这样做的。
    5. Tkinter 对每个键都有专用的绑定,包括键的组合。无需捕捉每一个关键事件。
    6. 如果您正在使用单个脚本,请使用if __name__ == '__main__': 进行测试。
    7. Tkinter 上的一些阅读材料 - http://effbot.org/tkinterbook/

    这是对代码的最小修改,它正在工作。

    import time
    import random
    import threading
    from tkinter import *
    
    MOVINGUP = 'u'
    MOVINGDOWN = 'd'
    MOVINGLEFT = 'l'
    MOVINGRIGHT = 'r'
    NOTMOVING = '0'
    
    
    class Snake:
        def __init__(self, root, recX, recY, recW, recH, blockX, blockY, blockW, blockH):
            self.root = root
    
            self.c = Canvas(root, bg='black', width=x, height=y)
            self.c.pack()
    
            self.rec = self.c.create_rectangle(recX, recY, recW, recH, fill='red', outline='white')
            self.block = self.c.create_rectangle(blockX, blockY, blockW, blockH, fill='green', outline='white')
    
            self.direction = NOTMOVING
    
            self.root.bind('<Up>', lambda e: self.moveset(MOVINGUP))
            self.root.bind('<Down>', lambda e: self.moveset(MOVINGDOWN))
            self.root.bind('<Left>', lambda e: self.moveset(MOVINGLEFT))
            self.root.bind('<Right>', lambda e: self.moveset(MOVINGRIGHT))
    
        def moveset(self, direction):
            self.direction = direction
    
        def movement(self):
            if self.direction == MOVINGUP:
                self.c.move(self.rec, 0, -11)
            elif self.direction == MOVINGDOWN:
                self.c.move(self.rec, 0, 11)
            elif self.direction == MOVINGLEFT:
                self.c.move(self.rec, -11, 0)
            elif self.direction == MOVINGRIGHT:
                self.c.move(self.rec, 11, 0)
            self.same_poz()
    
        def run(self):
            while True:
                time.sleep(0.15)
                self.movement()
    
        def same_poz(self):
            # Snake (x0, y0, x1, y1)
            snakepos = self.c.bbox(self.rec)
            # Food block (x0, y0, x1, y1)
            food = self.c.bbox(self.block)
            # If direction matters, if not then possible to only use self.hit in a single condition.
            if self.direction == MOVINGRIGHT and self.hit(snakepos, food):
                print('Caught the food moving right.')
            elif self.direction == MOVINGLEFT and self.hit(snakepos, food):
                print('Caught the food moving left.')
            elif self.direction == MOVINGUP and self.hit(snakepos, food):
                print('Caught the food moving up.')
            elif self.direction == MOVINGDOWN and self.hit(snakepos, food):
                print('Caught the food moving down.')
    
        def hit(self, snakepos, food):
            """
                Recieves coordinates of food block and snake block and returns if they collide.
            :param snakepos: Tuple containing (x0, y0, x1, y1) of the snake.
            :param food: Tuple containing (x0, y0, x1, y1) of the food block.
            :return: Boolean whether they collide
            """
            snakex = (snakepos[0], snakepos[2])
            snakey = (snakepos[1], snakepos[3])
            foodx = (food[0], food[2])
            foody = (food[1], food[3])
            # Returns True if any of the snake x cooridnates are between the food x coordinates, or both x coordinates match.
            if any((foodx[0] < xcoord < foodx[1] for xcoord in snakex)) or foodx == snakex:
                # Returns True if any of the snake y cooridnates are between the food y coordinates, or both y coordinates match.
                return any((foody[0] < ycoord < foody[1] for ycoord in snakey)) or foody == snakey
            return False
    
    
    if __name__ == '__main__':
        root = Tk()
        root.title('Snake')
        x, y = 484, 484
        recX, recY = x // 2, y // 2
        recW, recH = recX + 22, recY + 22
        randoms = []
        for i in range(484):
            if i % 11 == 0:
                randoms.append(i)
        blockX, blockY = random.choice(randoms), random.choice(randoms)
        blockW, blockH = blockX + 22, blockY + 22
    
    
        snake = Snake(root, recX, recY, recW, recH, blockX, blockY, blockW, blockH)
        threading.Thread(target=snake.run, daemon=True).start()
    
        root.mainloop()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-06
      • 2023-03-07
      • 2012-06-23
      • 2016-06-27
      相关资源
      最近更新 更多