冲突的“if”语句

Conflicting "if" statements

提问人:ButterySpirit 提问时间:11/13/2023 更新时间:11/13/2023 访问量:55

问:

因此,我正在尝试与我的播放器一起实现适当的墙壁碰撞检测,类似于 isaac 的绑定工作原理(您在按下两个键时撞到墙上,当您撞到墙上时,向墙的移动被禁用,但您可以继续沿另一个键的方向在墙上滑动)。因此,我尝试在我的播放器类的 update 方法中创建两个不同的 if 语句,分别处理左/右冲突和上/下冲突,但似乎 if 语句的顺序似乎相互冲突

def update(self,dt) 
        prev_x = self.x
        prev_y = self.y

        # Update the player's position
        self.world_x += dx
        self.world_y += dy
        self.x += dx
        self.y += dy
# Check for collisions with the "Walls" layer for horizontal movement
        if self.detect_collision_with_walls(self.walls_layer) and self.moving_left:
            self.x = prev_x
            self.world_x = self.x
        if self.detect_collision_with_walls(self.walls_layer) and self.moving_right:
            self.x = prev_x
            self.world_x = self.x

        # Check for collisions with the "Walls" layer for vertical movement
        if self.detect_collision_with_walls(self.walls_layer) and self.moving_up:
            self.y = prev_y
            self.world_y = self.y
            
        if self.detect_collision_with_walls(self.walls_layer) and self.moving_down:
            self.y = prev_y
            self.world_y = self.y

问题是只有前两个语句语句按应有的方式执行,当后两个语句运行时,它们会与顶部语句发生冲突,因为两者在技术上同时是正确的。它将玩家锁定在原位,直到导致碰撞的钥匙被释放,因为它本质上是这样做的:

 # Check for collisions with the "Walls" layer for vertical movement
        if self.detect_collision_with_walls(self.walls_layer) and self.moving_up:
            self.y = prev_y
            self.world_y = self.y
            self.x = prev_x
            self.world_x = self.x
            
        if self.detect_collision_with_walls(self.walls_layer) and self.moving_down:
            self.y = prev_y
            self.world_y = self.y
            self.x=prev_x
            self.world_x = self.x

我尝试了 elif 语句,这似乎没有帮助,因为当执行优先级较低的语句时,这两个条件在技术上仍然是正确的

Python 游戏开发

评论

0赞 Charles Duffy 11/13/2023
如果第一个序列运行,将序列中的第二个更改为 肯定会阻止第二个运行。如果您认为自己有相反的行为,请表现出来。(添加一些日志记录会有很多好处;只需打印值和正在执行的分支将提供更多的可见性)。ifelif
0赞 Karl Knechtel 11/13/2023
如果满足其中一个条件,代码是否应该尝试测试其他条件?你熟悉和吗?elseelif

答:

0赞 Brayden 11/13/2023 #1

为了防止锁定,同时仍然能够靠墙滑动,您需要知道要取消的方向(x 或 y)。您需要执行以下操作:

if self.colliding_with_wall(self.walls_layer, Direction.LEFT) and self.moving_left:
    self.x = prev_x
    self.world_x = self.x
if self.colliding_with_wall(self.walls_layer, Direction.RIGHT) and self.moving_right:
    self.x = prev_x
    self.world_x = self.x

# Check for collisions with the "Walls" layer for vertical movement
if self.colliding_with_wall(self.walls_layer, Direction.ABOVE) and self.moving_up:
    self.y = prev_y
    self.world_y = self.y
        
if self.colliding_with_wall(self.walls_layer, Direction.BELOW) and self.moving_down:
    self.y = prev_y
    self.world_y = self.y

确保同时实现该函数:

from enum import Enum, unique

@unique
class Direction(Enum):
    ABOVE = "above"
    BELOW = "below"
    LEFT = "left"
    RIGHT = "right"

def colliding_with_wall(walls, from_direction: Direction) -> bool:
    # Do the same loop to iterate over the walls as before but
    # add an additional check for which direction the player
    # hit the wall from.

    # Save the positions of the wall that the player encountered.
    # I'm not sure if you have 2D or 3D walls in your game so I'll just
    # do a 3D version and you can remove the extra code if yours is
    # only 2D.

    # Make a tuple of the wall's coordinates
    # I used ((top_left_x, top_left_y), (bottom_right_x, bottom_right_y))
    # Used made-up numbers here. Make sure you replace it with the
    # actual coordinates of the wall.
    wall = ((5, 10), (6, 14))

    # I assume that your player isn't single point so you're gonna need
    # to do something similar for the player.
    # Unless, of course, your game works on a tile system where the grid
    # is something like 8x8. In that case, the player only has one
    # coordinate.
    player = ((3, 9), (5, 11))

    # Here, I'll assume that the origin of your game (0, 0) is in the
    # top-left corner of the window. And that y increases going down.

    # I'll also assume that you use a `return false` before this point if
    # The player is not touching a wall at all.
    if from_direction == Direction.ABOVE:
        # Without more information about how your coordinate system works
        # (if it's like Minecraft's position system where the coordinate
        # values are floats/a large number with lots of precision, or
        # if it uses a tile map where you jump from tile to tile)

        # Check if the player is within the edges of the wall
        if player[0][0] < wall[1][0] and player[1][0] > wall[0][0]:
            # We're checking if the player hit the wall so the player
            # must be below the wall.

            # Use the threshold value (5 in this case) to adjust the
            # collision sensitivity based on how much your player moves
            # between function calls.
            if abs(player[0][1] - wall[1][1]) < 5:
                return true
    elif from_direction == Direction.BELOW:
        if player[0][0] < wall[1][0] and player[1][0] > wall[0][0]:
            if abs(player[1][1] - wall[0][1]) < 5:
                return true
    elif from_direction == Direction.LEFT:
        if player[0][1] < wall[1][1] and player[1][1] > wall[0][1]:
            if abs(player[0][0] - wall[1][0]) < 5:
                return true
    elif from_direction == Direction.RIGHT:
        if player[0][1] < wall[1][1] and player[1][1] > wall[0][1]:
            if abs(player[1][0] - wall[0][0]) < 5:
                return true
    else:
        # An invalid direction was entered so you can throw an error
        # here or just remove `else:` and ignore it.
        # If you remove `else:`, you must return either true of false.

如果不想对 Direction 枚举的值进行硬编码,也可以使用 .根据 Python 的枚举文档所说的话,您不应该在这里需要。auto@unique

from enum import Enum, auto

class Direction(Enum):
    ABOVE = auto()
    BELOW = auto()
    LEFT = auto()
    RIGHT = auto()

这应该可以让你防止穿过墙壁,同时仍然能够向另一个方向移动。请记住,StackOverflow 并不完全是一个 IDE,我的意思是没有语法检查,我没有时间实际测试它,所以请确保检查并测试此代码。


另外,我会将移动更改为仅在不接触墙壁时移动,而不是移动,如果您正在触摸墙壁,则向后移动。这在我的脑海中更有意义,但这种方式也很好。