Pixel Collision Detection Algorithm for WindowsForms
I am looking for a per pixel collision detection algorithm / method for Windows Forms .
I searched for it, but I found it for XNA only (as you could see below). Isn't such an algorithm consistent with the Windows Forms concept ?!
/// <summary>
/// Determines if there is overlap of the non-transparent pixels
/// between two sprites.
/// </summary>
/// <param name="rectangleA">Bounding rectangle of the first sprite</param>
/// <param name="dataA">Pixel data of the first sprite</param>
/// <param name="rectangleB">Bouding rectangle of the second sprite</param>
/// <param name="dataB">Pixel data of the second sprite</param>
/// <returns>True if non-transparent pixels overlap; false otherwise</returns>
static bool IntersectPixels(Rectangle rectangleA, Color[] dataA,
Rectangle rectangleB, Color[] dataB)
{
// Find the bounds of the rectangle intersection
int top = Math.Max(rectangleA.Top, rectangleB.Top);
int bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom);
int left = Math.Max(rectangleA.Left, rectangleB.Left);
int right = Math.Min(rectangleA.Right, rectangleB.Right);
// Check every point within the intersection bounds
for (int y = top; y < bottom; y++)
{
for (int x = left; x < right; x++)
{
// Get the color of both pixels at this point
Color colorA = dataA[(x - rectangleA.Left) +
(y - rectangleA.Top) * rectangleA.Width];
Color colorB = dataB[(x - rectangleB.Left) +
(y - rectangleB.Top) * rectangleB.Width];
// If both pixels are not completely transparent,
if (colorA.A != 0 && colorB.A != 0)
{
// then an intersection has been found
return true;
}
}
}
The problem with this is that I don't know how to initialize the Color [] arrays.
0
source to share
1 answer
Below is the adaptation to work with regular Winforms GDI+ Bitmaps & Lockbits
:
static bool IntersectPixels(Rectangle rectangleA, Bitmap bmpA,
Rectangle rectangleB, Bitmap bmpB)
{
bool collision = false;
Size s1 = bmpA.Size;
Size s2 = bmpB.Size;
PixelFormat fmt1 = bmpA.PixelFormat;
PixelFormat fmt2 = bmpB.PixelFormat;
Rectangle rect = new Rectangle(0, 0, s1.Width, s1.Height);
Rectangle rectB = new Rectangle(0, 0, s2.Width, s2.Height);
BitmapData bmp1Data = bmpA.LockBits(rect, ImageLockMode.ReadOnly, fmt1);
BitmapData bmp2Data = bmpB.LockBits(rectB, ImageLockMode.ReadOnly, fmt2);
int size1 = bmp1Data.Stride * bmp1Data.Height;
int size2 = bmp2Data.Stride * bmp2Data.Height;
byte[] data1 = new byte[size1];
byte[] data2 = new byte[size2];
System.Runtime.InteropServices.Marshal.Copy(bmp1Data.Scan0, data1, 0, size1);
System.Runtime.InteropServices.Marshal.Copy(bmp2Data.Scan0, data2, 0, size2);
// Find the bounds of the rectangle intersection
int top = Math.Max(rectangleA.Top, rectangleB.Top);
int bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom);
int left = Math.Max(rectangleA.Left, rectangleB.Left);
int right = Math.Min(rectangleA.Right, rectangleB.Right);
// Check every point within the intersection bounds
for (int y = top; y < bottom; y++)
{
for (int x = left; x < right; x++)
{
// Color data are BGRA!
// Get the alpha (+3!) value of both pixels at this point
byte colorA = data1[(x - rectangleA.Left) +
(y - rectangleA.Top) * rectangleA.Width + 3];
byte colorB = data2[(x - rectangleB.Left) +
(y - rectangleB.Top) * rectangleB.Width + 3];
// If both pixels are not completely transparent,
if (colorA != 0 && colorB != 0)
{
// then an intersection has been found
{ collision = true; goto done; }
}
}
}
done:
bmpA.UnlockBits(bmp1Data);
bmpB.UnlockBits(bmp2Data);
return collision;
}
To check for collision with a fully opaque rectangle, the code can be greatly simplified. You only skip the bounds ( RectangleB
) of that object:
static bool IntersectPixels(Rectangle rectangleA, Bitmap bmpA, Rectangle rectangleB)
{
bool collision = false;
Size s1 = bmpA.Size;
Rectangle rect = new Rectangle(0, 0, s1.Width, s1.Height);
rectangleB.Intersect(rectangleA);
BitmapData bmp1Data = bmpA.LockBits(rect, ImageLockMode.ReadOnly, bmpA.PixelFormat);
int size1 = bmp1Data.Stride * bmp1Data.Height;
byte[] data1 = new byte[size1];
System.Runtime.InteropServices.Marshal.Copy(bmp1Data.Scan0, data1, 0, size1);
// Check every point within the intersection bounds
for (int y = rectangleB.Top; y < rectangleB.Bottom; y++)
{
for (int x = rectangleB.Left; x < rectangleB.Right; x++)
{
// Get the alpha value of both pixels at this point
byte colorA = data1[(x - rectangleA.Left) +
(y - rectangleA.Top) * rectangleA.Width + 3];
// If a non-tranparent pixel
if (colorA != 0 ) { collision = true; goto done; }
}
}
done:
bmpA.UnlockBits(bmp1Data);
return collision;
}
I've done some testing, but I'm not entirely sure if I'm missing something. Please come back with any bugs you find!
+2
source to share