AABBの衝突によるプラットフォームジャンプの問題


9

最初に図を参照してください。

私の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;
}

回答:


2
  • まだ行っていない場合は、すべてのサポート機能(2番目のコードリスト)をテストします。
  • これらのオブジェクトの動作を視覚化または標準出力に出力します。各コードが何をしているか、そしてそれが完全にそれをすることをあなたが知っていることを確認してください。
  • 衝突http://www.flipcode.com/archives/Theory_Practice-Issue_01_Collision_Detection.shtmlに関する多くの洞察があります

どこが間違っているかを証明しようとしていないコードを見ただけです。

私はコードを見て、これらの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つだと思いますが、もちろんそれをテストすることはできません。

  1. 衝突検出が発生する前に、プレイヤーの速度を一時的な変数に保存します。
  2. 衝突応答を行った後、プレーヤーのXまたはYの位置が修正されているかどうかを確認します
  3. X位置が変更されている場合は、プレーヤーのY速度を応答前の速度に手動でリセットします(一種の「安全リセット」として)。

ところで、ジャンプ中にプレイヤーが屋根にぶつかったとき、現在のコードはどうなりますか?


速度は衝突応答の影響を受けないため、速度を変更しても何も解決されません。応答はプレーヤーの位置を変更するだけで、速度は変更されません。プレイヤーが屋根にぶつかると、しばらく浮いてから降りてきます。天井にぶつかったときにVelocityを0に設定しないので、これは意図されています。
Vittorio Romeo

GetOverlapVectorメソッドで結果ベクトルコンポーネントのいずれかをゼロに設定するコードを削除するとどうなりますか?
TravisG

エンティティは斜めに押し出されます。時々、それは正しく機能しないこともあり、グリッド上にあるかのようにスナップすることもあります。
Vittorio Romeo

今はわかりません。エンティティが押し出される方法は、衝突するボディからの距離に依存する必要がありますが、アルゴリズムはすでにそうしています。明日もう一度見ます。
TravisG 2011年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.