You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Tkinter中检测碰撞后删除单个食物椭圆对象

Tkinter碰撞检测失效问题:玩家触碰食物无法删除单个食物

我用Tkinter编写了一段代码,可通过A、D键控制Label组件(玩家)左右移动,希望实现玩家与Canvas绘制的oval(食物)坐标重合时,仅删除被触碰的单个食物对象,但当前碰撞检测逻辑未生效。

原代码

from tkinter import *
food_cords= []

wind = Tk()
wind.geometry("1600x850")
canvas = Canvas(wind,width = 1600,height=850)
canvaswide = [1600,850]
canvas.pack()
canvas.create_line(0,700,1600,700,fill = "black",width = 5,tag="line")

def move_right(event):
    label.place(x=label.winfo_x() + 10, y=label.winfo_y())
    x1 = label.winfo_x()
    print(x1)
    wind.update()
    if 1600 == x1:
       wind.bind("<d>", move_left) == wind.bind("<d>", nothing())

def move_left(event):
    label.place(x=label.winfo_x() - 10, y=label.winfo_y())
    x1 = label.winfo_x()
    print(x1)
wind.update()
if 0 == x1:
    wind.bind("<a>", move_left) ==  wind.bind("<a>", nothing)

def nothing(event):
    pass

wind.bind("<d>",move_right)
wind.bind("<a>",move_left)
bg = PhotoImage(file="python2.png")
mybg = canvas.create_image(0,-580,image=bg,anchor=NW)
label = Label(wind, image=bg)
label.place(x=0, y=580)
#y1 = label.winfo_y()

class Food():
    y = food_cords[0] + 20
    x = food_cords[1] - 40
    global label
    #global food_cords

    if cords == line_coordinates:
        for index in food_cords:
            if index == food_cords[0]:
                y = index + 20


                while food_cords[1] > 0:
                    x = food_cords[1] - 40
                    food_cords[1] = food_cords[1] - 100

                    oval = canvas.create_oval(0, 0, 30, 30, fill="yellow",tag="foood")
                    canvas.moveto(oval, x=x, y=y)
                    print(2312321313)
                    print(x)
                    print(label.winfo_x())
                    print(y)
                    print(label.winfo_y())
                    if x == label.winfo_x() and y == label.winfo_y:
                        print(1313123454565675643)
                        canvas.delete(oval)
                        wind.update()

                    canvas.pack()

food = Food()
wind.mainloop()

问题分析

  1. Food类逻辑完全失效:

    • food_cords是空列表,直接取food_cords[0]会引发索引错误,且类属性初始化方式错误
    • cords和line_coordinates未定义,导致食物创建的if条件永远不成立,根本没有食物被生成
    • 碰撞检测仅在食物创建时执行一次,玩家移动后不会重新检查碰撞
    • label.winfo_y少了括号,错误地将方法对象与数值比较,永远不会触发删除
  2. 移动边界控制逻辑错误:

    • 用==判断绑定事件是无效操作,且nothing()直接调用函数,应该传入函数名
    • move_left函数外的边界判断代码永远不会执行,因为x1是函数内的局部变量

修复后的代码

from tkinter import *

wind = Tk()
wind.geometry("1600x850")
canvas = Canvas(wind, width=1600, height=850)
canvas.pack()
# 绘制地面线
canvas.create_line(0, 700, 1600, 700, fill="black", width=5, tag="line")

# 存储所有食物的ID和坐标
food_list = []

def move_right(event):
    new_x = label.winfo_x() + 10
    # 限制玩家不超出右边界
    if new_x <= 1600 - label.winfo_width():
        label.place(x=new_x, y=label.winfo_y())
    check_collision()

def move_left(event):
    new_x = label.winfo_x() - 10
    # 限制玩家不超出左边界
    if new_x >= 0:
        label.place(x=new_x, y=label.winfo_y())
    check_collision()

def nothing(event):
    pass

# 碰撞检测函数:每次移动后检查所有食物
def check_collision():
    player_x = label.winfo_x()
    player_y = label.winfo_y()
    player_width = label.winfo_width()
    player_height = label.winfo_height()
    
    # 倒序遍历,避免删除元素后索引混乱
    for idx in reversed(range(len(food_list))):
        food_id, food_x, food_y = food_list[idx]
        # 判断玩家与食物是否重叠(考虑玩家和食物的尺寸)
        if (player_x < food_x + 30 and 
            player_x + player_width > food_x and 
            player_y < food_y + 30 and 
            player_y + player_height > food_y):
            canvas.delete(food_id)
            del food_list[idx]

# 初始化玩家
bg = PhotoImage(file="python2.png")
label = Label(wind, image=bg)
label.place(x=0, y=580)

# 生成食物:在地面线上方生成一排黄色食物
class Food():
    def __init__(self):
        # 从右往左生成,间隔100像素
        start_x = 1500
        while start_x > 0:
            food_y = 700 - 50  # 地面线上方50像素
            oval = canvas.create_oval(start_x, food_y, start_x+30, food_y+30, fill="yellow")
            food_list.append((oval, start_x, food_y))
            start_x -= 100

food = Food()

# 绑定按键事件
wind.bind("<d>", move_right)
wind.bind("<a>", move_left)

wind.mainloop()

关键改动说明

  • 用food_list存储每个食物的ID和坐标,方便后续碰撞检测和删除
  • 将碰撞检测独立成check_collision函数,每次玩家移动后调用,实时检查碰撞
  • 修复边界控制逻辑,直接限制玩家移动范围,避免无效的事件绑定操作
  • 改进碰撞检测逻辑,考虑玩家和食物的实际尺寸(不再用严格坐标相等,而是判断矩形重叠)
  • 重构Food类的初始化逻辑,正确生成一排食物

内容的提问来源于stack exchange,提问作者coder34321553667

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 10:53:20