0

私は何日もこれについて頭を悩ませてきました。エンティティを更新するとき、衝突をチェックし、以下のコードに従って衝突する場合、適切なモーション値が 0 に設定されます。何らかの理由を除いて、このコードは右側の衝突をチェックするために機能しません。エンティティの前に高さ 2 の壁がある場合、エンティティはそれを無視します。ただ、その下を確認するとちゃんと動いているように見えますが、完全に止まってしまいます。

衝突コード:

    public static bool CollidesRight(Level level, Vector2 position, Vector2 motion, int width, int height)
    {
        Vector2 result = position + motion;
        int x1 = (int)(result.X / (float)Tile.TILE_WIDTH);
        int x2 = (int)((result.X + (float)width) / (float)Tile.TILE_WIDTH) + 1;
        int y1 = (int)(result.Y / (float)Tile.TILE_HEIGHT);
        int y2 = (int)((result.Y + (float)height) / (float)Tile.TILE_HEIGHT);
        AABB resultBB = new AABB(result, width, height);
        for (int i = x1; i < x2; i++)
        {
            for (int j = y1; j < y2; j++)
            {
                if (level.GetTileAt(i, j) != 0 && (Tile.TileList[level.GetTileAt(i, j)].IsSolid() || Tile.TileList[level.GetTileAt(i, j)].HasSolidTop()))
                {
                    AABB tile = new AABB(new Vector2(i * 64f, j * 64f), 64, 64);
                    Console.WriteLine(tile);
                    return resultBB.Intersects(tile);
                }
            }
        }
        return false;
    }

これが私のエンティティの更新コードです:

    public virtual void Tick()
    {
        lastMotion = motion;
        lastPosition = position;
        if (Collision.CollidesBottom(level, position, motion, width, height))
        {
            onGround = true;
        }
        else if(!Collision.CollidesBottom(level, position, motion, width, height))
        {
            onGround = false;
        }

        if (onGround && !isJumping)
        {
            motion.Y = 0f;
            fallDistance = 0;
        }
        else if(!onGround)
        {
            fallDistance++;
            motion.Y += gravity * (fallDistance * 0.005f);
        }

        if (isJumping)
        {
            timeJumping++;
            if (timeJumping > 32)
            {
                timeJumping = 0;
                isJumping = false;
            }
            else
            {
                motion.Y = -2.25f;
            }
        }

        position.Y += motion.Y;

        if (motion.X != 0)
        {
            if (motion.X < 0)
            {
                motion.X += friction;
            }
            if (motion.X > 0)
            {
                motion.X -= friction;
            }
        }

        if ((motion.X > 0 && Collision.CollidesRight(level, position, motion, width, height)) || (motion.X < 0 && Collision.CollidesLeft(level, position, motion, width, height)))
        {
            motion.X = 0f;
        }

        position.X += motion.X;



        //MoveEntity(motion);
    }
4

1 に答える 1

0

3 つのオプションがあります。

まず、編集 - これについては気にしないでください。コードを読み間違えました。衝突チェックは X モーションを使用して動作するため、衝突チェックを行う前に X モーションを追加する必要があると思います。実際のプレーヤーのモーションに追加したくない場合は、少なくとも潜在的なモーションを関数に渡します。それだけですべてが解決するかもしれません。しかし、別の問題があります。

第二に、私はそれが this oneであると確信しています。あなたの position.Y は、 OnGround bool が設定されているときに頻繁に Int に切り捨てられると思われます。つまり、最小値はユニット全体になり、次のユニットはユニット全体になります。そして、pastebin からの AABB コードで:

if (bb.max.Y <= min.Y || bb.min.Y >= max.Y)
    {
        return false;
    }

X 座標関連のコードが衝突を検出した場合でも、このコードは false を返します。2 つの独立したチェックで false を返すのではなく、衝突が発生した場合に関数が true を返すように、ここでロジックを変更する必要があります。

第 3 に、幅が 1 単位で、タイルも幅が 1 単位で、x=2 および position.x = 0.5 のブロックと、非常に小さな xMotion (またはまだ追加されていないもの、回答を参照) があると仮定します。 1):

(ブロック 0 の一部とブロック 1 の一部を占有するなど)

[。][ ][バツ]

x = 1 に到達したら停止します。障害物にぶつかるからです。しかし:

x1 = (int)(0.5) = 0
x2 = (int)(0.5 + 1) + 1 = 2

あなたのループ:

for (int i = x1; i < x2; i++)

ブロック 0 (空) をチェックし、次にブロック 1 (空) をチェックしてから停止し (i == x2 であるため)、ブロック 2 をチェックしません。それは

for (int i = x1; i <= x2; i++)

そうすれば、近づいてくる衝突を検出する際にすべてがうまく機能します。将来の CollidesTop 関数についても、おそらく同様のことを行う必要があります。

PS もちろん、これらの答えを一度に 1 つずつ試してください。:)

于 2012-08-18T19:41:30.957 に答える