5

图表

当我的 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;
    }
4

3 回答 3

1

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

  1. 在碰撞检测发生之前,将玩家速度保存到某个临时变量。
  2. 完成碰撞响应后,检查玩家的 X 或 Y 位置是否已更正
  3. 如果 X 位置已经改变,手动重置(作为一种“安全重置”)玩家的 Y 速度到他响应之前的速度。

顺便说一句,当您的玩家在跳跃时撞到屋顶时,您当前的代码会发生什么?

于 2011-06-20T21:03:08.917 回答
0

我有同样的问题。甚至 Microsoft 平台游戏 starterskit 似乎也有这个错误。

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

于 2011-08-07T17:48:10.303 回答
0

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

于 2014-09-22T10:24:55.873 回答