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.