Microsoft XNA Platformer示例,是否正确实施了碰撞检测?


11

Microsoft提供的示例似乎(从我所看到的)碰撞检测将有一个小错误。当用户与不可通过的图块碰撞时,将计算相交的深度。深度值X和Y中较小的一个用于固定用户的位置,因此它不再与图块碰撞。但是,如果用户沿对角线行驶,这是否可能导致用户无法准确地到达角色首先与图块发生碰撞的位置?

我可能是错的,但这只是我的看法。

   private void HandleCollisions()
        {
            // Get the player's bounding rectangle and find neighboring tiles.
            Rectangle bounds = BoundingRectangle;
            int leftTile = (int)Math.Floor((float)bounds.Left / Tile.Width);
            int rightTile = (int)Math.Ceiling(((float)bounds.Right / Tile.Width)) - 1;
            int topTile = (int)Math.Floor((float)bounds.Top / Tile.Height);
            int bottomTile = (int)Math.Ceiling(((float)bounds.Bottom / Tile.Height)) - 1;

            // Reset flag to search for ground collision.
            isOnGround = false;

            // For each potentially colliding tile,
            for (int y = topTile; y <= bottomTile; ++y)
            {
                for (int x = leftTile; x <= rightTile; ++x)
                {
                    // If this tile is collidable,
                    TileCollision collision = Level.GetCollision(x, y);
                    if (collision != TileCollision.Passable)
                    {
                        // Determine collision depth (with direction) and magnitude.
                        Rectangle tileBounds = Level.GetBounds(x, y);
                        Vector2 depth = RectangleExtensions.GetIntersectionDepth(bounds, tileBounds);
                        if (depth != Vector2.Zero)
                        {
                            float absDepthX = Math.Abs(depth.X);
                            float absDepthY = Math.Abs(depth.Y);

                            // Resolve the collision along the shallow axis.
                            if (absDepthY < absDepthX || collision == TileCollision.Platform)
                            {
                                // If we crossed the top of a tile, we are on the ground.
                                if (previousBottom <= tileBounds.Top)
                                    isOnGround = true;

                                // Ignore platforms, unless we are on the ground.
                                if (collision == TileCollision.Impassable || IsOnGround)
                                {
                                    // Resolve the collision along the Y axis.
                                    Position = new Vector2(Position.X, Position.Y + depth.Y);

                                    // Perform further collisions with the new bounds.
                                    bounds = BoundingRectangle;
                                }
                            }
                            else if (collision == TileCollision.Impassable) // Ignore platforms.
                            {
                                // Resolve the collision along the X axis.
                                Position = new Vector2(Position.X + depth.X, Position.Y);

                                // Perform further collisions with the new bounds.
                                bounds = BoundingRectangle;
                            }
                        }
                    }
                }
            }

            // Save the new bounds bottom.
            previousBottom = bounds.Bottom;
        }

3
为什么要减1,ppl?这个问题对我有效。但这是一个简短的答案:无论如何,XNA附带的平台演示只是一个示例。不要严格遵循您的游戏模型。这是为了告诉您可以进行游戏。如果它的实现不是最好的,那么您就不必打扰。
Gustavo Maciel'3

谢谢,我只是以示例为前提,他们所做的是最好的方法,而我却缺少了一些东西。感谢您为我清理。
PriestVallon 2012年

Answers:


12

你是绝对正确的。我在XNA Platformer示例中遇到了一些与碰撞例程有关的问题。但是我设法从示例中提供的代码开始,并对其进行了一些修改,直到在我可以抛出的每个测试方案中获得一致的结果为止。

特别是当我尝试通过沿对角线倾斜沿墙壁滑动时遇到的问题。由于假定样本是为了根据最小位移轴来解决碰撞,因此导致在朝某个方向推动墙时角色无法移动。例如,使用一个标志,拥抱天花板并试图从左向右移动时会卡住(不记得具体内容)。切换标志可以解决这种情况,但是在相反的情况下会出现问题。最重要的是,使用所提供的实现,我无法使其在各个方面和各个方面都能正常工作-至少在一种情况下,它总是会失败。

因此,我所做的更改的核心全部是在两个单独的步骤上开始独立于X轴上的移动来处理X轴上的移动。我在此答案中已经写过有关它的内容,因此请前往那里获取详细信息。

如果我没记错的话,其实际原因是这样的:

在此处输入图片说明


1
大卫总是在XNA上加油!
Gustavo Maciel'3

1
@ Gustavo-Gtoknu我觉得仍然需要解决这个问题:P
David Gouveia 2012年

1
刚遇到这个答案-太好了!谢谢大卫。
奥斯汀·布伦霍斯特

1

如果发生多次碰撞,如果您从每个涉及的矩形的中心开始,从最接近到最远的距离纠正碰撞,则不会出现“悬挂”的问题。

1)找到所有碰撞的矩形

2)如果有多个(取决于您的用例,这可能是频繁的也可能是不频繁的),请找到最接近的。

3)一次解决一个冲突,并检查其他冲突是否仍然有效

在公认的答案中,冲突和输入逻辑是泥泞的。它以检查的方式确定航向,等等。以上述方式实现它可以使冲突逻辑与输入逻辑保持分离,但在必要时会以计算距离为代价。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.