AABB碰撞造成的平台跳跃问题


9

首先参见图:

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

考虑“向左跳转”示例:

  • 如果力度X大于力度Y,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;
}

Answers:


2

我只是看了我没有尝试证明错误所在的代码。

我看了看代码,这两行似乎很奇怪:

if ((Position.X >= body.CornerMin.X && Position.X <= body.CornerMax.X) &&
(Position.Y + Height/2f == body.Position.Y - body.Height/2f))

您检查间隔,然后检查是否相等?我可能是错的(可能会进行som舍入),但似乎可能会造成麻烦。


0

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

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

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


更改速度不会解决任何问题,因为速度不受碰撞响应的影响。响应只是改变播放器的位置,而保持力度不变。当玩家撞到屋顶时,它会漂浮一段时间,然后又下降。这是因为我没有将Velocity设置为最高时设置为0。
— 维托里奥·罗密欧

如果删除在GetOverlapVector方法中将结果向量组件之一设置为零的代码,会发生什么情况?
— TravisG 2011年

该实体被斜向推出,有时甚至不能正常工作,而其他时候则只是像在网格上一样将其捕捉。
— 罗密欧

我现在无法理解。实体被推出的方式应取决于其与碰撞对象之间的距离,但是您的算法已经做到了。我明天再看。
— TravisG 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.