XNA系列教程 2D碰撞教程2:像素检测

 

2D碰撞教程2:像素检测

本教程详细讲解了像素碰撞检测的实现。

注意

这个教程的代码是在前一个教程:2D碰撞教程1:矩形检测中实现的,在进行下面的教程前请确保已经完成教程1的学习。

绪论

在前一个例子当中,你已经通过举行碰撞检测实现了一个躲避下落物体游戏。而矩形只是通过你加载的纹理贴图的大小来决定的,并不能准确的代表你的游戏角色的大小,因此在游戏当中你会发现出现一些误差。

例如,在这种情况下游戏角色并没有碰到下落的物体,但是背景却指示为游戏角色已经被下落的物体击中。这是由于在这种情况下两个纹理贴图出现了重合,而矩形的检测就认为两者已经产生了碰撞。

我们期望的情况应该如下图,在没有被下落物体击中,即便是纹理贴图相互重合也认为游戏角色没有被集中。

为了达到上述的目标,我们的代码必须能够做到只有在物体像素产生碰撞之后再响应碰撞,这个就叫做像素检测。

第一步:取得纹理数据

像素检测需要得到每一个纹理贴图的像素数据,为了访问每一个像素,我们必须调用Texture2D.GetData。通过这个方法你可以将纹理贴图的数据复制到你所定义的一个数组,当然数组的格式为默认的Color类型。

1.         首先,你需要在game类中为每一个贴图声明Color数组。

 

// The color data for the images; used for per-pixel collision
       
       
Color[] personTextureData;
       
       
Color[] blockTextureData;                                     
       
       

2.         之后,使用Texture2D.GetData方法将贴图中的每一个像素复制到你所定义的数组当中。当然,这一步必须当纹理贴图加载之后。在LoadGraphicsContent方法中添加下面粗体代码。

 

// Load textures
       
       
blockTexture = content.Load<Texture2D>("Content/Block");
       
       
personTexture = content.Load<Texture2D>("Content/Person");
       
       

      
      
       
        
      
      
// Extract collision data
        
        
blockTextureData =
        
        
    new Color[blockTexture.Width * blockTexture.Height];
        
        
blockTexture.GetData(blockTextureData);
        
        
personTextureData =
        
        
    new Color[personTexture.Width * personTexture.Height];
        
        
personTexture.GetData(personTextureData);                               
       
       

3.         对每一个纹理贴图你都需要分配一个color数组,这个数据是一维的,也就是说贴图的颜色数据会按照顺序依次存储到这个数组当中。一旦这个数组的空间被分配,那么GetData函数会将纹理贴图中的像素数据填充入这个数组当中。

第二步:像素检测的实现

现在你已经有了所需要的数据,那么根据这些数据你可以完成像素碰撞检测。这个方法首先需要一对纹理题图的包围矩形和他们的颜色数据。

1.         首先,将下面的方法添加到你的代码当中。

 

static bool IntersectPixels(Rectangle rectangleA, Color[] dataA,
       
       
                            Rectangle rectangleB, Color[] dataB)                                 
       
       

2.         这个方法主要包括两个部分,第一,他将识别出两个包围矩形的重合部分,这个重合区域也许存在,也许不存在。第二,这个方法会循环的检测重合区域的像素颜色,如果发现物体的像素产生了碰撞,那么这个方法将返回true,如果经过对像素的检测没有发现碰撞,那么将返回false

3.         将下面的代码添加到IntersectPixels方法当中。

 

// 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);                              
       
       

4.         这四个变量定义了矩形重合的区域。如果没有重合区域的话,right的值会小于left或者bottom的值会小于top,或者这两种情况同时存在。我们通过一个嵌套的for循环来自动判断是否有重合区域。

5.         将下面的代码依次添加如上面的方法。

 

// 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;
       
       
                        }
       
       
            }
       
       
}
       
       

      
      
       
        
      
      
// No intersection found
       
       
return false;
       
       

这个for循环会依照从左至右,从上到下的顺序读取每一个像素的颜色,我们需要将矩形的世界坐标转换为本地坐标。我们对本地坐标进行判断,如果两者都不是00代表透明)的话,那么则可以判断出现了碰撞。

注意

在教程1当中我们已经讲过纹理处理器会自动将洋红色转换为透明色。

第三步:调用像素碰撞检测

现在你已经完成了像素碰撞检测的方法,你需要在原有的举行碰撞的地方调用这个方法。

1.         Updata方法中修改代码如下。

 

// Update each block
       
       
personHit = false;
       
       
for (int i = 0; i < blockPositions.Count; i++)
       
       
{
       
       
            // Animate this block falling
       
       
            blockPositions[i] =
       
       
                        new Vector2(blockPositions[i].X,
       
       
                                                             blockPositions[i].Y + BlockFallSpeed);
       
       

      
      
       
        
      
      
            // Get the bounding rectangle of this block
       
       
            Rectangle blockRectangle =
       
       
                        new Rectangle((int)blockPositions[i].X, (int)blockPositions[i].Y,
       
       
                        blockTexture.Width, blockTexture.Height);
       
       

      
      
       
        
      
      
            // Check collision with person
        
        
            if (IntersectPixels(personRectangle,
        
        
                                                 personTextureData, personTexture.Width,
        
        
                                                 blockRectangle,
        
        
                                                 blockTextureData, blockTexture.Width))
        
        
            {
        
        
                        personHit = true;
        
        
            }
       
       

      
      
       
        
      
      
    // Remove this block if it has fallen off the screen
       
       
            if (blockPositions[i].Y > Window.ClientBounds.Height)
       
       
            {
       
       
                        blockPositions.RemoveAt(i);
       
       

      
      
       
        
      
      
                        // When removing a block, the next block will have the same index
       
       
                        // as the current block. Decrement i to prevent skipping a block.
       
       
                        i--;
       
       
            }
       
       
}                                     
       
       

2.         好了,编译并运行这个游戏。

恭喜你!

你现在已经掌握了像素碰撞检测的技能了。

Ideas to Expand扩展

提供一下内容作为扩展。

·                  增加下落物体的大小和样式。

·                  为游戏角色添加保护罩

·                  添加奖励物品

点击这里下载源码

© 2007 Microsoft Corporation. All rights reserved.
Send feedback to xna@microsoft.com.

© 2007 Vincent Zhang. 转载请注明 . 如果对翻译文章有疑问发送邮件至发送邮件至 vinile@163.com
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值