XNA中关于2D图形像素碰撞

下面所介绍的例子是微软官方的一个例子,这里给出下载XNA官方2D像素碰撞例子的链接。

     在这个例子中没有涉及到什么新鲜的技术,主要是利用提取图像的像素,然后根据两张图像画布相交的范围构造一个小范围的矩形框,之后遍历此矩形框中的每一个像素点,判断当前遍历到的像素点的alpha值是否为零,若两张图片同一个像素点的alpha值同时不为零,则两张图片碰撞,反之则没有进行碰撞。好了,不罗嗦了,下面就展开介绍一下这个例子吧。

     这个例子比较简单,没有自己封装类,所有功能都是在PerPixelCollisionGame类中实现的,该类继承Game类。

     首先是定义一些常用的变量,这里找了几个主要的变量列了出来:

// 将要渲染的图片,一张是小人,一张是三角块
Texture2D personTexture;
Texture2D blockTexture;

// 这两个数组像素是用来存储小人的图片像素和三角块的图片像素
Color[] personTextureData;
Color[] blockTextureData;

//小人的坐标
Vector2 personPosition;

//小人的移动速度
const int PersonMoveSpeed = 5;

//创建一个坐标链表记录每一个三角块儿的坐标
List<Vector2> blockPositions = new List<Vector2>();

// 检测是否碰撞
bool personHit = false;

     下面就是PerPixelCollisionGame类的构造函数,在这个构造函数中主要是定义了小人的初始位置,并且为了不让小人跑出我们的视线,特意定义了一个所谓的安全边框即safeBounds

protected override void Initialize()
        {
            base.Initialize();
            Viewport viewport = graphics.GraphicsDevice.Viewport;
            safeBounds = new Rectangle(
                (int)(viewport.Width * SafeAreaPortion),
                (int)(viewport.Height * SafeAreaPortion),
                (int)(viewport.Width * (1 - 2 * SafeAreaPortion)),
                (int)(viewport.Height * (1 - 2 * SafeAreaPortion)));

            personPosition.X = (safeBounds.Width - personTexture.Width) / 2;
            personPosition.Y = safeBounds.Height - personTexture.Height;
        }

     接下来是加载所用到的图像,这里没有什么好说的

       /// <summary>
       /// 加载图像资源
       /// </summary>
       protected override void LoadContent()
       {
           // 加载图片,包括小人和三角块
           blockTexture = Content.Load<Texture2D>("Block");
           personTexture = Content.Load<Texture2D>("Person");

           //初始化三角块儿的像素数组大小
           blockTextureData =
               new Color[blockTexture.Width * blockTexture.Height];
           // 提取三角块图片像素
           blockTexture.GetData(blockTextureData);

           ///初始化小人的像素数组大小
           personTextureData =
               new Color[personTexture.Width * personTexture.Height];
           //提取小人图片像素
           personTexture.GetData(personTextureData);

           // 增加一个精灵画刷来渲染图片
           spriteBatch = new SpriteBatch(graphics.GraphicsDevice);
       }

      接下来是PerPixelCollisionGame类的Update方法,在这个方法中前半部分是对键盘输入的检测,以此来控制小人儿的左移和右移。接下来是随机生成一个三角块的初始位置,并把此位置添加到名为blockPositions的坐标链表中。其中personRectangle是定义了包含小人的一个矩形框,这个矩形框的宽度和高度是这个小人图片宽度和高度(其本质是图片画布的宽度和高度)。再接下来的这个for语句是这个例子的关键,不停的遍历整个三角块儿链表,判断是否有三角块与小人有像素碰撞,若有personHit返回true,否则返回false,这个for语句中的IntersectPixels方法实现了两个图片的像素碰撞功能,下面重点讨论一下这个方法:

                                           像素碰撞示意图

                    上图是两张图片相交构成的一个小矩形框(中间红色部分)

         static bool IntersectPixels(Rectangle rectangleA, Color[] dataA,
                                    Rectangle rectangleB, Color[] dataB)
        {
            // 根据两个矩形框相交而形成的一个小的矩形范围
            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);

            // 在这个小矩形框范围内从上倒下,从左到右检查每一个像素点的值,
            //并判断每一个像素点上两张图片的alpha的值是否同时等于零,以此来判
            //断两张图片是否产生像素碰撞
           for (int y = top; y < bottom; y++)

           {
               for (int x = left; x < right; x++)
               {
                   // 在同一点上获取两张图片的像素值
                   Color colorA = dataA[(x - rectangleA.Left) +
                                        (y - rectangleA.Top) * rectangleA.Width];
                   Color colorB = dataB[(x - rectangleB.Left) +
                                        (y - rectangleB.Top) * rectangleB.Width];

                   // 判断两张图片在同一像素点上alpha值是否同时为零
                   if (colorA.A != 0 && colorB.A != 0)
                   {
                       //相碰撞,返回真
                       return true;
                   }
               }
           }
           //没有碰撞,返回假
           return false;

       }

最后剩下渲染部分了:

protected override void Draw(GameTime gameTime)
{
    GraphicsDevice device = graphics.GraphicsDevice;

    // 若personHit为真值,则屏幕背景颜色改为红色,否则为矢车菊蓝色
    if (personHit)
    {
        device.Clear(Color.Red);
    }
    else
    {
        device.Clear(Color.CornflowerBlue);
    }

    spriteBatch.Begin();

    // 渲染小人                                                                                              spriteBatch.Draw(personTexture, personPosition, Color.White);

   // 渲染三角块的坐标链表渲染链表中的每一个三角块
    foreach (Vector2 blockPosition in blockPositions)
    spriteBatch.Draw(blockTexture, blockPosition, Color.White);

 

    spriteBatch.End();

    base.Draw(gameTime);
}

至此这个例子也就完成了,其中最重要的部分就是IntersectPixels方法了,这个方法完成了两张图片的像素碰撞的功能,这个例子的本质也就是判断两个图片相交的画布部分的alpha值,如果同时不为零就代表碰撞,反之则没有碰撞。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值