【问题标题】:Collisions detection bugged碰撞检测被窃听
【发布时间】:2011-06-10 06:59:47
【问题描述】:

我遇到了这个问题,每当我触地时,我的速度都会设置为 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);
}

【问题讨论】:

标签: c# debugging collision-detection


【解决方案1】:

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

不只是你:专业人士也会遇到这个问题。在 Super Mario Bros 游戏中,请访问 tasvideos.org,查看由这种 move-then-eject 策略引起的 collection of collision bugs

所以,不要那样做。计算出确切的碰撞点并仅移动到该点。如今,计算机的速度已经足够快了。


您要求推荐一种将角色与瓷砖碰撞的方法。好吧,首先考虑角色的单步运动,例如 (dx, dy):

我夸大了距离以使示例变得有趣:通常您会期望运动步长与图块大小相比相当小。

角色可能会接触到与角色命中框的扫过路径相交的所有图块,如下图阴影所示。使用类似于Wu's line algorithm 的方法来查找这些图块。

按被击中的时间对图块进行排序:

角色与编号最小的实心图块发生碰撞。

【讨论】:

  • 那么你会推荐什么其他方法,我只做过简单的项目,最多需要使用边界框和轨迹进行非旋转碰撞检测。向下追踪,检查距离下一个实心块有多远,如果空间更小,那么角色想要将它移动尽可能小的距离?
  • 如果我继续使用它,然后如果距离更大,那么最大步长会不断更新最大步长,直到到达目的地。我仍然不知道如何修复我目前使用的算法:(
  • 我不明白你所说的“最大步长”是什么意思。
  • 假设角色尝试水平移动 100 像素,但我将最大步进距离设置为 5 像素,然后我的游戏将模拟 20 步 5 像素以确保碰撞检测不会失败
  • 在我推荐的方法中,没有必要设置最大步长,因为将考虑扫过路径上的所有图块。
【解决方案2】:

您是否尝试过使用调整后的 y 坐标?上移一个仅用于计算。

【讨论】:

  • 但是如果这会将角色移动到他上方的另一个图块中怎么办。而且这个错误也发生在屏幕的右边缘,如果你走进它,它会说你正在碰撞,即使你没有
  • 另外,如果需要更多数据,请询问,我会发布!
【解决方案3】:

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

将此添加到我的代码中:

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

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

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

它的作用是如果它恰好在边缘上减去 1,那么它就不会添加该图块。

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

感谢大家的帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    • 2019-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多