Pygame tilemap 碰撞(使其 return 哪一侧发生碰撞)
Pygame tilemap collisions (make it return which side is colliding)
我有一个由精灵组成的关卡(在一个精灵组中),这些精灵被放置在一个二维数组中,这就是 tilemap。
我有一个玩家精灵(在另一个精灵组中)
如何用它制作 2d 平台游戏?我只需要一段代码,它可以告诉玩家的哪一侧正在接触瓷砖,然后 returns 它这样我就可以创造条件来阻止他从一边移动到另一边或阻止他跳跃。
我已经尝试了很多不同的东西,但由于 tilemap 的原因,我无法使它正常工作。
我在这里为想学习如何编程的人回答问题。如果问题显然是 "gimme teh codez" 或 "I copied some code from here & there; now fix it for me!",我不会在答案中投入太多 编码 努力。所以我希望你能理解为什么下面的答案主要是理论上的,不包含经过测试和调试的代码。
我假设您谈论的是 "gravity" 的 2D 游戏,玩家会以某种方式跳跃和跌落。如果您谈论的是 2D rouge-like(自上而下视图,无重力),下面的一些术语可能有点不对,但逻辑相同。
基于图块的 "map" 或 "level" 可以被认为是一组图层。我会将可碰撞的精灵分成一个单独的精灵组,我们称它们为 platforms
。装饰砖可以分成 background
组。背景是一个较低的层,除了必须绘制之外,否则可以忽略。单个背景图像可能比一大堆精灵更好。
因此,每当玩家尝试移动时,都需要测试平台是否与新的理论位置发生碰撞,然后才能 移动完成。 PyGame Sprite object 中有一个方便的函数,叫做 pygame.sprite.spritecollideany()
。这允许您的代码很容易地检查单个精灵和一个 while 精灵组之间的碰撞:
collided_with = player_sprite.spritecollideany( platform_sprite_group )
if ( collided_with != None ):
print( "Player collided with sprite: " + str( collided_with ) )
另一个方便的函数是 pygame.sprite.groupcollide()
,这非常适合让一组 sprite 与另一组碰撞 - 就像一束箭与一群敌人发生碰撞一样。但你也可以制作一个带有 single item 的精灵组,并将其用于单个对象。
您真的不需要知道玩家的哪一侧与平台发生碰撞。这是隐式信息,因为您已经知道玩家的移动方向。碰撞测试的基础是认识到一次移动一个精灵大于 1 个像素可以将玩家移动到现有精灵的顶部而不会触及任何一侧。假设玩家移动得非常快,它的下一个移动位置可能就在另一个精灵的中间!那么它击中了哪一边呢? (玩家移动的那一侧。)
例如:如果玩家想向左移动 10 个像素,但平台边缘距离 5 个像素,玩家 "collides" 但不会接触。一旦发生碰撞,代码需要确定可接受的运动是什么,并将运动调整到这个增量。由于 PyGame 精灵对象基于 Rect object,这是使用 Rect 的 x
、y
和 width
、height
的相当简单的测试. 'x' & 'y' 代表左上角,所以我们需要考虑精灵的宽度:
# Player has tried to move delta_x and delta_y pixels
collided_with = player_sprite.spritecollideany( background_sprite_group )
if ( collided_with != None ):
print( "Player collided with sprite: " + str( collided_with ) )
if ( delta_x > 0 ): # moving right
# collides on right side
distance_to_sprite_x = player_sprite.rect.x + player_sprite.rect.width - collided_with.rect.x
elif ( delta_x < 0 ): # moving left
# collides on left side (take width of sprite into account)
distance_to_sprite_x = player_sprite.rect.x - collided_with.rect.x + collided_with.rect.width
else: # not moving horizontally
distance_to_sprite_x = 0
# Adjust the x-movement to make it rest against the sprite
delta_x = distance_to_sprite_x
# TODO: similarly for delta_y
显然玩家移动得足够快(每帧很多像素),理论上它可以 "jump" 整个平台,并且不会发生碰撞,直接通过。上面的代码存在这个潜在错误。但大多数游戏都不需要担心这种情况。
所以我希望上面介绍的逻辑足以让您开始处理各种碰撞。试着让一些代码工作,这是最好的学习方式。写一些东西,测试它,犯错误,提出问题。我们随时准备提供帮助。很容易陷入仅仅复制和粘贴其他人的代码(有时质量中等)来获得 "quick solution" 的陷阱。但它并不能真正帮助你学习基础知识。
我有一个由精灵组成的关卡(在一个精灵组中),这些精灵被放置在一个二维数组中,这就是 tilemap。
我有一个玩家精灵(在另一个精灵组中)
如何用它制作 2d 平台游戏?我只需要一段代码,它可以告诉玩家的哪一侧正在接触瓷砖,然后 returns 它这样我就可以创造条件来阻止他从一边移动到另一边或阻止他跳跃。 我已经尝试了很多不同的东西,但由于 tilemap 的原因,我无法使它正常工作。
我在这里为想学习如何编程的人回答问题。如果问题显然是 "gimme teh codez" 或 "I copied some code from here & there; now fix it for me!",我不会在答案中投入太多 编码 努力。所以我希望你能理解为什么下面的答案主要是理论上的,不包含经过测试和调试的代码。
我假设您谈论的是 "gravity" 的 2D 游戏,玩家会以某种方式跳跃和跌落。如果您谈论的是 2D rouge-like(自上而下视图,无重力),下面的一些术语可能有点不对,但逻辑相同。
基于图块的 "map" 或 "level" 可以被认为是一组图层。我会将可碰撞的精灵分成一个单独的精灵组,我们称它们为 platforms
。装饰砖可以分成 background
组。背景是一个较低的层,除了必须绘制之外,否则可以忽略。单个背景图像可能比一大堆精灵更好。
因此,每当玩家尝试移动时,都需要测试平台是否与新的理论位置发生碰撞,然后才能 移动完成。 PyGame Sprite object 中有一个方便的函数,叫做 pygame.sprite.spritecollideany()
。这允许您的代码很容易地检查单个精灵和一个 while 精灵组之间的碰撞:
collided_with = player_sprite.spritecollideany( platform_sprite_group )
if ( collided_with != None ):
print( "Player collided with sprite: " + str( collided_with ) )
另一个方便的函数是 pygame.sprite.groupcollide()
,这非常适合让一组 sprite 与另一组碰撞 - 就像一束箭与一群敌人发生碰撞一样。但你也可以制作一个带有 single item 的精灵组,并将其用于单个对象。
您真的不需要知道玩家的哪一侧与平台发生碰撞。这是隐式信息,因为您已经知道玩家的移动方向。碰撞测试的基础是认识到一次移动一个精灵大于 1 个像素可以将玩家移动到现有精灵的顶部而不会触及任何一侧。假设玩家移动得非常快,它的下一个移动位置可能就在另一个精灵的中间!那么它击中了哪一边呢? (玩家移动的那一侧。)
例如:如果玩家想向左移动 10 个像素,但平台边缘距离 5 个像素,玩家 "collides" 但不会接触。一旦发生碰撞,代码需要确定可接受的运动是什么,并将运动调整到这个增量。由于 PyGame 精灵对象基于 Rect object,这是使用 Rect 的 x
、y
和 width
、height
的相当简单的测试. 'x' & 'y' 代表左上角,所以我们需要考虑精灵的宽度:
# Player has tried to move delta_x and delta_y pixels
collided_with = player_sprite.spritecollideany( background_sprite_group )
if ( collided_with != None ):
print( "Player collided with sprite: " + str( collided_with ) )
if ( delta_x > 0 ): # moving right
# collides on right side
distance_to_sprite_x = player_sprite.rect.x + player_sprite.rect.width - collided_with.rect.x
elif ( delta_x < 0 ): # moving left
# collides on left side (take width of sprite into account)
distance_to_sprite_x = player_sprite.rect.x - collided_with.rect.x + collided_with.rect.width
else: # not moving horizontally
distance_to_sprite_x = 0
# Adjust the x-movement to make it rest against the sprite
delta_x = distance_to_sprite_x
# TODO: similarly for delta_y
显然玩家移动得足够快(每帧很多像素),理论上它可以 "jump" 整个平台,并且不会发生碰撞,直接通过。上面的代码存在这个潜在错误。但大多数游戏都不需要担心这种情况。
所以我希望上面介绍的逻辑足以让您开始处理各种碰撞。试着让一些代码工作,这是最好的学习方式。写一些东西,测试它,犯错误,提出问题。我们随时准备提供帮助。很容易陷入仅仅复制和粘贴其他人的代码(有时质量中等)来获得 "quick solution" 的陷阱。但它并不能真正帮助你学习基础知识。