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,等于未改变状态,跳跃逻辑完全无效。
修复方案
- 替换类为单例对象:直接创建玩家、地面、背景的对象实例,确保所有操作都是同一个对象,持久保存坐标状态。
- 重构碰撞与重力逻辑:当玩家碰撞地面时,将玩家底部对齐地面顶部,同时重置重力为0,避免重力持续累加导致穿透。
- 简化跳跃逻辑:移除冗余的
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
相关产品推荐
相关产品推荐

