优化每像素碰撞

时间:2013-09-16 15:17:49

标签: c# optimization xna collision-detection

我一直在为学校项目开发自己的物理引擎,最近我遇到了一个问题:大精灵上的每像素碰撞使我的FPS下降了很多。

这是我的像素碰撞代码。在输入以下代码之前,我正在使用Intersects()来查看它们的边界框是否发生冲突。

private bool PerPixelCollision(IObject a, IObject b)
{

    Color[] bitsA = new Color[a.Texture.Width * a.Texture.Height];
    a.Texture.GetData(bitsA);
    Color[] bitsB = new Color[b.Texture.Width * b.Texture.Height];
    b.Texture.GetData(bitsB);

    // Calculate the intersecting rectangle
    int x1 = Math.Max(a.Bounds.X, b.Bounds.X);
    int x2 = Math.Min(a.Bounds.X + a.Bounds.Width, b.Bounds.X + b.Bounds.Width);

    int y1 = Math.Max(a.Bounds.Y, b.Bounds.Y);
    int y2 = Math.Min(a.Bounds.Y + a.Bounds.Height, b.Bounds.Y + b.Bounds.Height);

    Color c;
    Color d;
    // For each single pixel in the intersecting rectangle
    for (int y = y1; y < y2; ++y)
    {
        for (int x = x1; x < x2; ++x)
        {
            // Get the color from each texture
            c = bitsA[(x - a.Bounds.X) + (y - a.Bounds.Y) * a.Texture.Width];
            d = bitsB[(x - b.Bounds.X) + (y - b.Bounds.Y) * b.Texture.Width];

            if (c.A != 0 && d.A != 0) // If both colors are not transparent (the alpha channel is not 0), then there is a collision
            {
                return true;
            }
        }
    }
    // If no collision occurred by now, we're clear.
    return false;
}

在我用来测试的例子中,我在另一个代表地板的精灵中丢掉4个精灵(736x79)。当我将代表地板的精灵更改为更大的精灵(3600x270)时,FPS会下降。我知道问题在于像素碰撞,因为我正在使用分析器。

有没有人知道如何优化碰撞?

P.S。:如果我对我的问题不够清楚,请抱歉。我的英语不太好。

编辑:第一个问题是通过使用@pinckerman提供的解决方案解决的,但我发现另一个问题与像素碰撞检测有关。 当精灵与纹理的透明部分碰撞时,我们得到相交的部分并检查该部分的所有像素。问题是:当透明部分足够大以覆盖整个精灵时,我会检查该精灵的整个纹理(目前使用50x50纹理,即2500像素)。有没有办法不检查整个纹理?

由于

1 个答案:

答案 0 :(得分:2)

我很确定你的FPS下降太多,因为你正在做

Color[] bitsA = new Color[a.Texture.Width * a.Texture.Height];
a.Texture.GetData(bitsA);
Color[] bitsB = new Color[b.Texture.Width * b.Texture.Height];
b.Texture.GetData(bitsB);

在你方法的开头。
我想你每个PerPixelCollision循环调用Update并在每个游戏周期创建并处理数百万个值,这不是一件非常有效的事情。

一个大精灵会创建一个巨大的Color[]数组:你的数组越大,这个方法就越慢。

编辑:

对于你的第二个问题,我认为,如果你事先不知道“大”纹理的透明区域在哪里,你还是要检查整个精灵。
如果你的精灵不是太大而不是对性能的大肆浪费。

PS:我看到你自己得到了交叉的Rectangle,也许你会找到有用的this method