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

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()

关键修改说明:

  1. 重力逻辑限制:在physics方法中,仅当玩家不在地面(obj.is_stand为False)时才累加重力,避免地面上的玩家被持续拉扯。
  2. 跳跃输入优化:修改跳跃触发条件,只有玩家站在地面时按空格才会起跳,防止按住空格持续强制修改dy值。
  3. 移除冗余代码:删除Player类中重复的坐标赋值和无意义的rect.update调用,减少不必要的状态干扰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 15:47:03