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 从左侧猛击玩家。
我正在开发一个简单的 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 从左侧猛击玩家。