像素碰撞检测要点在于检测两个交叉图像像素点的的透明度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;
}