Проблемы с прыжками на платформе при столкновениях AABB - PullRequest
5 голосов
/ 20 июня 2011

Diagram

Когда мой физический движок AABB разрешает пересечение, он делает это путем нахождения оси, где проникновение меньше, а затем "выталкивает" объект на этой оси.

Рассматривая пример «прыжок движется влево»:

  • Если скорость X больше скорости Y, AABB выталкивает объект на ось Y, эффективно останавливая прыжок (результат: игрок останавливается в воздухе).
  • Если скорость X меньше скорости (не показано на диаграмме), программа работает, как и предполагалось, потому что AABB выталкивает объект на ось X.

Как я могурешить эту проблему?

Исходный код:

public void Update()
    {
        Position += Velocity;
        Velocity += World.Gravity;

        List<SSSPBody> toCheck = World.SpatialHash.GetNearbyItems(this);

        for (int i = 0; i < toCheck.Count; i++)
        {
            SSSPBody body = toCheck[i];
            body.Test.Color = Color.White;

            if (body != this && body.Static)
            {                   
                float left = (body.CornerMin.X - CornerMax.X);
                float right = (body.CornerMax.X - CornerMin.X);
                float top = (body.CornerMin.Y - CornerMax.Y);
                float bottom = (body.CornerMax.Y - CornerMin.Y);

                if (SSSPUtils.AABBIsOverlapping(this, body))
                {
                    body.Test.Color = Color.Yellow;

                    Vector2 overlapVector = SSSPUtils.AABBGetOverlapVector(left, right, top, bottom);

                    Position += overlapVector;
                }

                if (SSSPUtils.AABBIsCollidingTop(this, body))
                {                      
                    if ((Position.X >= body.CornerMin.X && Position.X <= body.CornerMax.X) &&
                        (Position.Y + Height/2f == body.Position.Y - body.Height/2f))
                    {
                        body.Test.Color = Color.Red;
                        Velocity = new Vector2(Velocity.X, 0);

                    }
                }
            }               
        }
    }

    public static bool AABBIsOverlapping(SSSPBody mBody1, SSSPBody mBody2)
    {
        if(mBody1.CornerMax.X <= mBody2.CornerMin.X || mBody1.CornerMin.X >= mBody2.CornerMax.X)
            return false;
        if (mBody1.CornerMax.Y <= mBody2.CornerMin.Y || mBody1.CornerMin.Y >= mBody2.CornerMax.Y)
            return false;

        return true;
    }
    public static bool AABBIsColliding(SSSPBody mBody1, SSSPBody mBody2)
    {
        if (mBody1.CornerMax.X < mBody2.CornerMin.X || mBody1.CornerMin.X > mBody2.CornerMax.X)
            return false;
        if (mBody1.CornerMax.Y < mBody2.CornerMin.Y || mBody1.CornerMin.Y > mBody2.CornerMax.Y)
            return false;

        return true;
    }
    public static bool AABBIsCollidingTop(SSSPBody mBody1, SSSPBody mBody2)
    {
        if (mBody1.CornerMax.X < mBody2.CornerMin.X || mBody1.CornerMin.X > mBody2.CornerMax.X)
            return false;
        if (mBody1.CornerMax.Y < mBody2.CornerMin.Y || mBody1.CornerMin.Y > mBody2.CornerMax.Y)
            return false;

        if(mBody1.CornerMax.Y == mBody2.CornerMin.Y)
            return true;

        return false;
    }
    public static Vector2 AABBGetOverlapVector(float mLeft, float mRight, float mTop, float mBottom)
    {
        Vector2 result = new Vector2(0, 0);

        if ((mLeft > 0 || mRight < 0) || (mTop > 0 || mBottom < 0))
            return result;

        if (Math.Abs(mLeft) < mRight)
            result.X = mLeft;
        else
            result.X = mRight;

        if (Math.Abs(mTop) < mBottom)
            result.Y = mTop;
        else
            result.Y = mBottom;

        if (Math.Abs(result.X) < Math.Abs(result.Y))
            result.Y = 0;
        else
            result.X = 0;

        return result;
    }

Ответы [ 3 ]

1 голос
/ 21 июня 2011

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

  1. До обнаружения столкновения сохраните скорость игроков во временную переменную.
  2. После того, как вы ответили на столкновение, проверьте, исправлена ​​ли позиция игроков X или Y
  3. Если позиция X была изменена, вручную сбросьте (как своего рода «безопасный сброс») скорость игрока Y до той, которая была у него до ответа.

Кстати, что происходит с вашим текущим кодом, когда ваши игроки попадают на крышу во время прыжков?

0 голосов
/ 22 сентября 2014

Одно из возможных решений, которое я нашел, - это сортировка объектов перед разрешением по скорости игрока.

0 голосов
/ 07 августа 2011

У меня была та же проблема.Похоже, что даже в стартовом пакете Microsoft для платформеров есть эта ошибка.

Решение, которое я нашел до сих пор, состоит в том, чтобы либо использовать мультисэмплинг (argh), либо использовать перемещенное направление объекта: перемещать только расстояние между этими двумя объектами и недалее при обнаружении столкновения (и сделать это для каждой оси).

...