PyGame瓦片地图Y轴碰撞问题:玩家矩形触地抖动求助
解决PyGame瓦片地图Y轴碰撞抖动问题
抖动的核心原因是玩家站在地面时重力仍持续累加,导致每帧obj.dy都会增加grav_rate,即使碰撞时被重置为0,下一帧又会被加上重力,玩家反复尝试下落、被碰撞检测推回,形成抖动。
以下是修复后的代码,关键修改点已标注:
import pygame from sys import exit pygame.init() screen = pygame.display.set_mode((800, 600)) clock = pygame.time.Clock() class Player: def __init__(self, x, y): self.rect = pygame.Rect(x, y, 40, 40) # 移除重复赋值,Rect初始化已设置坐标 # self.rect.x = x # self.rect.y = y self.vel = 4 self.dx = 0 self.dy = 0 self.is_jump = False self.is_stand = False self.jump_count = 10 def handle_input(self): key = pygame.key.get_pressed() if key[pygame.K_RIGHT]: self.dx = self.vel elif key[pygame.K_LEFT]: self.dx = -self.vel else: self.dx = 0 # 优化跳跃逻辑:仅站在地面时允许触发跳跃 if key[pygame.K_SPACE] and self.is_stand: self.is_jump = True self.is_stand = False self.dy = -self.jump_count def update(self): self.handle_input() pygame.draw.rect(screen, (0, 255, 0), self.rect) # 移除无意义的rect.update调用,未修改尺寸无需执行 # self.rect.update(self.rect.x, self.rect.y, 40, 40) class Game: def __init__(self): self.map = [ ["T", "T", "T", "T", "T", "T", "T", "T", "T", "T", "T", "T", "T", "T", "T", "T", "T", "T", "T", "T"], ["T", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "T"], ["T", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "T"], ["T", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "T"], ["T", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "T"], ["T", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "T"], ["T", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "T"], ["T", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "T"], ["T", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "T", "T", "T", "T", "T", "T", "T"], ["T", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "T"], ["T", "T", "T", "T", "T", "T", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "T"], ["T", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "T"], ["T", "0", "P", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "T"], ["T", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "T"], ["T", "T", "T", "T", "T", "T", "T", "T", "T", "T", "T", "T", "T", "T", "T", "T", "T", "T", "T", "T"] ] self.tiles = [] for row_num, row in enumerate(self.map): for col_num, column in enumerate(row): if column == "T": rect = pygame.Rect(40*col_num, 40*row_num, 40, 40) self.tiles.append(rect) elif column == "P": self.player = Player(40*col_num, 40*row_num) self.gravity = 5 self.grav_rate = 0.3 def physics(self, obj): # 限制重力作用:仅玩家不在地面时累加重力 if not obj.is_stand: obj.dy += self.grav_rate if obj.dy > self.gravity: obj.dy = self.gravity for tile in self.tiles: coll_x = obj.rect.x + obj.dx, obj.rect.y, obj.rect.w, obj.rect.h - 1 coll_y = obj.rect.x, obj.rect.y + obj.dy, obj.rect.w, obj.rect.h if tile.colliderect(coll_x): pygame.draw.rect(screen, (255, 255, 0), (tile.x, tile.y, 10, 10)) if obj.dx < 0: obj.rect.left = tile.right elif obj.dx > 0: obj.rect.right = tile.left obj.dx = 0 if tile.colliderect(coll_y): pygame.draw.rect(screen, (255, 255, 255), (tile.x, tile.y, 10, 10), 2) if obj.dy < 0: obj.dy = -obj.dy elif obj.dy > 0: obj.dy = 0 obj.is_jump = False obj.is_stand = True obj.rect.bottom = tile.top # pygame.draw.rect(screen, (255, 255, 0), coll_x, 1) # pygame.draw.rect(screen, (255, 255, 255), coll_y, 1) obj.rect.x += obj.dx obj.rect.y += obj.dy def update(self): while True: screen.fill((0, 0, 0)) for event in pygame.event.get(): if event.type == pygame.QUIT: exit() for tile in self.tiles: pygame.draw.rect(screen, (255, 0, 0), tile) self.physics(self.player) self.player.update() pygame.display.update() clock.tick(60) g = Game() g.update()
关键修改说明:
- 重力逻辑限制:在
physics方法中,仅当玩家不在地面(obj.is_stand为False)时才累加重力,避免地面上的玩家被持续拉扯。 - 跳跃输入优化:修改跳跃触发条件,只有玩家站在地面时按空格才会起跳,防止按住空格持续强制修改
dy值。 - 移除冗余代码:删除Player类中重复的坐标赋值和无意义的
rect.update调用,减少不必要的状态干扰。
内容的提问来源于stack exchange,提问作者iceketer
相关产品推荐
相关产品推荐

