我怎样才能让我的碰撞变得更加坚固?

时间:2011-05-13 05:30:02

标签: c# xna collision-detection tiles

我正在使用XNA在C#中进行游戏,我一直在学习C#中的程序,感谢Nick Gravelyn的教程,但我遇到了麻烦。当我使用尼克的碰撞系统时,我没有使用他的播放器代码。我正在使用一个基于Fatso784的教程,我已经修改过了。因此,我无法使我的碰撞系统的修改版本正常工作。我已经明白了它将玩家推出某些瓷砖,但我需要它更加坚固,因为玩家偶尔也能穿过墙壁。我很确定我正在处理碰撞错误,但可能是碰撞有点糊涂。所以这是我的播放器类的相关代码,移动代码:

public void Move()
    {
        pos.X = bounds.X;
        pos.Y = bounds.Y;

        offsetPos.X = bounds.Width;
        offsetPos.Y = bounds.Height;

        if (frameCount % delay == 0)
        {
            switch (direction)
            {
                case "stand":
                    if (sideCollide == "none")
                    {
                        Equalize(2);
                    }
                    else if (sideCollide == "left")
                    {
                        speed += 1f;
                    }
                    else if (sideCollide == "right")
                    {
                        speed -= 1f;
                    }
                    bounds.X += (int)speed;
                    if (frameCount / delay >= 8)
                        frameCount = 0;
                    srcBounds = new Rectangle(frameCount / delay * 64, 0, 64, 64);
                    break;
                case "left":
                    if (sideCollide != "left")
                    {
                        if (speed > -maxspeed)
                        {
                            speed -= acceleration;
                        }
                        else if (speed < -maxspeed)
                        {
                            speed -= acceleration;
                            speed += drag;
                            Equalize(2);
                        }
                        speed += friction;
                    }
                    bounds.X += (int)speed;
                    if (frameCount / delay >= 4)
                        frameCount = 0;
                    srcBounds = new Rectangle(frameCount / delay * 64, 64, 64, 64);
                    break;
                case "right":
                    if (sideCollide != "right")
                    {
                        if (speed < maxspeed)
                        {
                            speed += acceleration;
                        }
                        else if (speed > maxspeed)
                        {
                            speed += acceleration;
                            speed -= drag;
                            Equalize(2);
                        }
                        speed -= friction;
                    }
                    bounds.X += (int)speed;
                    if (frameCount / delay >= 4)
                        frameCount = 0;
                    srcBounds = new Rectangle(frameCount / delay * 64, 64, 64, 64);
                    break;
                case "up":
                    if (speed > -4 && speed < 4)
                        srcBounds.Y = 128;
                    else
                        srcBounds.Y = 64;
                    if (srcBounds.Y == 0 || srcBounds.Y == 128)
                    {
                        if (jumpCount < 2)
                        {
                            if (frameCount / delay >= 9)
                                frameCount = 0;
                        }
                        else if (jumpCount > 2 && jumpCount <= 10)
                        {
                            if (frameCount / delay > 3)
                                frameCount = 2 * delay;
                        }
                        else if (jumpCount > 10 && jumpCount <= 18)
                        {
                            if (frameCount / delay > 5)
                                frameCount = 4 * delay;
                        }
                        else if (jumpCount > 18)
                        {
                            if (frameCount / delay >= 9)
                                frameCount = 0;
                        }

                        srcBounds = new Rectangle(frameCount / delay * 64, 128, 64, 64);
                    }
                    else if (srcBounds.Y == 64)
                    {
                        if (frameCount / delay >= 4)
                            frameCount = 0;
                        if (jumpCount <= 10)
                            srcBounds = new Rectangle((frameCount / delay) / 2 * 64, 64, 64, 64);
                        else
                            srcBounds = new Rectangle(frameCount / delay * 64, 64, 64, 64);
                    }
                    if (jumpCount == 0)
                        startY = bounds.Y;
                    bounds = new Rectangle(bounds.X + (int)speed,
                        (jumpCount - 10) * (jumpCount - 10) - 100 + startY, 64, 64);
                    jumpCount++;
                    if (bounds.Y > startY)
                    {
                        bounds.Y = startY;
                        direction = "stand";
                        jumpCount = 0;
                    }
                    break;
            }
        }

        frameCount++;
    }

碰撞代码:

