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 运动,因为碰撞检查使用它来工作。如果您不想将其添加到实际的玩家动作中,至少将潜在动作传递给函数。仅此一项就可以解决所有问题。但还有另一个问题。

其次,我很确定是这个,我怀疑你的 position.Y 在设置 OnGround 布尔值时经常被截断为 Int 。这意味着它的最小值将是一个完整的单元,而下一个单元将是一个完整的单元。在 pastebin 的 AABB 代码中:

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

即使 X 坐标相关代码检测到碰撞,此代码也会返回 false。您应该修改此处的逻辑,以便函数在发生冲突时返回 true,而不是在两次独立检查时返回 false

第三,假设您的宽度为 1 个单位,并且您的图块也是 1 个单位宽,在 x=2 和 position.x = 0.5 处有一个块,以及一个非常小的 xMotion(或尚未添加的一个,请参阅答案1):

(占用一些块 0 和一些块 1,像这样)

[。][ ][X]

当你击中 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 当然,一次一个地尝试这些答案。:)

于 2012-08-18T19:41:30.957 回答