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

pygame的event.get()中如何正确获取函数返回的碰撞状态?

问题根因

碰撞逻辑不生效是三个硬伤导致的,没有玄学问题:

  • 你只在按键按下的瞬间做了一次碰撞检测,按住按键持续移动的过程中,每帧更新坐标前完全没做碰撞校验
  • 每帧调用Extracted_Data算出来的碰撞结果根本没被用到,帧末不管有没有碰撞都会直接执行x += x_speed/y += y_speed位移,角色自然会穿进障碍区
  • 碰撞盒计算逻辑错位:玩家碰撞盒用屏幕固定位置减速度计算,没有对齐玩家实际的世界坐标,检测结果本身就有偏差
  • 把渲染逻辑和碰撞逻辑混写,全局变量乱传状态,很容易出现状态不同步的问题
修复方案

1. 重构碰撞检测函数

把碰撞检测和渲染拆开,函数只做纯逻辑判断,不要在里面画矩形、不要乱改全局变量,直接返回碰撞结果:

def check_collision(world_x, world_y, offset_x, offset_y):
    # 计算玩家下一帧位置对应的实际碰撞盒,对齐世界坐标
    player_hitbox = pygame.Rect(
        world_x + (screen_width - png_width/4)/2 + offset_x,
        world_y + (screen_height - png_height/8)/2 + offset_y,
        tile_size,
        3/4 * tile_size
    )
    # 遍历所有障碍块检测碰撞
    for row_index, row in enumerate(data):
        for col_index, val in enumerate(row):
            if val == 1025:
                boundary_rect = pygame.Rect(
                    world_x + col_index * tile_size,
                    world_y + row_index * tile_size,
                    tile_size,
                    tile_size
                )
                if player_hitbox.colliderect(boundary_rect):
                    return True
    return False

2. 调整主循环执行顺序

把碰撞检测挪到位移执行之前,每帧都做校验,不要只在按键事件里做检测:

  • 事件循环只负责更新速度方向,不要在事件分支里直接做碰撞判断
  • 分X/Y两个轴单独做碰撞校验,避免斜向移动卡墙、穿模
  • 确认碰撞后先把对应方向的速度清零,再执行位移
while not leaved:
    gameDisplay.fill('white')
    # 处理输入事件,仅更新速度状态
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            leaved = True
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_q:
                Img_Position = Img_Positions.get("left")
                x_speed = -player_speed
            if event.key == pygame.K_d:
                x_speed = player_speed
            if event.key == pygame.K_z:
                y_speed = -player_speed
            if event.key == pygame.K_s:
                y_speed = player_speed
        if event.type == pygame.KEYUP:
            if event.key in (pygame.K_q, pygame.K_d):
                x_speed = 0
            if event.key in (pygame.K_z, pygame.K_s):
                y_speed = 0

    # 位移前先做碰撞校验,分轴检测
    if x_speed != 0 and check_collision(x, y, x_speed, 0):
        x_speed = 0
    if y_speed != 0 and check_collision(x, y, 0, y_speed):
        y_speed = 0

    # 校验通过再更新坐标
    x += x_speed
    y += y_speed

    # 所有逻辑跑完再渲染
    Background(x,y)
    Player(Img_Position)
    Foreground(x,y)
    Text()
    pygame.display.update()
    clock.tick(FPS)

pygame.quit()
quit()
优化提示
  • 不要把pygame.draw.rect这类渲染调用写到纯逻辑函数里,碰撞检测直接用pygame.Rect做数学计算即可,不需要真的把形状画到屏幕上,能减少不必要的性能消耗
  • 尽量少用全局变量传递状态,函数需要什么参数就传入什么,计算结果直接return,避免多段逻辑修改变量导致的状态不同步问题
  • 分轴碰撞检测是2D Tile类游戏的标准实现方案,比整体碰撞检测的卡墙概率低很多

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 05:36:34