5

ダイアグラム

私のAABB物理エンジンが交差点を解決するとき、それは貫通が小さい軸を見つけて、その軸上のエンティティを「押し出す」ことによって解決します。

「左にジャンプする」例を考えてみましょう。

  • speedXがvelocityYより大きい場合、AABBはエンティティをY軸上に押し出し、ジャンプを効果的に停止します(結果:プレーヤーは空中で停止します)。
  • 速度Xが速度Yよりも小さい場合(図には示されていません)、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つだと思いますが、もちろんテストすることはできません。

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

ちなみに、ジャンプ中にプレイヤーが屋根にぶつかると、現在のコードはどうなりますか?

于 2011-06-20T21:03:08.917 に答える
0

私も同じ問題を抱えていました。Microsoftプラットフォーマースターターキットでさえそのバグがあるようです。

これまでに見つけた解決策は、マルチサンプリング(argh)を使用するか、オブジェクトの移動方向を使用することです。これら2つのオブジェクト間の距離のみを移動し、衝突が検出された場合はそれ以上移動しません(各軸に対して実行します)。

于 2011-08-07T17:48:10.303 に答える
0

私が見つけた1つの可能な解決策は、プレーヤーの速度に基づいて解決する前にオブジェクトを並べ替えることです。

于 2014-09-22T10:24:55.873 に答える