xna像素的碰撞检测

       像素碰撞检测要点在于检测两个交叉图像像素点的的透明度alpha。这样可以提升碰撞检测的精确度。

 一般的我们选取人物,怪物游戏素材图像,都不可能占满整个图像

如果我们以整张图片定义一个矩形方框来检测碰撞显然不够精确(但其实已经够用),我们的主角可能没碰到这颗树就发生了碰撞检测(挂掉了)。

我们希望的是主角真正的碰到这颗树,才发生碰撞检测。那我们应该怎么做呢?

我们假设模拟一下:我们的主角在屏幕的中央,然后树往下掉,我们则控制方向键来躲避他,如果碰到则屏幕颜色变红。

首先定义纹理对象:

Texture2D personTexture;
Texture2D treeTexture;

定义两个颜色数组,来保存图像的颜色数据:

Color[] personColorData;
Color[] treeColorData;

定义这个主角的位置和速度:

Vector2 personPosition;
const int PersonMoveSpeed = 10;

定义树的位置,由于我们这是躲避树模型,我们需要随机产生很多树,我们用泛型结构:

List<Vector2> treePositions = new List<Vector2>();

const int treeFallSpeed = 2;

定义树产生的频率,当我们随机产生的种子数小于这个频率 的时候我们创建一个树添加到treePositions中:

float   treecreatecount=0.05f;

Random random = new Random();

这里我们调用Random类的一个虚方法NextDobouble()来产生一随机数介于0.0和1.0之间

于是我们就可以这样来判断

if(random.NextDouble()<treecreatecount)

{

}

最后我们定义一个状态量来表征我们碰撞结果

bool  isHit=false;

加载资源步骤省略。初始化我们主角的位置在屏幕的中央.

然后我们加载颜色数据(需先加载图形资源)

treeColorData =
               new Color[treeTexture.Width * treeTexture.Height];
           treeTexture.GetData(treeColorData);
personColorData =
               new Color[personTexture.Width * personTexture.Height];
           personTexture.GetData(personColorData);

这样我们图像中每一个像素点的颜色数据我们就保存到了treeColorData,和personColorData中。

接下来我们更新我们的游戏逻辑

 按左按右运动:

if (keyboard.IsKeyDown(Keys.Left))
       {
            personPosition.X -= PersonMoveSpeed;
        }
        if (keyboard.IsKeyDown(Keys.Right))
        {
            personPosition.X += PersonMoveSpeed;
        }

产生树的代码:                   

if (random.NextDouble() <treecreatecount)
        {
            float x = (float)random.NextDouble() *
                (Window.ClientBounds.Width - treeTexture.Width);
            treePositions.Add(new Vector2(x, -treeTexture.Height));
        }

包围主角的矩形框:

   Rectangle personRectangle =
            new Rectangle((int)personPosition.X, (int)personPosition.Y,
            personTexture.Width, personTexture.Height);

碰撞检测:

       personHit = false;
        for (int i = 0; i < treePositions.Count; i++)
        {

            初始化每一个树的位置,并更新位置
                treePositions[i] =
                new Vector2(treePositions[i].X,
                            treePositions[i].Y + treeFallSpeed);

             树的矩形包围框:

                  Rectangle treeRectangle =
                new Rectangle((int)treePositions[i].X, (int)treePositions[i].Y,
                treeTexture.Width, treeTexture.Height);

检测交叉图像像素点:

          if (IntersectPixels(personRectangle, personColorData,
                                treeRectangle, treeColorData))
            {
                personHit = true;
            }

最后如果树落到底边,则自动消失

        if (treePositions[i].Y > Window.ClientBounds.Height)
            { 
                treePositions.RemoveAt(i--);

                   
             }

接下来我们定义一下上面出现的一个方法:

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

            检测交叉区域的每一个点:      

            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];

然后就是判断如果这个点两张图像上透明度都为0,也就是不透明,则返回真。

                  if (colorA.A != 0 && colorB.A != 0)
                    {
                                               return true;
                    }
                }
            }

                     return false;
        }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值