在Android中使用SurfaceView的画布进行位图碰撞检测

3
在Android中,我使用SurfaceView显示一个简单的2D游戏。位图(.png) 带有 alpha (代表游戏对象)被绘制在画布上。
现在,我想做一个简单但准确的碰撞检测。检查这些位图是否重叠相当容易。
但是,当这些位图具有透明区域时,如何检查碰撞呢?我的挑战在于检测两个球是否发生碰撞。它们在宽度和高度上都充满了整个位图,但在所有四个边缘上,肯定存在透明区域,因为这是一个圆在正方形中。
有什么最简单的方法可以只在球真正碰撞时检测到碰撞,而不是它们周围的位图框?
我需要存储尽可能多的点的坐标在球的轮廓上吗?或者Android可以在检查碰撞时“忽略”alpha通道吗?
3个回答

13

我能想到的另一种方法适用于可以使用Path构造的简单对象。

一旦你有了两个边界由路径表示的对象,可以尝试以下方法:

Path path1 = new Path();
path1.addCircle(10, 10, 4, Path.Direction.CW);
Path path2 = new Path();
path2.addCircle(15, 15, 8, Path.Direction.CW);

Region region1 = new Region();
region1.setPath(path1, clip);
Region region2 = new Region();
region2.setPath(path2, clip);

if (!region1.quickReject(region2) && region1.op(region2, Region.Op.INTERSECT)) {
    // Collision!
}

如果你已经将对象作为路径(Paths)获得,你可以使用 drawPath() 直接绘制它们。你还可以通过transform()转换路径进行移动。


1
感谢您,这确实是一个非常有趣和有用的解决方案,适用于非圆形对象!不过,我还没有弄清楚 clip 可能是什么…… - caw
3
根据我理解,上述代码中的“clip”变量应该是路径的边界框。为了一般性,我使用以下代码:Region clip = new Region(0, 0, layoutWidth, layoutHeight);其中,布局宽度和高度可以是您的画布、活动或其他内容的大小。 - Steven McConnon
如果有人对剪辑(clip)感到困惑,剪辑代表区域,例如:RectF bounds = new RectF(); path.computeBounds(bounds, true); Region region1 = new Region(); region1.setPath(path, new Region((int) bounds.left, (int) bounds.top,(int) bounds.right, (int) bounds.bottom)); region1.setPath(path, region1); ... - Mubashir Murtaza
请注意,setPath 可能会返回 false,表示生成的区域为空。在这种情况下,以下检查不起作用,原因显而易见。 - Nicolai Weitkemper

9
如果是球体碰撞,您可以执行解析式碰撞检测 - 比每像素检测快得多。您只需要获得两个球的中心(x1,y1)和(x2,y2)以及第一个球的半径r1和第二个球的半径r2。现在,如果球心之间的距离小于或等于半径之和,则表示球正在碰撞:
    colide = sqrt((x1-x2)^2+(y1-y2)^2)<=r1+r2

但更快的方法是比较这个值的平方:

   colide =  (x1-x2)^2+(y1-y2)^2<=(r1+r2)^2

2
非常感谢!对于球的例子,这可能是完美的解决方案。我应该提到我会更喜欢一个更通用的解决方案(例如每像素检测),但这是我的错。 - caw

2

谢谢,因为我不想使用精灵,所以最好的方法可能是只使用这段代码的一部分,对吗?这是重要的部分吗?https://github.com/m5/andengine-pixel-perfect/blob/master/src/com/qwerjk/andengine/collision/PixelPerfectBitMask.java 而且,有没有可能逐像素检查位图的颜色?我可以检查哪里真正有颜色(而不是alpha),并以此确定真实对象的轮廓。 - caw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接