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

如何让物体基于形状边缘而非中心实现碰壁反弹?

实现小球基于边缘的屏幕反弹

你的问题出在两个核心点:一是依赖pygame.draw.circle返回的旧Rect对象判断碰撞,但半径变化后这个Rect不会自动更新,导致边界判断始终基于初始半径;二是你尝试的边界判断逻辑有误,正确的边缘碰撞应该用球的实际边缘位置(中心±半径)来和屏幕边界对比。

下面是修改后的完整代码,核心改动是自己维护球的中心坐标,每次计算实时边缘位置来判断碰撞:

import pygame
# 初始化游戏
pygame.init()

# 定义屏幕尺寸
width = 500
height = 500
screen_res = (width, height)

pygame.display.set_caption("bouncingball")
screen = pygame.display.set_mode(screen_res)
black = (0, 0, 0)

# 定义球的属性
Rad = 10
maxRadius = 250
color = [(255,0,0), (255,127,0), (255,255,0), (0,255,0), (0,0,255), (75, 0, 130), (128,0,211)]
i = 0

# 自己维护球的中心坐标,替代依赖Rect的方式
center_x, center_y = 250, 250

# 定义速度
speed = [0, 1]
speedMultipler = -1.01

# 游戏循环
while True:
    # 事件处理
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()

    # 填充背景
    screen.fill(black)

    # 更新球的位置
    center_x += speed[0]
    center_y += speed[1]

    # 计算球的实时边缘位置
    left_edge = center_x - Rad
    right_edge = center_x + Rad
    top_edge = center_y - Rad
    bottom_edge = center_y + Rad

    if Rad >= maxRadius:
        # 水平方向碰撞判断
        if left_edge <= 0 or right_edge >= width:
            # 修正位置,避免球卡在边界外
            if left_edge <= 0:
                center_x = Rad
            else:
                center_x = width - Rad
            
            # 更新速度和颜色
            if abs(speed[0]) > 70:
                speed[0] = -speed[0]
            else:
                speed[0] *= speedMultipler
            i = (i + 1) % len(color)
        
        # 垂直方向碰撞判断
        if top_edge <= 0 or bottom_edge >= height:
            # 修正位置
            if top_edge <= 0:
                center_y = Rad
            else:
                center_y = height - Rad
            
            # 更新速度和颜色
            if abs(speed[1]) > 70:
                speed[1] = -speed[1]
            else:
                speed[1] *= speedMultipler
            i = (i + 1) % len(color)
    else:
        # 水平方向碰撞判断(未到最大半径)
        if left_edge <= 0 or right_edge >= width:
            # 修正位置
            if left_edge <= 0:
                center_x = Rad
            else:
                center_x = width - Rad
            
            speed[0] *= speedMultipler
            Rad *= 1.05
            i = (i + 1) % len(color)
        
        # 垂直方向碰撞判断(未到最大半径)
        if top_edge <= 0 or bottom_edge >= height:
            # 修正位置
            if top_edge <= 0:
                center_y = Rad
            else:
                center_y = height - Rad
            
            speed[1] *= speedMultipler
            Rad *= 1.05
            i = (i + 1) % len(color)

    # 绘制当前球
    pygame.draw.circle(surface=screen, color=color[i],
                       center=(center_x, center_y), radius=Rad)
    
    # 更新屏幕
    pygame.display.flip()

关键改动说明:

  • 放弃依赖Rect对象:原来的ball_obj是绘制时返回的Rect,半径变化后它的边界不会同步更新,改为自己维护center_x和center_y,确保位置和半径始终匹配。
  • 实时计算边缘位置:每次循环都用center_x ± Rad、center_y ± Rad计算球的实际边缘,判断碰撞时完全基于当前球的大小。
  • 碰撞后修正位置:检测到碰撞时,把球的中心修正到刚好贴住边界的位置(比如左碰后center_x = Rad),避免球因速度过大穿过边界或卡在边界外。
  • 简化颜色切换逻辑:用i = (i + 1) % len(color)替代原来的条件判断,更简洁且不易出错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 10:54:51