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

Pygame玩家精灵忽略colliderect()碰撞,穿透地面快速下落问题排查

问题

运行以下Pygame代码时,玩家可通过WASD或方向键移动,但静止约10秒后精灵会消失,打印玩家y坐标发现其值持续飙升,说明玩家穿透地面后持续下落。尝试过添加地面吸附变量、设置跳跃权限关联重力逻辑均未生效,需要实现玩家稳定停留在地面的效果。

原代码:

import pygame, time
from sys import exit

pygame.init()
pygame.font.init()

clock = pygame.time.Clock()
font = pygame.font.SysFont("Arial", 18)

def update_fps():
    fps = str(int(clock.get_fps()))
    fps_text = font.render(fps, 1, pygame.Color("coral"))
    return fps_text

# Game Variables / Functions

screen_width = 1068
screen_height = 628
screen = pygame.display.set_mode((screen_width, screen_height))
original_player_pos = (50, 500)
original_player_size = (40, 60)
FPS = 69
gravity = 0
jump_force = 15
player_speed_right = 10
player_speed_left = 10
ground_grip = True
can_jump = True

# Player

class player():
    player_surf = pygame.image.load("Graphics\player_idle.png").convert_alpha()
    player = player_surf.get_rect(topleft=(original_player_pos))

class background():
    sky_surf = pygame.image.load("Graphics\Sky.png")
    sky_surf = pygame.transform.scale(sky_surf, (screen_width * 2, screen_height * 2))
    sky = sky_surf.get_rect(topleft=(0, -screen_height))

class surfaces():
    main_platform_surf = pygame.image.load("Graphics\main_ground.png")
    main_platform = main_platform_surf.get_rect(topleft=(0, screen_height - main_platform_surf.get_height() + (main_platform_surf.get_height()) / 2))

# Game Engine Functions

def y_movement():
    global gravity, ground_grip,can_jump
    
    gravity += 1
    player().player.y += gravity

    if ground_grip == True:
        if player().player.colliderect(surfaces().main_platform):
            player().player.y = surfaces().main_platform.y - original_player_size[1]

        if not player().player.colliderect(surfaces().main_platform) and player().player.y < surfaces().main_platform.y - original_player_size[1]:
            can_jump = False
        else:
            can_jump = True

def x_movement():
    keys = pygame.key.get_pressed()

    if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
        player().player.x += player_speed_right
        return "Right"
    if keys[pygame.K_LEFT] or keys[pygame.K_a]:
        player().player.x -= player_speed_left
        return "Left"

def draw(surface, rect):
    screen.blit(surface, rect)

def jump():
    global gravity
    gravity = -jump_force

# Game Engine

while True:
    update_fps()
    screen.fill("black")

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE and can_jump == True:
                ground_grip = False
                if ground_grip == False:
                    jump()
                    ground_grip = True

    x_movement()
    y_movement()
    
    draw(background().sky_surf, background().sky)
    draw(surfaces().main_platform_surf, surfaces().main_platform)
    draw(player().player_surf, player().player)
    draw(update_fps(), (10,0))

    clock.tick(FPS)
    pygame.display.update()

问题原因

  • 类的使用逻辑错误:定义的player、background、surfaces是类,但每次调用player()都会创建全新实例,导致玩家位置从未被持久保存——所有坐标修改都是在临时实例上进行,绘制的又是另一个新实例,时间久了坐标彻底混乱。
  • 碰撞与重力逻辑缺失:即使类的问题修复,当前碰撞处理没有重置重力,重力会持续累加,单次增量过大后直接穿透地面。
  • 跳跃逻辑自相矛盾:按下空格时先将ground_grip设为False,立刻又设回True,等于未改变状态,跳跃逻辑完全无效。

修复方案

  1. 替换类为单例对象:直接创建玩家、地面、背景的对象实例,确保所有操作都是同一个对象,持久保存坐标状态。
  2. 重构碰撞与重力逻辑:当玩家碰撞地面时,将玩家底部对齐地面顶部,同时重置重力为0,避免重力持续累加导致穿透。
  3. 简化跳跃逻辑:移除冗余的ground_grip变量,直接用can_jump控制跳跃权限,按下空格时直接设置重力为负的跳跃力。

修复后的完整代码

import pygame
from sys import exit

pygame.init()
pygame.font.init()

clock = pygame.time.Clock()
font = pygame.font.SysFont("Arial", 18)

def update_fps():
    fps = str(int(clock.get_fps()))
    fps_text = font.render(fps, True, pygame.Color("coral"))
    return fps_text

# Game Variables
screen_width = 1068
screen_height = 628
screen = pygame.display.set_mode((screen_width, screen_height))
original_player_pos = (50, 500)
original_player_size = (40, 60)
FPS = 60
gravity = 0
jump_force = 15
player_speed = 10
can_jump = True

# 创建单例对象,避免重复实例化
# Player
player_surf = pygame.image.load("Graphics\\player_idle.png").convert_alpha()
player_rect = player_surf.get_rect(topleft=original_player_pos)

# Background
sky_surf = pygame.image.load("Graphics\\Sky.png")
sky_surf = pygame.transform.scale(sky_surf, (screen_width * 2, screen_height * 2))
sky_rect = sky_surf.get_rect(topleft=(0, -screen_height))

# Surfaces
main_platform_surf = pygame.image.load("Graphics\\main_ground.png")
main_platform_rect = main_platform_surf.get_rect(topleft=(0, screen_height - main_platform_surf.get_height()))

# Game Engine Functions
def y_movement():
    global gravity, can_jump
    
    gravity += 0.8  # 调小重力增量,让下落更平滑自然
    player_rect.y += gravity

    # 地面碰撞处理:固定位置+重置重力
    if player_rect.colliderect(main_platform_rect):
        player_rect.bottom = main_platform_rect.top
        gravity = 0
        can_jump = True
    else:
        can_jump = False

def x_movement():
    keys = pygame.key.get_pressed()
    if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
        player_rect.x += player_speed
    if keys[pygame.K_LEFT] or keys[pygame.K_a]:
        player_rect.x -= player_speed
    # 限制玩家在屏幕范围内,防止移出视野
    player_rect.x = max(0, min(player_rect.x, screen_width - player_rect.width))

def draw(surface, rect):
    screen.blit(surface, rect)

def jump():
    global gravity
    gravity = -jump_force

# Game Engine
while True:
    screen.fill("black")

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE and can_jump:
                jump()

    x_movement()
    y_movement()
    
    draw(sky_surf, sky_rect)
    draw(main_platform_surf, main_platform_rect)
    draw(player_surf, player_rect)
    draw(update_fps(), (10, 0))

    clock.tick(FPS)
    pygame.display.update()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 23:25:17