如何在 python tkinter 中检查两个对象是否相互接触?

How to check if two objects touch each other in python tkinter?

我正在尝试创建一个函数,告诉我两个 canvas 对象(在我的代码中,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 的基础知识时使用 Tkinter 进行编程。 (不想听起来刺耳)

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