Как я могу сделать свое столкновение более твердым? - PullRequest
7 голосов
/ 13 мая 2011

Я работаю над игрой на C # с XNA и изучаю программу на C # благодаря учебникам Ника Грейвлина, но я столкнулся с проблемой. Пока я использую систему столкновений Ника, я не использую его код игрока. Я использую тот, который основан на учебнике от 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 Ответ

1 голос
/ 13 мая 2011

Этот ответ в основном является ответом на ответ Тима - потому что он дал очень неправильный подход. (Ваш вопрос - очень большой дамп кода, я действительно не могу воспроизвести точную ошибку с таким большим количеством кода.)

Хитрость с обнаружением столкновений - то, как это делают «настоящие» физические движки, - это всегда обрабатывать ваши объекты как твердые тела. Вы всегда - каждый кадр - проверяете объекты на проникновение, а затем отделяете их, если они проникают.

Если вы тестируете только перемещение через границу объекта, вы собираетесь пропустить столкновения. Это включает любой подход, в котором вы пытаетесь предсказать и избежать столкновения, привязываясь к поверхности. Если вы делаете это, вы просто запрашиваете ошибки точности с плавающей точкой, чтобы позволить вам скользить внутри объектов.

РЕДАКТИРОВАТЬ: конечно, ваш код, кажется, все целочисленные (Point и Rectangle). Так что, по крайней мере, точность с плавающей точкой не должна быть проблемой. Но, может быть, у вас есть <, где вы должны иметь <= или что-то в этом роде?

(Также вы используете строки во многих местах, где вы очень часто должны использовать перечисления.)

...