c# - 我怎样才能让我的碰撞更稳固?

标签 c# xna collision-detection tiles

我正在使用 XNA 在 C# 中开发游戏,并且由于 Nick Gravelyn 的教程,我一直在学习 C# 中的程序,但我遇到了障碍。当我使用 Nick 的碰撞系统时,我没有使用他的玩家代码。我使用的是基于我修改过的 Fatso784 的教程。因此,我无法使修改后的碰撞系统正常工作。我已经知道它会将玩家推出某些方 block ,但我需要它更坚固,因为玩家仍然可以偶尔穿过墙壁。我很确定我对碰撞的处理有误,但碰撞可能有点糊状。所以这是我的玩家类的相关代码,移动代码:

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

那么我怎样才能改善碰撞呢?

最佳答案

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

碰撞检测的诀窍 - “真正的”物理引擎执行此操作的方式 - 是始终将您的对象视为实体。您始终 - 每一帧 - 检查对象是否相互渗透,然后在它们相互渗透时分离它们。

如果您只测试移动越过对象的边界,您将错过碰撞。这包括您尝试通过捕捉到表面来预测和避免碰撞的任何方法。如果你这样做,你只是在要求浮点精度错误,让你溜进对象。

编辑: 当然,您的代码似乎都是基于整数的(PointRectangle)。所以至少浮点精度不应该成为问题。但也许你有一个 <你应该在哪里有一个<=或者类似的东西?

(此外,您在很多应该使用枚举的地方使用了字符串。)

关于c# - 我怎样才能让我的碰撞更稳固?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5987585/

相关文章:

c# - 正则表达式在 C# 上的正则表达式属性中不起作用

c# - 在 ASP.NET 单元测试中模拟 HttpContext.server.MapPath

c# - 集合已更改。未执行可能的盘点操作

c# - xna着色器的问题

javascript - Canvas 图像与侧面检测碰撞

c# - 将属性表单对象复制到另一个对象的扩展方法,第一次尝试

c# - Wpf Prism - 将参数从 View 传递到 View 模型

c# - Windows Phone 中的 XNA RenderTarget2D

python-2.7 - 游戏。有效检测与 Sprite 的线碰撞

algorithm - circle-AABB 包含测试