好的,所以我正在开发一款 Android 游戏。我需要实现像素完美碰撞检测。我已经在每个图像周围设置了边界框,每个边界框都经过转换以匹配图像的当前旋转。这一切都很好。我还将每个位图中的像素数据存储在一个数组中。有人可以帮我找出检测像素是否重叠的最有效方法吗?在此先感谢您的帮助!
好的,所以我正在开发一款 Android 游戏。我需要实现像素完美碰撞检测。我已经在每个图像周围设置了边界框,每个边界框都经过转换以匹配图像的当前旋转。这一切都很好。我还将每个位图中的像素数据存储在一个数组中。有人可以帮我找出检测像素是否重叠的最有效方法吗?在此先感谢您的帮助!
我的代码基于 Mayra 的示例,并进行了位图像素碰撞处理。我希望这将有所帮助。
public class CollisionUtil {
public static boolean isCollisionDetected(Sprite sprite1, Sprite sprite2){
Rect bounds1 = sprite1.getBounds();
Rect bounds2 = sprite2.getBounds();
if( Rect.intersects(bounds1, bounds2) ){
Rect collisionBounds = getCollisionBounds(bounds1, bounds2);
for (int i = collisionBounds.left; i < collisionBounds.right; i++) {
for (int j = collisionBounds.top; j < collisionBounds.bottom; j++) {
int sprite1Pixel = getBitmapPixel(sprite1, i, j);
int sprite2Pixel = getBitmapPixel(sprite2, i, j);
if( isFilled(sprite1Pixel) && isFilled(sprite2Pixel)) {
return true;
}
}
}
}
return false;
}
private static int getBitmapPixel(Sprite sprite, int i, int j) {
return sprite.getBitmap().getPixel(i-(int)sprite.getX(), j-(int)sprite.getY());
}
private static Rect getCollisionBounds(Rect rect1, Rect rect2) {
int left = (int) Math.max(rect1.left, rect2.left);
int top = (int) Math.max(rect1.top, rect2.top);
int right = (int) Math.min(rect1.right, rect2.right);
int bottom = (int) Math.min(rect1.bottom, rect2.bottom);
return new Rect(left, top, right, bottom);
}
private static boolean isFilled(int pixel) {
return pixel != Color.TRANSPARENT;
}
}
我更改了 arcones 的代码,因此该方法适用于位图而不是精灵。
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Rect;
public class KollisionsErkennung {
/**
* @param bitmap1 First bitmap
* @param x1 x-position of bitmap1 on screen.
* @param y1 y-position of bitmap1 on screen.
* @param bitmap2 Second bitmap.
* @param x2 x-position of bitmap2 on screen.
* @param y2 y-position of bitmap2 on screen.
*/
public static boolean isCollisionDetected(Bitmap bitmap1, int x1, int y1,
Bitmap bitmap2, int x2, int y2) {
Rect bounds1 = new Rect(x1, y1, x1+bitmap1.getWidth(), y1+bitmap1.getHeight());
Rect bounds2 = new Rect(x2, y2, x2+bitmap2.getWidth(), y2+bitmap2.getHeight());
if (Rect.intersects(bounds1, bounds2)) {
Rect collisionBounds = getCollisionBounds(bounds1, bounds2);
for (int i = collisionBounds.left; i < collisionBounds.right; i++) {
for (int j = collisionBounds.top; j < collisionBounds.bottom; j++) {
int bitmap1Pixel = bitmap1.getPixel(i-x1, j-y1);
int bitmap2Pixel = bitmap2.getPixel(i-x2, j-y2);
if (isFilled(bitmap1Pixel) && isFilled(bitmap2Pixel)) {
return true;
}
}
}
}
return false;
}
private static Rect getCollisionBounds(Rect rect1, Rect rect2) {
int left = (int) Math.max(rect1.left, rect2.left);
int top = (int) Math.max(rect1.top, rect2.top);
int right = (int) Math.min(rect1.right, rect2.right);
int bottom = (int) Math.min(rect1.bottom, rect2.bottom);
return new Rect(left, top, right, bottom);
}
private static boolean isFilled(int pixel) {
return pixel != Color.TRANSPARENT;
}
}
对于我的需要,它的工作速度足够快。
如果你们中有人感兴趣,我想分享我写的代码:
您需要知道的重要一点是 Sprite.getWidth() 和 Sprite.getHeight() 仅返回 Sprite 保存的位图的宽度/高度。您可以根据需要轻松调整代码,应该很容易理解代码的工作原理:)
public static boolean touchesSprite(Sprite s1, Sprite s2) {
Bitmap b1 = s1.getBmp();
Bitmap b2 = s2.getBmp();
int xshift = s2.getX()-s1.getX();
int yshift = s2.getY()-s1.getY();
//Test if the Sprites overlap at all
if((xshift > 0 && xshift > s1.getWidth()) || (xshift < 0 && -xshift > s2.getWidth())) {
return false;
}
if((yshift > 0 && yshift > s1.getHeight()) || (yshift < 0 && -yshift > s2.getHeight())) {
return false;
}
//if they overlap, find out in which regions they do
int leftx, rightx, topy, bottomy;
int leftx2, topy2;
if(xshift >= 0) {
leftx = xshift;
leftx2 = 0;
rightx = Math.min(s1.getWidth(), s2.getWidth()+xshift);
} else {
rightx = Math.min(s1.getWidth(), s2.getWidth()+xshift);
leftx = 0;
leftx2 = -xshift;
}
if(yshift >= 0) {
topy = yshift;
topy2 = 0;
bottomy = Math.min(s1.getHeight(), s2.getHeight()+yshift);
} else {
bottomy = Math.min(s1.getHeight(), s2.getHeight()+yshift);
topy = 0;
topy2 = -yshift;
}
//then compare the overlapping regions,
//if in any spot both pixels are not transparent, return true
int ys = bottomy-topy;
int xs = rightx-leftx;
for(int x=0; x<xs; x++) {
for(int y=0; y<ys; y++) {
int pxl = b1.getPixel(leftx+x, topy+y);
int pxl2 = b2.getPixel(leftx2+x, topy2+y);
if(!((pxl & 0xff000000) == 0x0) && !((pxl2 & 0xff000000) == 0x0)) {
return true;
}
}
}
return false;
}
基本思想是为每个对象创建一个位掩码,您可以在每个像素中指示该对象是否实际存在。然后比较两个对象的位掩码的每个像素。
您可以通过计算两个边界框重叠的矩形区域来最小化需要检查的像素数。该区域内的像素是您需要检查的。
遍历所有这些像素,并检查像素是否已填充到两个对象中。如果其中任何一个是,那么您就会发生碰撞。
如果您的矩形与 x/y 轴对齐,要找到重叠,请找到重叠的左侧、右侧、顶部和底部。它看起来像这样(我可能搞砸了边缘情况,还没有尝试过):
int left = max(obj1.left, obj2.left) int right = min(obj1.right, obj2.right) int top = min(obj1.top, obj2.top) int bottom = max(obj1.bottom, obj2.bottom) for (int x = left; x < right; x++) { for (int y = top; y < bottom; y++) { if (obj1.isFilled(x,y) && obj2.isFilled(x,y)) { return true; } } }