Pygame spritecollide 碰撞箱

Pygame spritecollide hitboxes

我正在开发一个简单的 2D 平台游戏,但我在使用 sprite 的碰撞框时遇到了一些问题。我使用 pygame.sprite.spritecollide 函数生成接触我的玩家精灵的方块(平台)列表。

这是我的播放器class:

class Player( pygame.sprite.Sprite ):

     def __init__(self,x,y,image):

        super( Player, self ).__init__()

        self.vel_x = 0
        self.vel_y = 0
        self.moveSpeed = 3
        self.jumpPower = 7

        self.direction = idle
        self.grounded = False
        self.falling = True
        self.jumping = False
        self.climbing = False

        self.image = pygame.Surface((50,50))#pygame.transform.scale( image, (50,50))
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.width = 50
        self.height = 50
        self.rect.bottom = self.rect.y + self.height

    def set_position( self,x,y ):

        self.rect.x = x
        self.rect.y = y

    def experience_gravity(self, gravity = 0.3):

        if not self.grounded:
            self.vel_y += gravity
            self.falling = True
        else:
            self.vel_y = 0
            self.grounded = True
            self.falling = False

    def jump(self):

        self.grounded = False
        self.vel_y -= self.jumpPower

    def update(self, collidable = pygame.sprite.Group() ):

        global collision

        self.experience_gravity()

        self.rect.x += self.vel_x
        self.rect.y += self.vel_y

        collision_list = pygame.sprite.spritecollide( self, collidable, False )

        for p in collision_list:
            if ( self.vel_y > 0 ):
                self.vel_y = 0
                self.grounded = True

在我的更新方法中,我检查了包含我所有平台(参数可碰撞)的精灵组与玩家之间的碰撞。

这是我的街区 class:

class Block( pygame.sprite.Sprite ):

    def __init__( self, x, y, width, height):

        super( Block, self ).__init__()
        self.image = pygame.Surface( ( width, height ) )
        self.image.fill( black )

        self.rect = self.image.get_rect()

        self.type = platform

        self.rect.x = x
        self.rect.y = y
        self.width = width
        self.height = height

非常不言自明的块class。我的其余代码是将所有内容更新和 blit 到白色背景上。我 运行 遇到的问题是,当玩家降落在平台上时,只有当它已经在平台上时才会停止下落(变成地面)。更奇怪的是,木块沉入平台的深度并不一致。有时它会下降 10 个像素,其他的会下降 20 个像素。这是玩家卡住的截图:

The player block is stuck inside the platform block

所以这真的让我感到困惑,特别是因为块落入的数量不一致。如果有人能告诉我如何解决这个问题,我将不胜感激。

谨致问候,

德里克

没有任何调试跟踪很难诊断,但我有一两个想法。

首先,转储调试轨迹:打印每个时间步的显着值:玩家块的位置、碰撞块的位置和适用的速度。这应该会在所涉及对象的每个时间步为您提供一个类似于 table 的快照。

现在,查看碰撞前最后一个时间步的值。我怀疑您的玩家速度可能为 -20,但降落在仅低于 10 像素的平台上。您的更新逻辑需要处理两个时间步之间的着陆,并在平台高度停止播放器。在我看来,好像允许玩家在整个时间步长内跌倒,这会将他柔软的下肢嵌入平台 10 个像素。

其次,检查您是否在比较较近的边缘:在本例中,是玩家的下边缘与平台的上边缘。稍后您将需要处理玩家的右下角接触方块左上角的情况,并且您必须确定玩家是先击中方块的顶部(着陆)还是侧面(改变水平速度和下降) .


我不会改变计算出的速度;我认为只调整最终位置会更容易。您发布的最后一段代码是您已经将碰撞作为特例处理的地方。当您检测到碰撞时,获取对象的顶面(y 值)。如果它高于播放器底部的当前位置,则将该顶部表面指定为正确位置。这将使您的玩家坐在碰撞列表中最高的物体之上。

请注意,这仅在您的整个碰撞列表都在坠落时才有效;对于横向碰撞,您也需要分开列表并根据需要调整每个边界。如果在同一时间步长中有来自多个侧面的碰撞,这可能会变得复杂——例如,当玩家同时撞到墙壁和平台时,一个 goombah 从左侧猛击玩家。