AABB碰撞的平台跳跃问题

时间:2011-06-20 19:58:31

标签: c# collision-detection physics aabb

Diagram

当我的AABB物理引擎解析一个交叉点时,它通过找到穿透力较小的轴来实现,然后“推出”该轴上的实体。

考虑“向左跳跃”的例子:

  • 如果velocityX大于velocityY,则AABB将实体推出Y轴,有效地停止跳跃(结果:玩家在半空中停止)。
  • 如果velocityX小于velocitY(图中未显示),则程序按预期工作,因为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 个答案:

答案 0 :(得分:1)

很难读取其他人的代码,但我认为这是一种可能的(纯粹是头脑风暴的)解决方法,虽然我当然无法测试它:

  1. 在发生碰撞检测之前,将玩家速度保存到某个临时变量。
  2. 完成碰撞响应后,检查玩家X或Y位置是否已更正
  3. 如果X位置已经改变,手动重置(作为一种“安全重置”),玩家Y的速度为他在响应之前的速度。
  4. 顺便说一下,当你的玩家在跳跃时撞到屋顶时,你当前的代码会发生什么?

答案 1 :(得分:0)

我遇到了同样的问题。即使是微软的平台游戏初学者套件也似乎有这个错误。

我到目前为止找到的解决方案是使用多重采样(argh)或使用对象的移动方向:仅在检测到碰撞时移动这两个对象之间的距离而不再移动(并为每个轴执行此操作)

答案 2 :(得分:0)

我找到的一个可能的解决方案是在解析之前根据玩家的速度对对象进行排序。