本文介绍了WindowsForms 的每像素碰撞检测算法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找 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 的每像素碰撞检测算法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-15 02:21