[翻译]XNA系列教程 2D碰撞教程2:像素检测

news/2024/6/18 19:14:51

PS:转自__Vincent Zhang__的文章

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

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

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

绪论
      在前一个例子当中,你已经通过举行碰撞检测实现了一个躲避下落物体游戏。而矩形只是通过你加载的纹理贴图的大小来决定的,并不能准确的代表你的游戏角色的大小,因此在游戏当中你会发现出现一些误差。例如,在这种情况下游戏角色并没有碰到下落的物体,但是背景却指示为游戏角色已经被下落的物体击中。这是由于在这种情况下两个纹理贴图出现了重合,而矩形的检测就认为两者已经产生了碰撞。
     我们期望的情况在没有被下落物体击中,即便是纹理贴图相互重合也认为游戏角色没有被集中。
    为了达到上述的目标,我们的代码必须能够做到只有在物体像素产生碰撞之后再响应碰撞,这个就叫做像素检测。

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

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

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

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

1  //  Load textures
2  blockTexture  =  content.Load < Texture2D > ( " Content/Block " );
3  personTexture  =  content.Load < Texture2D > ( " Content/Person " );
4  //  Extract collision data
5  blockTextureData  =      new  Color[blockTexture.Width  *  blockTexture.Height];
6  blockTexture.GetData(blockTextureData);personTextureData  =      new  Color[personTexture.Width  *  personTexture.Height];
7  personTexture.GetData(personTextureData);

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

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

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

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

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

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

ContractedBlock.gif ExpandedBlockStart.gif Code
// 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. 将下面的代码依次添加如上面的方法。

ContractedBlock.gif ExpandedBlockStart.gif Code
// 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;                        
       }            
    }

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

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

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

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

ContractedBlock.gif ExpandedBlockStart.gif Code
 1 // Update each block
 2 personHit = false;for (int i = 0; i < blockPositions.Count; i++)
 3 {            
 4     // Animate this block falling            
 5     blockPositions[i] =new Vector2(blockPositions[i].X,blockPositions[i].Y + BlockFallSpeed);            
 6     // Get the bounding rectangle of this block            
 7     Rectangle blockRectangle =new Rectangle((int)blockPositions[i].X, (int)blockPositions[i].Y,blockTexture.Width, blockTexture.Height);             
 8     // Check collision with person            
 9     if (IntersectPixels(personRectangle, personTextureData, personTexture.Width,blockRectangle, blockTextureData,blockTexture.Width))            
10     {                       
11        personHit = true;            
12     }     // Remove this block if it has fallen off the screen           
13    if (blockPositions[i].Y > Window.ClientBounds.Height)
14    {                        
15       blockPositions.RemoveAt(i);                         
16      // When removing a block, the next block will have the same index                        
17     // as the current block. Decrement i to prevent skipping a block.                        
18        i--;            
19     }
20 }

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

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

转载于:https://www.cnblogs.com/315358525/archive/2009/07/14/1522944.html


http://www.niftyadmin.cn/n/2556779.html

相关文章

了解 Windows Vista 内核

以下是连接: 了解 Windows Vista 内核&#xff1a;第一部分 概览:线程优先级和计划 基于文件的符号链接 取消 I/O 操作 了解 Windows Vista 内核&#xff1a;第 二 部分 概览:内存管理 启动和关闭 电源管理 了解 Windows Vista 内核&#xff1a;第三部分 概览:可靠性 可恢…

CodeForces 297C Splitting the Uniqueness (脑补构造题)

题意 Split a unique array into two almost unique arrays. unique arrays指数组各个数均不相同&#xff0c;almost unique arrays指可以删掉数后再判断。 思路 略神的数学构造题。。。 官方题解&#xff1a; An equivalent definition for almost unique, is arrays with at …

设备用反线 不同设备用平行 这条法则要好好理解.

"设备用反线 不同设备用平行" 这条法则是组建网络的连线法则,但是要会理解. 一般的网卡还是按这个法则没有错,但是遇到笔记本的自适应网卡时,就要注意下. 为什么那? 记本电脑通常内置无线和有线网卡&#xff0c;虽然无线网络数据传输目前已经成为主流&#xff0c;但…

C#:iterator 迭代器/partial class 分布类/泛型

iterator 迭代器 写个最简单的迭代&#xff0c;&#xff08;迭代一个字符串数组&#xff09;&#xff1a; 1.实现接口中的方法&#xff1a; 1 using System;2 using System.Collections.Generic;3 using System.Linq;4 using System.Text;5 using System.Threading.Tasks;6 usi…

学习:SQL数据库日志收缩(转)

declare data varchar(20) select data 数据库名 execute (execute sp_helpdb data ) execute ( BACKUP LOG data WITH TRUNCATE_ONLY ) execute ( DBCC SHRINKDATABASE( data ,10)) execute (execute sp_helpdb data ) 文章来源&#xff1a;http://bbs.winos.cn/v…

基本知识点罗列

1.dropdownlist的绑定 BLLAuction bll_getAuctionnew BLLAuction();this.ddlauctioncode.DataSource bll_getAuction.GetAuctionList();this.ddlauctioncode.DataTextField "Name";this.ddlauctioncode.DataValueField "code";this.ddlauctioncode.Data…

Administrator用户直接获取SYSTEM权限

来源&#xff1a; http://www.nsfocus.com 作者&#xff1a;"scz" < scznsfocus.com> 标题: MSDN系列(3)--Administrator用户直接获取SYSTEM权限 日期: 2003-06-21 21:51更新: --------------------------------------------------------------------------…

web developer tips (26):在 App_Code目录下同时放c#和VB.NET文件

原文地址&#xff1a;How to have C# and VB.NET files inside your App_Code directory 如果你利用App_Code目录来开发一个Asp.net web网站&#xff0c;有时候需要写用不同net语言的代码文件。例如&#xff0c;如果你想用在同一个web网站同时使用c#和VB.net http://www.watch-…