XNA中是否有一种众所周知的方法(或者也许是可重用的代码)用于像素完美碰撞检测?
我假设这还将多边形(框/三角形/圆形)用于首过,碰撞的快速测试,如果该测试表明有碰撞,则它将搜索每个像素的碰撞。
这很复杂,因为我们必须考虑比例,旋转和透明度。
警告:如果您使用的是来自以下答案的链接中的示例代码,请注意,矩阵的缩放比例已被注释掉,这是有充分理由的。您无需取消注释即可开始扩展。
XNA中是否有一种众所周知的方法(或者也许是可重用的代码)用于像素完美碰撞检测?
我假设这还将多边形(框/三角形/圆形)用于首过,碰撞的快速测试,如果该测试表明有碰撞,则它将搜索每个像素的碰撞。
这很复杂,因为我们必须考虑比例,旋转和透明度。
警告:如果您使用的是来自以下答案的链接中的示例代码,请注意,矩阵的缩放比例已被注释掉,这是有充分理由的。您无需取消注释即可开始扩展。
Answers:
我看到您将问题标记为2d,所以我将继续转储我的代码:
class Sprite {
[...]
public bool CollidesWith(Sprite other)
{
// Default behavior uses per-pixel collision detection
return CollidesWith(other, true);
}
public bool CollidesWith(Sprite other, bool calcPerPixel)
{
// Get dimensions of texture
int widthOther = other.Texture.Width;
int heightOther = other.Texture.Height;
int widthMe = Texture.Width;
int heightMe = Texture.Height;
if ( calcPerPixel && // if we need per pixel
(( Math.Min(widthOther, heightOther) > 100) || // at least avoid doing it
( Math.Min(widthMe, heightMe) > 100))) // for small sizes (nobody will notice :P)
{
return Bounds.Intersects(other.Bounds) // If simple intersection fails, don't even bother with per-pixel
&& PerPixelCollision(this, other);
}
return Bounds.Intersects(other.Bounds);
}
static bool PerPixelCollision(Sprite a, Sprite b)
{
// Get Color data of each Texture
Color[] bitsA = new Color[a.Texture.Width * a.Texture.Height];
a.Texture.GetData(bitsA);
Color[] bitsB = new Color[b.Texture.Width * b.Texture.Height];
b.Texture.GetData(bitsB);
// Calculate the intersecting rectangle
int x1 = Math.Max(a.Bounds.X, b.Bounds.X);
int x2 = Math.Min(a.Bounds.X + a.Bounds.Width, b.Bounds.X + b.Bounds.Width);
int y1 = Math.Max(a.Bounds.Y, b.Bounds.Y);
int y2 = Math.Min(a.Bounds.Y + a.Bounds.Height, b.Bounds.Y + b.Bounds.Height);
// For each single pixel in the intersecting rectangle
for (int y = y1; y < y2; ++y)
{
for (int x = x1; x < x2; ++x)
{
// Get the color from each texture
Color a = bitsA[(x - a.Bounds.X) + (y - a.Bounds.Y)*a.Texture.Width];
Color b = bitsB[(x - b.Bounds.X) + (y - b.Bounds.Y)*b.Texture.Width];
if (a.A != 0 && b.A != 0) // If both colors are not transparent (the alpha channel is not 0), then there is a collision
{
return true;
}
}
}
// If no collision occurred by now, we're clear.
return false;
}
private Rectangle bounds = Rectangle.Empty;
public virtual Rectangle Bounds
{
get
{
return new Rectangle(
(int)Position.X - Texture.Width,
(int)Position.Y - Texture.Height,
Texture.Width,
Texture.Height);
}
}
编辑:虽然这段代码几乎可以自我解释,但我确实很讨厌没有注释,所以我添加了一些;)我也摆脱了按位操作,因为它基本上是用Color.A属性以更复杂的方式进行操作;)
Bounds
?
CollidesWith(Sprite other, bool calcPerPixel = true);
:)
在App Hub上,有一个非常古老的示例,可带您完成2D碰撞检测的过程,从简单的边界框到对旋转和缩放的精灵进行像素测试。它已完全更新到4.0。如果您是该主题的新手,那么整个系列都值得一读。
http://xbox.create.msdn.com/zh-CN/education/catalog/tutorial/collision_2d_perpixel_transformed
我还发现Riemer Grootjans的2D射击游戏有趣。 http://www.riemers.net/chi/Tutorials/XNA/Csharp/series2d.php
(他要花一些时间来找到它...... http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series2D/Coll_Detection_Overview.php ......但你可能想跟着一起看他正在解决的问题)
但是我告诫您,Riemers示例不是XNA 4.0,您可能需要做一些工作才能使其运行。但是,这并不困难或神秘。
我建议创建一个黑白碰撞图。对其进行编程,使黑色像素成为碰撞点。也给角色一个碰撞图;处理地图时,请使用一种算法,该算法会将黑色像素的大方块变成碰撞矩形。将此矩形数据保存在数组中。您可以使用“矩形相交”功能查找碰撞。您还可以使用纹理变换碰撞贴图。
这很像使用碰撞矩阵,但是更高级,您可以对其进行转换!如果需要,可以考虑构建一个碰撞图生成器工具。如果可以使用,请与他人共享代码!