碰撞检测有问题

时间:2011-01-17 06:58:59

标签: c# debugging collision-detection

我遇到了这个问题,每当我触地时我的速度设置为0.这是因为我推动我的功能将我精确推向了边缘。因此,当我除以块的高度时,它仍然认为我在那个块上。当我跳到最右边的墙上时也会发生这种情况。

示例: 在坐标0,720和我的y = 723

上有一个块

723/5 = 144(向下舍入)

然后我被推到了720.但是当我再按块高度划分时,它仍然认为我正在接触720上的那块,直到让我们说725

720/5 = 144

我如何解决这个问题,我的意思是我知道问题是什么,但我看不出任何解决方法。

此外,当我没有跳跃并且精确地位于关卡的右边缘时,我可以通过向右走来穿过墙壁,但是一旦我跳过碰撞检测跳跃进入。

我不知道为什么以及如何发生最后一个问题,任何人都可以看看会发生什么。

代码:

void DoCollisions()
{
    onGround = false;
    Position.Y += Velocity.Y;
    Vector2 tileCollision = GetTileCollision();
    if (tileCollision.X != -1 || tileCollision.Y != -1)
    {
        onGround = true;
        Vector2 collisionDepth = CollisionRectangle.DepthIntersection(
            new Rectangle(
                tileCollision.X * World.tileEngine.TileWidth,
                tileCollision.Y * World.tileEngine.TileHeight,
                World.tileEngine.TileWidth,
                World.tileEngine.TileHeight
            )
        );
        Velocity.Y = 0;
        Position.Y += collisionDepth.Y;

    }

    Position.X += Velocity.X;
    tileCollision = GetTileCollision();
    if (tileCollision.X != -1 || tileCollision.Y != -1)
    {
        Vector2 collisionDepth = CollisionRectangle.DepthIntersection(
            new Rectangle(
                tileCollision.X * World.tileEngine.TileWidth,
                tileCollision.Y * World.tileEngine.TileHeight,
                World.tileEngine.TileWidth,
                World.tileEngine.TileHeight
            )
        );
        Velocity.X = 0;
        Position.X += collisionDepth.X;

    }
}

Vector2 GetTileCollision()
{
    int topLeftTileX = (int)(CollisionRectangle.TopLeft.X / World.tileEngine.TileWidth);
    int topLeftTileY = (int)(CollisionRectangle.TopLeft.Y / World.tileEngine.TileHeight);
    int BottomRightTileX = (int)(CollisionRectangle.DownRight.X / World.tileEngine.TileWidth);
    int BottomRightTileY = (int)(CollisionRectangle.DownRight.Y / World.tileEngine.TileHeight);

    for (int i = topLeftTileX; i <= BottomRightTileX; i++)
    {
        for (int j = topLeftTileY; j <= BottomRightTileY; j++)
        {
            if (World.tileEngine.TileIsSolid(i, j))
            {
                return new Vector2(i,j);
            }
        }
    }

    return new Vector2(-1,-1);
}

3 个答案:

答案 0 :(得分:4)

的实施策略一直移动,然后弹出,如果碰撞几乎可以保证是错误的,因为没有简单的方法来确保弹出代码将你弹回到你的位置本应该相撞。通常它会向其他方向弹射,因此会出现错误。

不仅仅是你:专业人士也会遇到这个问题。请参阅tasvideos.org,了解由 move-then-eject 策略引起的 Super Mario Bros 游戏中的collection of collision bugs

所以,不要这样做。找出确切的碰撞点,并尽可能地移动。如今计算机足够快。


您要求使用推荐的方法将字符与切片进行碰撞。那么,首先考虑你角色的一个动作步骤,比如说( dx dy ):

alt text

我夸大了距离以使示例变得有趣:通常你会发现与平铺尺寸相比,运动步骤相当小。

角色可能触及与角色命中框的扫掠路径相交的所有切片,如下面的阴影所示。使用Wu's line algorithm行的方法来查找这些图块。

alt text

按照点击时将图块按顺序排序:

alt text

角色碰撞的是编号最小的瓷砖。

答案 1 :(得分:0)

您是否尝试使用经过调整的y坐标?向上移动一个以进行计算。

答案 2 :(得分:0)

对于任何与我一样处理同样问题的人,我设法解决了这个问题,并认为使用我的代码的pastebin链接会很方便:http://pastebin.com/t8PdtDEK

将此添加到我的代码中:

        if (previousPos.X == Position.X)
            Velocity.X = 0;
        if (previousPos.Y == Position.Y)
            Velocity.Y = 0;

并将其添加到我的get碰撞方法中:

        if (CollisionRectangle.DownRight.Y % World.tileEngine.TileHeight == 0)
            BottomRightTileY -= 1;
        if (CollisionRectangle.DownRight.X % World.tileEngine.TileWidth == 0)
            BottomRightTileX -= 1;

它的作用是如果它精确地在边缘上减去1,所以它不会添加那个图块。

此外,pastebin上的链接不包含插值,以确保对象不会快速移动。

感谢所有人的帮助!