【问题标题】:Passing through walls after collision Pygame碰撞后穿过墙壁 Pygame
【发布时间】:2015-08-03 21:48:41
【问题描述】:

大家好,我需要有关 pygame 碰撞问题的帮助。 我有一个边界图,可以通过使用蒙版重叠来设置像素完美碰撞。检测到碰撞没有任何问题,但是在阻止玩家穿过墙壁时,总是有某种方式可以通过它。我已经做了一些尝试(真的很多),包括当你同时按下三个按钮时甚至冻结播放器以避免它闪出,但无济于事。

现在,我检查用户按下哪个按钮来设置方向:

while True:
for event in pygame.event.get():
    if event.type == pygame.QUIT:
        pygame.quit()
        sys.exit()
    key = pygame.key.get_pressed()
    if key[pygame.K_w]:
        COLLISION_DIRECTION = "UP"
    if key[pygame.K_s]:
        COLLISION_DIRECTION = "DOWN"
    if key[pygame.K_d]:
        COLLISION_DIRECTION = "RIGHT"
    if key[pygame.K_a]:
        COLLISION_DIRECTION = "LEFT"

然后根据方向检查碰撞。在我最后一次绝望的尝试中,我求助于将最后一个非碰撞位置保存在数组中,将世界(我正在移动世界,而不是玩家)平移到该位置并减去或增加移动速度:

if boundariesMap_mask.overlap(player.mask, (offset_x, offset_y)) is None:
        lastPos = [world.x, world.y]
    else:
        while COLLISION_DIRECTION == "UP":
            world.y = (lastPos[1]-DIST_WORLD)
            break
        while COLLISION_DIRECTION == "DOWN":
            world.y = (lastPos[1]+DIST_WORLD)
            break
        while COLLISION_DIRECTION == "LEFT":
            world.x = (lastPos[0]-DIST_WORLD)
            break
        while COLLISION_DIRECTION == "RIGHT":
            world.x = (lastPos[0]+DIST_WORLD)
            break

我最好的猜测是,我应该在移回安全位置时阻止所有额外的输入,以避免更改 COLLISION_DIRECTION。 你们能帮我吗?

world.x 和 world.y 是世界的变量坐标

编辑:我忘了添加世界构造函数类

class World(pygame.sprite.Sprite):
def __init__(self):
    self.sprite = pygame.image.load('bin\\assets\\test.png')
    self.x = 220
    self.y = 45

def draw(self, surface):
    surface.blit(self.sprite, (self.x, self.y))

def handle_keys(self):

    key = pygame.key.get_pressed()
    if pygame.joystick.get_count():
        joystick_x = round(my_joystick.get_axis(0))
        joystick_y = round(my_joystick.get_axis(1))

        if joystick_x < 0:
            self.x += DIST_WORLD
        if joystick_x > 0:
            self.x -= DIST_WORLD
        if joystick_y < 0:
            self.y += DIST_WORLD
        if joystick_y > 0:
            self.y -= DIST_WORLD

    if key[pygame.K_w]:
        self.y += DIST_WORLD
    if key[pygame.K_s]:
        self.y -= DIST_WORLD
    if key[pygame.K_a]:
        self.x += DIST_WORLD
    if key[pygame.K_d]:
        self.x -= DIST_WORLD

【问题讨论】:

  • 我不完全确定我是否已经接近,所以如果我离开了,我很抱歉,我想我会分享以防万一 - 您是否尝试过冻结检测速度直到返回到任何位置,然后重新设置?
  • 是的,我什至将它设置为 0 到任何其他按钮输入,直到返回到非碰撞位置。我之前也设置了一个非常准确的“远离碰撞点”功能,但它一直有效,直到你一次按下三个按钮。如果你这样做了,你会穿过墙壁,代码会启动并且你不会停下来,直到你处于非碰撞位置,所以我把它取下来。在我终于实现了像素完美碰撞之后,现在出现这个问题真是令人沮丧
  • 快速说明:我认为您的第二个代码块中的选项卡已关闭:else: 块是缩进的,而 if.. 语句不是。我也不确定World 类中的函数是否正确显示。 ;)

