【问题标题】:C# / XNA - 2D collision engine glitch?C#/XNA - 2D 碰撞引擎故障?
【发布时间】:2012-03-17 18:13:14
【问题描述】:

我这里有很多代码,但是比较简单。

这都是来自不同类的所有 sn-ps,所有引用都是正确的,但我想我在某处犯了一个基于数学的错误,我找不到它。它总是在 y 轴上发现一个像素之前的碰撞。我还没有尝试过使用不同的 X 轴位置,但它似乎可以通过它旁边的块。

结构“mapSection”只包含两个Vector2s-左上块和左下块坐标。

tileManager.def_ts 是默认的 tile 宽度和高度 (32)。播放器的尺寸为 32x64。

toWorldSpace 函数现在除了返回之外什么都不做,所以这不是问题。

当我说块坐标时,我的意思是块在图块数组中的哪个索引(例如 0、0 是第一个块,0、1 是 Y 轴上的第二个块,1、3 是第一个块在X轴和Y轴上的3,我不是指实际像素。)

来自磁贴引擎类:

    public mapSection toMapMinMax(Vector2 position, Vector2 size)
    {
        position = toWorldSpace(position);

        position.X = (float)Math.Floor(position.X / tileManager.def_ts);
        position.Y = (float)Math.Floor(position.Y / tileManager.def_ts);

        size.X = (float)Math.Floor(size.X / tileManager.def_ts);
        size.Y = (float)Math.Floor(size.Y / tileManager.def_ts);

        return new mapSection(position, position + size);
    }

    public bool collision(Vector2 screenPosition, Vector2 size)
    {
        mapSection mapCollisionPossibilities = toMapMinMax(screenPosition, size);

        for (int y = (int)mapCollisionPossibilities.topLeft.Y; y <= mapCollisionPossibilities.bottomRight.Y; y++)
        {
            for (int x = (int)mapCollisionPossibilities.topLeft.X; x <= mapCollisionPossibilities.bottomRight.X; x++)
            {
                if (x >= 0 && y >= 0 && y < tiles.Count && x < tiles[y].Count)
                {
                    if (tileManager.tileTypes[tiles[y][x]].collideable == true)
                    {
                        return true;
                    }
                }
            }
        }

        return false;
    }

这是播放器类的代码:

        if (!tEngine.collision(position + new Vector2(0, 1), new Vector2(32, 64)))
        {
            position.Y += 1;
        }

我添加了“Vector2(0, 1)”,因为我想看看在更下方的像素是否存在碰撞;这样他就会跌倒,直到撞到什么东西。它现在非常基本,但它只是为了测试碰撞引擎,它不起作用。

有错误的图片。你可以看到播放器的像素太高了。

图中“X:”为X轴左上块坐标,“X2:”为X轴右下块坐标,与“Y:”和“Y2:”相同,除了Y 轴。直接从 mapSection 中读取。

如果有人能注意到为什么会发生这种情况,我们将不胜感激。

谢谢。

如果您无法理解代码的任何部分,请在 cmets 中发布,我会很乐意解释,或者如果您认为我在这篇文章的某些方面过于不具体。

【问题讨论】:

  • 这个问题本质上只是视觉问题,还是数字也相差 1?这可能是由许多原因引起的,包括图形图像有额外的行、不减去 1 的高度计算、应该是
  • toMapMinMax 会过早返回下一个图块一个像素,这可能是一个舍入问题。随着 Y 值的增加,您需要逐步执行 toMapMinMax,并确认它每次都返回正确的图块坐标。
  • 在 toMapMinMax 中,您可能应该在执行计算之前对位置和大小进行舍入,方法是转换为整数或使用 Math.Round
  • 您的碰撞代码和绘制代码必须采用不同的舍入方式。即使您的碰撞代码关闭了一个像素,您也不会注意到您的绘制代码是否也关闭了。要么你碰撞得太快,要么你画得太高了。 (可能)
  • “我只在位置上加 1”浮点数不保证那么准确。例如,您可以添加 18 + 1,得到 18.99999999999。 Math.Floor 会将其变为 18,而您的绘制代码可能会绘制为 19。

标签: c# xna collision-detection


【解决方案1】:

编辑:对于瓦片坐标问题,您的 toMapMinMax 代码应该更像这样:

EDIT2:已从 bottomRight 中减去 (1, 1),因为它是我们要添加的大小。

public mapSection toMapMinMax(Vector2 position, Vector2 size)
{
    Vector2 topLeft = position;
    Vector2 bottomRight = position + size - new Vector2(1, 1);

    topLeft.X = (float)Math.Floor(topLeft.X / tileManager.def_ts);
    topLeft.Y = (float)Math.Floor(topLeft.Y / tileManager.def_ts);
    bottomRight.X = (float)Math.Floor(bottomRight.X / tileManager.def_ts);
    bottomRight.Y = (float)Math.Floor(bottomRight.Y / tileManager.def_ts);

    return new mapSection(topLeft, bottomRight);
}

另外,我的上述评论是错误的;您确实希望在两个 for 循环中使用

对于偏离一个像素的问题:

为了让您看到角色偏离一定数量的像素,绘制代码和碰撞代码必须不同。如果它们是相同的,例如如果它们都偏离了 15 个像素(您过早地碰撞了 15 个像素,但您也提前了 15 个像素),您将看不到任何变化。

1 像素间隙表示绘制坐标计算和碰撞坐标计算之间存在 1 个像素的差异。这 1 个像素的差异很可能是由舍入差异引起的,可能是您在碰撞代码中调用 Math.Floor,但未对绘图代码中的坐标进行舍入。 (我猜你可能只是将位置 Vector2 直接传递给 SpriteBatch.Draw 方法)。

【讨论】:

  • 但是地板只会把它画高 1 像素还是在同一个地方?
  • 你在 OP 中看到我最近的评论了吗?
  • 仍然是同样的问题,似乎与我原来的例子给出了相同的结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多