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

Pygame角色移动碰撞问题求助:触碰方块时停止不穿透

问题:Pygame角色触碰方块时停止移动,避免穿透效果

我是Python和Pygame新手,希望实现角色触碰"Block"方块时停止移动,避免穿透效果。目前的角色移动代码如下:

def Player_Movement():
    global x_plr, y_plr, X_vel, Y_vel, Main_Player
    keys = pygame.key.get_pressed()
    speed = 5
    if X_vel > 0:
        X_vel -= 1
    if X_vel < 0:
        X_vel += 1
    if Y_vel > 0:
        Y_vel -= 1
    if Y_vel < 0:
        Y_vel += 1

    if keys[pygame.K_d]:
        X_vel = speed
    if keys[pygame.K_a]:
        X_vel = -speed
    if keys[pygame.K_w]:
        Y_vel = -speed
    if keys[pygame.K_s]:
        Y_vel = speed
    
    if Main_Player.colliderect(Block):
        Main_Player = pygame.draw.rect(win, playercolor, (x_plr, y_plr, size, size))
        X_vel += abs(X_vel)
        print(X_vel)
    x_plr += X_vel

    if Main_Player.colliderect(Block):
        Main_Player = pygame.draw.rect(win, playercolor, (x_plr, y_plr, size, size))
        Y_vel += abs(Y_vel)
        print(Y_vel)
    y_plr += Y_vel

为方便排查,附上完整代码:

import pygame
pygame.init()

clock = pygame.time.Clock()
winWidth = 1100
winHeight = 700
win = pygame.display.set_mode((winWidth, winHeight))
pygame.display.set_caption('my caption')

# variables

x_plr = 200
y_plr = 100
X_vel = 0
Y_vel = 0
size = 25
playercolor = (255, 70, 70)
Main_Player = pygame.draw.rect(win, playercolor, (x_plr, y_plr, size, size))

Block = pygame.draw.rect(win, (230, 230, 230), (500, 100, 50, 50))

def Displaying():
    global Main_Player, Block
    Main_Player = pygame.draw.rect(win, playercolor, (x_plr, y_plr, size, size))
    Block = pygame.draw.rect(win, (230, 230, 230), (350, 100, 300, 50))
    

def Player_Movement():
    global x_plr, y_plr, X_vel, Y_vel, Main_Player
    keys = pygame.key.get_pressed()
    speed = 5
    if X_vel > 0:
        X_vel -= 1
    if X_vel < 0:
        X_vel += 1
    if Y_vel > 0:
        Y_vel -= 1
    if Y_vel < 0:
        Y_vel += 1

    if keys[pygame.K_d]:
        X_vel = speed
    if keys[pygame.K_a]:
        X_vel = -speed
    if keys[pygame.K_w]:
        Y_vel = -speed
    if keys[pygame.K_s]:
        Y_vel = speed
    
    if Main_Player.colliderect(Block):
        Main_Player = pygame.draw.rect(win, playercolor, (x_plr, y_plr, size, size))
        X_vel += abs(X_vel)
        print(X_vel)
    x_plr += X_vel

    if Main_Player.colliderect(Block):
        Main_Player = pygame.draw.rect(win, playercolor, (x_plr, y_plr, size, size))
        Y_vel += abs(Y_vel)
        print(Y_vel)
    y_plr += Y_vel
        
        

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
    win.fill((50,50,50))

    Player_Movement()

   
    
    Displaying()
    pygame.display.update()
    pygame.display.update(Main_Player)
    clock.tick(60)

解决方案

问题分析

原代码存在几个核心问题:

  • 碰撞检测时机错误:移动前检测碰撞时角色位置未更新,移动后检测时角色已穿透方块,无法有效阻止穿透。
  • 碰撞处理逻辑错误:直接修改速度的方式无法精准控制角色位置,反而会导致速度异常。
  • 矩形对象管理混乱:依赖绘制函数返回的矩形对象进行碰撞检测,位置同步容易出错。

修改后的完整代码

import pygame
pygame.init()

clock = pygame.time.Clock()
winWidth = 1100
winHeight = 700
win = pygame.display.set_mode((winWidth, winHeight))
pygame.display.set_caption('my caption')

# 变量定义
x_plr = 200
y_plr = 100
X_vel = 0
Y_vel = 0
size = 25
playercolor = (255, 70, 70)
# 直接创建碰撞用的矩形对象,脱离绘制逻辑
Main_Player = pygame.Rect(x_plr, y_plr, size, size)
Block = pygame.Rect(350, 100, 300, 50)

def Displaying():
    # 仅负责绘制,不修改矩形位置数据
    pygame.draw.rect(win, playercolor, Main_Player)
    pygame.draw.rect(win, (230, 230, 230), Block)
    

def Player_Movement():
    global x_plr, y_plr, X_vel, Y_vel, Main_Player
    keys = pygame.key.get_pressed()
    speed = 5
    # 保留原有的摩擦力逻辑
    if X_vel > 0:
        X_vel -= 1
    if X_vel < 0:
        X_vel += 1
    if Y_vel > 0:
        Y_vel -= 1
    if Y_vel < 0:
        Y_vel += 1

    # 按键控制速度
    if keys[pygame.K_d]:
        X_vel = speed
    if keys[pygame.K_a]:
        X_vel = -speed
    if keys[pygame.K_w]:
        Y_vel = -speed
    if keys[pygame.K_s]:
        Y_vel = speed

    # 分方向处理移动与碰撞:先X轴,再Y轴
    # X方向移动与碰撞检测
    Main_Player.x += X_vel
    if Main_Player.colliderect(Block):
        # 碰撞后回退到刚好接触的位置
        if X_vel > 0:
            Main_Player.right = Block.left
        else:
            Main_Player.left = Block.right
        X_vel = 0  # 重置X方向速度,避免持续移动

    # Y方向移动与碰撞检测
    Main_Player.y += Y_vel
    if Main_Player.colliderect(Block):
        # 碰撞后回退到刚好接触的位置
        if Y_vel > 0:
            Main_Player.bottom = Block.top
        else:
            Main_Player.top = Block.bottom
        Y_vel = 0  # 重置Y方向速度

    # 更新全局坐标变量(供其他逻辑使用)
    x_plr = Main_Player.x
    y_plr = Main_Player.y
        
        

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
    win.fill((50,50,50))

    Player_Movement()
    Displaying()
    pygame.display.update()
    clock.tick(60)

关键修改说明

  • 独立碰撞矩形:用pygame.Rect直接创建角色和方块的碰撞区域,不再依赖绘制函数返回的对象,确保位置数据准确。
  • 分方向碰撞处理:先处理X轴移动与碰撞,再处理Y轴,避免多方向碰撞时的逻辑冲突。
  • 精准位置回退:碰撞时将角色位置调整到与方块刚好接触的状态,同时重置对应方向的速度,彻底阻止穿透。
  • 职责分离:Displaying函数仅负责绘制,不再修改矩形位置,代码逻辑更清晰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 09:20:23