public void CollideOutside(TileMap tilemap)
    {
        Point cell = Engine.PointCell(PlayerCenter);

        Point? upLeft = null, Up = null, upRight = null, Right = null, downRight = null, Down = null, downLeft = null, Left = null;

        if (cell.Y > 0)
        {
            Up = new Point(cell.X, cell.Y - 1);
        }
        if (cell.Y < tilemap.collisionMap.HeightinPixels)
        {
            Down = new Point(cell.X, cell.Y + 1);
        }
        if (cell.X > 0)
        {
            Left = new Point(cell.X - 1, cell.Y);
        }
        if (cell.X < tilemap.collisionMap.WidthinPixels)
        {
            Right = new Point(cell.X + 1, cell.Y);
        }

        if (cell.X > 0 && cell.Y > 0)
        {
            upLeft = new Point(cell.X - 1, cell.Y - 1);
        }
        if (cell.X < tilemap.collisionMap.WidthinPixels - 1 && cell.Y > 0)
        {
            upRight = new Point(cell.X + 1, cell.Y - 1);
        }
        if (cell.X > 0 && cell.Y < tilemap.collisionMap.HeightinPixels - 1)
        {
            downLeft = new Point(cell.X - 1, cell.Y + 1);
        }
        if (cell.X < tilemap.collisionMap.WidthinPixels - 1 && cell.Y < tilemap.collisionMap.Height - 1)
        {
            downRight = new Point(cell.X + 1, cell.Y + 1);
        }

        if (Up != null && tilemap.collisionMap.GetCellIndex(Up.Value) == 1)
        {
            Rectangle rect = Engine.CreateCell(Up.Value);
            Rectangle playerCell = Boundary;

            if (rect.Intersects(playerCell))
            {

            }
        }
        if (Down != null && tilemap.collisionMap.GetCellIndex(Down.Value) == 1)
        {
            Rectangle rect = Engine.CreateCell(Down.Value);
            Rectangle playerCell = Boundary;

            if (rect.Intersects(playerCell))
            {

            }
        }
        if (Right != null && tilemap.collisionMap.GetCellIndex(Right.Value) == 1)
        {
            Rectangle rect = Engine.CreateCell(Right.Value);
            Rectangle playerCell = Boundary;

            if (rect.Intersects(playerCell))
            {
                speed = -1f;
                sideCollide = "right";
            }
            else
            {
                sideCollide = "none";
            }
        }
        if (Left != null && tilemap.collisionMap.GetCellIndex(Left.Value) == 1)
        {
            Rectangle rect = Engine.CreateCell(Left.Value);
            Rectangle playerCell = Boundary;

            if (rect.Intersects(playerCell))
            {
                speed = 1f;
                sideCollide = "left";
            }
            else
            {
                sideCollide = "none";
            }
        }
        if (upLeft != null && tilemap.collisionMap.GetCellIndex(upLeft.Value) == 1)
        {
            Rectangle rect = Engine.CreateCell(upLeft.Value);
            Rectangle playerCell = Boundary;

            if (rect.Intersects(playerCell))
            {

            }
        }
        if (upRight != null && tilemap.collisionMap.GetCellIndex(upRight.Value) == 1)
        {
            Rectangle rect = Engine.CreateCell(upRight.Value);
            Rectangle playerCell = Boundary;

            if (rect.Intersects(playerCell))
            {

            }
        }
        if (downLeft != null && Left != null && tilemap.collisionMap.GetCellIndex(downLeft.Value) == 1)
        {
            Rectangle rect = Engine.CreateCell(downLeft.Value);
            Rectangle playerCell = Boundary;

            if (rect.Intersects(playerCell))
            {
                speed = 1f;
                sideCollide = "left";
            }
        }
        if (downRight != null && Right != null && tilemap.collisionMap.GetCellIndex(downRight.Value) == 1)
        {
            Rectangle rect = Engine.CreateCell(downRight.Value);
            Rectangle playerCell = Boundary;

            if (rect.Intersects(playerCell))
            {
                speed = -1f;
                sideCollide = "right";
            }
        }

        if (Right == null && Left == null)
        {
            sideCollide = "none";
        }
    }

    public Rectangle Boundary
    {
        get
        {
            Rectangle rect = bounds;
            rect.X = (int)pos.X;
            rect.Y = (int)pos.Y;
            return rect;
        }
    }

那我怎样才能改善碰撞?

1 个答案:

答案 0 :(得分:1)

这个答案主要是为了回应蒂姆的答案 - 因为他给出了非常错误的方法。 (你的问题是一个非常大的代码转储,我无法真正发挥这么多代码的错误。)

碰撞检测的技巧 - “真正的”物理引擎的做法 - 是始终将对象视为实体。你总是 - 每一帧 - 检查对象的互穿性,然后分开,如果它们相互渗透。

如果您只测试移动对象的边界,那么 会错过碰撞。这包括您尝试通过捕捉到表面来预测和避免碰撞的任何方法。如果你这样做,你只需要浮点精度错误就可以让你在对象中滑动。

编辑:当然,您的代码似乎都是基于整数的(PointRectangle)。所以至少浮点精度应该不是问题。但也许你有一个<你应该有一个<=或者其他什么呢?

(你也在很多地方使用字符串,你应该使用枚举。)