播放器和磁贴之间的碰撞检测

时间:2012-12-29 12:10:29

标签: c# xna

我正在尝试将基本(现在)碰撞检测实现到我的平台游戏中。我有每个尺寸为16 x 16的瓷砖。字符大小为32 x 32像素,并有自己的边界框。现在,在我的Tile课程中,我有一个bool,isSolid。我的数组中的每个tile都有一个矩形用于各自的边界框。

我正在检查播放器和磁贴之间是否有交叉点:

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) 
{
...
}

现在,我的问题是,这是非常不准确的,因为我正在完成这个职位。我现在很累,为了我的生活,我无法弄清楚如何正确地做到这一点。解决这个问题的最佳方法是什么?

1 个答案:

答案 0 :(得分:1)

这可能不完全是“基本的”,它工作得非常好并且没有任何问题,因为它计算X轴和Y轴seperatley,这种碰撞结构将在以后帮助你。 (我从旧的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;
        }

就是这样!它会检测到collisons,但是我们需要让它知道一旦碰撞就将玩家推回多少!您将需要这两种扩展方法。

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;
        }

注意你可能需要稍微修改一下,因为玩家位置是左边的BOTTOM。对于垂直和水平,还需要碰撞枚举。请告诉我这是否有任何遗漏。