1

我正在尝试在我的平台游戏中实现基本的(目前)碰撞检测。我有每个大小为 16 x 16 的瓷砖。字符大小为 32 x 32 像素,并有自己的边界框。现在,在我的 Tile 类中,我有一个 bool,isSolid。我的数组中的每个图块也有一个矩形用于它们各自的边界框。

我正在检查玩家和瓷砖之间是否存在交叉点:

if (player.GetBoundingBox().Intersects(map.tiles[(int)player.position.Y / 16,
(int)player.position.X / 16].bounds) && map.tiles[(int)player.position.Y / 16,  
(int)player.position.X / 16].isSolid) 
{
...
}

现在,我的问题是这是非常不准确的,因为我正在四舍五入。我现在累死了,我一生都无法弄清楚如何正确地做到这一点。解决这个问题的最佳方法是什么?

4

1 回答 1

1

好吧,这可能并不完全是“基本的”,它工作得非常好并且没有任何问题,因为它会计算 X 轴和 Y 轴分离,这种碰撞结构将在以后帮助你。(我从旧的 Platformer Starter 工具包代码切换到这个,这是非常错误的)

假设你已经有了重力方法,让我们开始吧。

这应该在您的下降和速度逻辑之后,它将看到需要检查哪些轴。

            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds; //If you havent already, get the elapsed time
            if (velocity.X != 0f)
            {
                Position += velocity.X * Vector2.UnitX * elapsed;
                HandleCollisions(CollisionDirection.Horizontal);
            }
            if (velocity.Y != 0f)
            {
                Position += velocity.Y * Vector2.UnitY * elapsed;
                HandleCollisions(CollisionDirection.Vertical);
            }

现在对于非常重要的 HandleCollisons 方法

        private void HandleCollisions(CollisionDirection direction)
        {
            // Get the player's bounding rectangle and find neighboring tiles.
            Rectangle bounds = player.GetBoundingBox();
            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)
                {
                   Rectangle tileBounds = Level.GetBounds(x, y);
                    // If this tile is collidable,
                    bool IsSolid = map.tiles[x,y].IsSolid;
                    Vector2 depth;
                    if (isSolid && TileIntersectsPlayer(BoundingRectangle, tileBounds, direction, out depth))
                    {

                            if ((collision == ItemCollision.Platform && movement.Y > 0))
                                continue;
                            isOnGround = true;
                            if (isSolid || isOnGround)
                            {
                                if (direction == CollisionDirection.Horizontal)
                                {
                                    position.X += depth.X;
                                }
                                else
                                {

                                    isOnGround = true;
                                    position.Y += depth.Y;
                                }
                            }


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

        }
        public static bool TileIntersectsPlayer(Rectangle player, Rectangle block, CollisionDirection direction, out Vector2 depth)
        {
            depth = direction == CollisionDirection.Vertical ? new Vector2(0, player.GetVerticalIntersectionDepth(block)) : new Vector2(player.GetHorizontalIntersectionDepth(block), 0);
            return depth.Y != 0 || depth.X != 0;
        }

就是为了那个!它会检测碰撞,但我们需要让它计算出碰撞后将玩家向后推的程度!您将需要这两种扩展方法。

public static float GetHorizontalIntersectionDepth(this Rectangle rectA, Rectangle rectB)
        {
            // Calculate half sizes.
            float halfWidthA = rectA.Width / 2.0f;
            float halfWidthB = rectB.Width / 2.0f;

            // Calculate centers.
            float centerA = rectA.Left + halfWidthA;
            float centerB = rectB.Left + halfWidthB;

            // Calculate current and minimum-non-intersecting distances between centers.
            float distanceX = centerA - centerB;
            float minDistanceX = halfWidthA + halfWidthB;

            // If we are not intersecting at all, return (0, 0).
            if (Math.Abs(distanceX) >= minDistanceX)
                return 0f;

            // Calculate and return intersection depths.
            return distanceX > 0 ? minDistanceX - distanceX : -minDistanceX - distanceX;
        }

        public static float GetVerticalIntersectionDepth(this Rectangle rectA, Rectangle rectB)
        {
            // Calculate half sizes.
            float halfHeightA = rectA.Height / 2.0f;
            float halfHeightB = rectB.Height / 2.0f;

            // Calculate centers.
            float centerA = rectA.Top + halfHeightA;
            float centerB = rectB.Top + halfHeightB;

            // Calculate current and minimum-non-intersecting distances between centers.
            float distanceY = centerA - centerB;
            float minDistanceY = halfHeightA + halfHeightB;

            // If we are not intersecting at all, return (0, 0).
            if (Math.Abs(distanceY) >= minDistanceY)
                return 0f;

            // Calculate and return intersection depths.
            return distanceY > 0 ? minDistanceY - distanceY : -minDistanceY - distanceY;
        }

请注意,您可能需要稍微修改一下,因为玩家的位置是左下角。对于垂直和水平,还需要一个碰撞枚举。请告诉我这是否缺少任何东西。

于 2012-12-29T14:30:19.630 回答