首页 > 解决方案 > Pygame tilemap 碰撞(使其返回正在碰撞的一侧)

问题描述

我有一个由精灵组成的关卡(在精灵组中),这些精灵由二维数组放置,这就是瓷砖地图。

我有一个玩家精灵(在另一个精灵组中)

你如何制作一个 2d 平台游戏呢?我只需要一段代码,它可以判断玩家的哪一侧正在触摸瓷砖并将其返回,这样我就可以制定条件来阻止他从一侧移动到另一侧或阻止他跳跃。我尝试了很多不同的东西,但由于瓷砖地图,我无法使其正常工作。

标签: pythonpygamespritetiles

解决方案


我在这里为想要学习如何编程的人回答问题。如果问题显然是“给我代码”,或者“我从这里和那里复制了一些代码;现在为我修复它!”,我不会在答案中投入太多的编码工作。所以我希望你能理解为什么下面的这个答案在很大程度上是理论上的,并且不包含经过测试和调试的代码。

我假设您正在谈论具有“重力”的 2D 游戏,因此玩家会以某种方式跳跃和跌落。如果您谈论的是类似 2D胭脂的(自上而下的视图,无重力),下面的某些命名法可能有点偏离,但逻辑相同。

可以将基于图块的“地图”或“关卡”视为一组图层。我会将可碰撞的精灵拆分成一个单独的精灵组,我们称之为platforms. 装饰瓷砖可以成background组。背景是较低层,除了必须绘制之外,可以忽略不计。单个背景图像可能比一大堆精灵更好。

因此,每当玩家尝试移动时,都需要在移动完成之前测试平台是否与新的理论位置发生碰撞。PyGame Sprite 对象中有一个方便的函数,称为pygame.sprite.spritecollideany(). 这使您的代码可以很容易地检查单个精灵和一段时间精灵组之间的冲突:

collided_with = player_sprite.spritecollideany( platform_sprite_group )
if ( collided_with != None ):
    print( "Player collided with sprite: " + str( collided_with ) )

另一个方便的功能是pygame.sprite.groupcollide(),这非常适合将一组精灵与另一个精灵碰撞 - 就像一束箭对着一堆敌人一样。但是您也可以创建一个包含单个项目的精灵组,并将其用于单个对象。

您实际上并不需要知道玩家的哪一侧与平台发生碰撞。这是隐含的信息,因为您已经知道玩家的移动方式。碰撞测试的基础是,意识到一次移动一个大于 1 像素的精灵可以将玩家移动到现有精灵的顶部,而无需接触侧面。假设玩家移动得非常快,它的下一个移动位置可能正好在另一个精灵的中间!那么它击中了哪一边呢?(玩家移动的一侧。)

例如:如果玩家想向左移动 10 个像素,但平台边缘距离 5 个像素,则玩家“碰撞”但没有接触。一旦发生碰撞,代码需要确定可接受的运动是什么,并将运动调整到这个增量。由于 PyGame sprite 对象基于Rect 对象x,因此这是使用 Rect 的,ywidth,进行的相当简单的测试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 

显然是玩家移动得足够快(每帧很多像素),理论上它可以“跳跃”整个平台,而不是碰撞,直接通过。上面的代码受到这个潜在错误的影响。但是大多数游戏不需要担心这种情况。

所以我希望上面介绍的逻辑足以让你开始处理各种碰撞。试着让一些代码工作,这是最好的学习方式。写一些东西,测试它,犯错误,提出问题。我们随时准备提供帮助。很容易陷入仅仅复制和粘贴其他人的代码(有时质量中等)以获得“快速解决方案”的陷阱。但这并不能真正帮助您学习基础知识。


推荐阅读