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

如何在Tkinter中实现两个小球的碰撞检测与相互反弹效果?

问题原因

你原有代码中两球碰撞的判定逻辑错误:仅判断x或y坐标完全相等,该条件触发概率极低,同时没有考虑小球的实际尺寸,不符合圆形物体的碰撞判定规则。

修复步骤
  • 首先删除4个边界反弹判断中错误的碰撞触发条件,也就是所有or x == x1、or y == y1、or x1 == x、or y1 == y的冗余逻辑
  • 新增独立的两球碰撞判定:计算两个小球的圆心坐标,当圆心距离小于等于两球半径之和(即小球直径)时判定为碰撞
  • 碰撞后直接交换两个小球的x、y方向速度即可实现弹性反弹(两球大小、质量一致时该逻辑成立,若要更精准的角度反弹可按碰撞法线计算速度分量)
修复后完整代码
from tkinter import *

# dimensions of canvas
WIDTH=300
HEIGHT=400

# Create window and canvas
window = Tk()
canvas = Canvas(window, width=WIDTH, height=HEIGHT, bg='#ADF6BE')
canvas.pack()

# starting position of ball
x = 0
y = 10
# starting position of ball1
x1 = 100
y1 = 0

# distance moved each time step for ball 1
dx = 10
dy= 10
# distance moved each time step for ball 2
dx1 = 10
dy1 = 10

# diameter of ball
ballsize = 30


while True:
    x = x + dx
    y = y + dy
    x1 = x1 + dx1
    y1 = y1 + dy1

    # 边界反弹判断,删除了错误的碰撞触发条件
    if x >= WIDTH-ballsize or x <= 0:
        dx = -dx
        print("x=", x)
        print('y=', y)
    if y >= HEIGHT-ballsize or y <= 0:
        dy = -dy
        print("x=", x)
        print('y=', y)

    if x1 >= WIDTH-ballsize or x1 <= 0:
        dx1 = -dx1
        print("x1=", x1)
        print('y1=', y1)
    if y1 >= HEIGHT-ballsize or y1 <= 0:
        dy1 = -dy1
        print("x1=", x1)
        print('y1=', y1)
    
    # 新增两球碰撞判断
    cx = x + ballsize / 2
    cy = y + ballsize / 2
    cx1 = x1 + ballsize / 2
    cy1 = y1 + ballsize / 2
    distance_sq = (cx - cx1)**2 + (cy - cy1)**2
    if distance_sq <= ballsize ** 2:
        # 交换速度实现反弹
        dx, dx1 = dx1, dx
        dy, dy1 = dy1, dy
        # 位置修正避免两球卡在一起
        overlap = ballsize - (distance_sq ** 0.5)
        x += dx * overlap / 10
        y += dy * overlap / 10
        x1 += dx1 * overlap / 10
        y1 += dy1 * overlap / 10

    # Create balls
    ball=canvas.create_oval(x, y, x+ballsize, y+ballsize, fill="white", outline='white')
    ball1 = canvas.create_oval(x1, y1, x1 + ballsize, y1 + ballsize, fill="white", outline='white')
    # display ball
    canvas.update()
    canvas.after(50)
    #remove ball
    canvas.delete(ball)
    canvas.delete(ball1)

window.mainloop()

内容的提问来源于stack exchange,提问作者Adam A.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 22:12:01