问题描述
我正在寻找 Windows 窗体 的每像素碰撞检测算法/方法.
I´m searching for a per pixel collision detection algorithm/ method for Windows Forms.
我已经搜索过了,但我只找到了一个 XNA(如下所示).这样的算法是不是很符合 Windows Forms 的概念?!
I have searched for it but I only find one for XNA (as you could see below).Isn´t such an algorithm agreeable with the concept of Windows Forms?!
/// <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;
}
}
}
那个问题是,我不知道如何初始化 Color[] 数组.
The Problem with that one is, that I don´t know how to initialize the Color[] Arrays.
推荐答案
这是一个适用于常规 Winforms GDI+ Bitmaps &锁位
:
Here is a adaption 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;
}
为了检查与完全不透明矩形的碰撞,可以大大简化代码.您只传递该对象的边界 (RectangleB
):
For checking a collision with a fully non-transparent rectangle the code can be simplified greatly. You pass only 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 have done some testing, but I'm not quite sure if I missed something.. Please come back with any errors you find!
这篇关于WindowsForms 的每像素碰撞检测算法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!