标签: python pygame game-physics collision


【解决方案1】:

从问题和您在 cmets 中的回答来看,似乎每当注册三个或更多按键时都会触发故障,导致 COLLISION_DIRECTIONWorld.yWorld.x 更新不当。

考虑这样一个事实,如果玩家在 X 或 Y 轴上沿某个方向移动,他们不能同时向相反方向移动。还要考虑这样一个事实:如果玩家同时按下多个键,主游戏循环中的代码允许覆盖 COLLISION_DIRECTION 的值;例如,如果同时按住 W、A 和 S,则最终的 COLLISION_DIRECTION 将是 "LEFT"

我假设您允许对角线运动,所以我们在这里要做的是使COLLISION_DETECTION 同时对 x 轴和 y 轴有意义。然后,我们必须将按键检查的次数限制为恰好两次(一次用于 x 轴,一次用于 y 轴),这样就不会发生三键问题。

在您的主游戏循环中:

## Instead of one COLLISION_DIRECTION, we now have two separate variables:
## COLLISION_DIRECTION_X and COLLISION_DIRECTION_Y

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        key = pygame.key.get_pressed()

        ## Using elif so we don't mess up COLLISION_DIRECTION_Y
        if key[pygame.K_w]:
            COLLISION_DIRECTION_Y = "UP"
        elif key[pygame.K_s]:
            COLLISION_DIRECTION_Y = "DOWN"

        ## Using elif so we don't mess up COLLISION_DIRECTION_X
        if key[pygame.K_d]:
            COLLISION_DIRECTION_X = "RIGHT"
        elif key[pygame.K_a]:
            COLLISION_DIRECTION_X = "LEFT"

相应地更新您的碰撞检测:

 if boundariesMap_mask.overlap(player.mask, (offset_x, offset_y)) is None:
    lastPos = [world.x, world.y]
 else:
    ## Redundant while-break replaced with simple if-statements;
    ## Using while is not exactly necessary because we carry out
    ## these statements each frame

    if COLLISION_DIRECTION_Y == "UP":
        world.y = (lastPos[1]-DIST_WORLD)
    elif COLLISION_DIRECTION_Y == "DOWN":
        world.y = (lastPos[1]+DIST_WORLD)

    if COLLISION_DIRECTION_X == "LEFT":
        world.x = (lastPos[0]-DIST_WORLD)
    elif COLLISION_DIRECTION_X == "RIGHT":
        world.x = (lastPos[0]+DIST_WORLD)

然后,在您的 handle_keys 函数中:

 def handle_keys(self):

    key = pygame.key.get_pressed()
    if pygame.joystick.get_count():
        joystick_x = round(my_joystick.get_axis(0))
        joystick_y = round(my_joystick.get_axis(1))

        ## Restrict joystick x-input checking, because we logically
        ## cannot be both greater and less than zero

        if joystick_x < 0:
            self.x += DIST_WORLD
        elif joystick_x > 0:
            self.x -= DIST_WORLD

        ## Restrict joystick y-input checking, because we logically
        ## cannot be both greater and less than zero

        if joystick_y < 0:
            self.y += DIST_WORLD
        elif joystick_y > 0:
            self.y -= DIST_WORLD

    ## Restrict keypress vertical axis checking for the same reason
    if key[pygame.K_w]:
        self.y += DIST_WORLD
    elif key[pygame.K_s]:
        self.y -= DIST_WORLD

    ## Restrict keypress horizontal axis checking for same reason
    if key[pygame.K_a]:
        self.x += DIST_WORLD
    elif key[pygame.K_d]:
        self.x -= DIST_WORLD

我希望这会有所帮助!如果代码没有做到这一点,我深表歉意,但至少,我希望我在代码之前的 cmets 提供一些见解。

【讨论】:

    猜你喜欢
    • 2016-04-24
    • 1970-01-01
    • 2018-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多