I'm been developing my own physics engine for a school project and recently I encountered a problem: Per pixel collisions on big sprites make my FPS drop A LOT.
Here's my pixel collision code. Before entering the following code I'm using Intersects()
to see if their bounding boxes collided.
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;
}
In the example I'm using to test I'm dropping 4 sprites in another sprite that represents the floor (736x79). When I change the sprite that represents the floor to a bigger sprite (3600x270) the FPS drops. I know the problem is in the pixel collision because I'm using a profiler.
Does anyone have any idea on how to optimize the collision?
P.S.: Sorry if I wasn't clear enough about my problem. My english is not so good.
EDIT: The first problem was solved by using the solution provided by @pinckerman but I found another one related to pixel collision detection. When a sprite collide with a the transparent part of a texture, we get the part that intersected and check all the pixels of that part. The problem is: When the transparent part is big enough to cover the whole sprite, I check the whole texture of that sprite (currently using 50x50 textures which is 2500 pixels). Is there any way to not check the whole texture?
Thanks
GetData()
on a texture stalls the rendering pipeline, which prevents the GPU and CPU from working together at maximum efficiency. In most cases it's going to be better to use geometric collision detection--though of course, there's nothing wrong with this sort of thing as a learning exercise. See this article for more information. – Cole Campbell