我目前正在为我的2D游戏进行碰撞.我做了一些研究并推断我应该使用将alpha值像素存储到实体图像的“掩码”中的方法,并且对于另一个使用相同的方法.然后,我把两个实体的x& y co-ords,以及高度和宽度,并创建一个Rectangle对象,并使用方法Rectangle.intersects(Rectangle r)检查它们是否实际碰撞,以使其更有效,而不是通过2 for循环.
如果它们相交,我会创建一个具有以下尺寸的新数组:
int maxLengthY = Math.max(thisEntity.getMask().length, e.getMask().length);
int maxLengthX = Math.max(thisEntity.getMask()[0].length, thisEntity.getMask()[0].length);
int minX = Math.min(thisEntity.getX(), e.getX());
int minY = Math.min(thisEntity.getY(), e.getY());
int[][] map = new int[maxLengthX + minX][maxLengthY + minY];
然后将另外两个掩模添加到这个掩模上,并使用相应的y和amp; x“边界”,如下:
for(int curX = 0; curX < maxLengthX + minX; curX++) { //only loop through the co-ords that area affected
for(int curY = 0; curY < maxLengthY + minY; curY++) {
int this_x = thisEntity.getX();
int this_width = thisEntity.getImage().getWidth();
int this_y = thisEntity.getY();
int this_height = thisEntity.getImage().getHeight();
int[][] this_mask = thisEntity.getMask();
if(curX < (this_x + this_width) && curX < this_x) {//check that the co-ords used are relevant for thisEntity's mask
if(curY < (this_y + this_height) && curY < this_y) {
map[curX][curY] = this_mask[Math.abs(curX - this_x)][Math.abs(curY - this_y)]; // store data from mask to map
}
}
int other_x = e.getX();
int other_width = e.getImage().getWidth();
int other_y = e.getY();
int other_height = e.getImage().getHeight();
int[][] other_mask = e.getMask();
if(curX < (other_x + other_width) && curX > other_x) { //check that the co-ords used are relevant for e's mask
if(curY < (other_y + other_height) && curY > other_y) {
if(map[curX][curY] == 1) { //check if this segment is already written by thisEntity
map[curX][curY] = 2; //if yes, set to 2 instead of e's value to show collision
} else {
map[curX][curY] = other_mask[curX][curY]; // the minus to nullify minX and minY "requirements"
}
}
}
}
}
导致数组“地图”看起来像SO:
(原谅我1337的涂装技巧)
这是所有美丽的代码:
public Entity[] collisions(Entity thisEntity) {
ArrayList<Entity> list = new ArrayList<Entity>();
try {
for (Entity e : getLevel().getEntities()) {
System.out.println("rect contains = "+thisEntity.getRect().contains(e.getRect()));
if (!thisEntity.equals(e)) {
Rectangle r = e.getRect();
r = thisEntity.getRect();
if (thisEntity.getRect().intersects(e.getRect())) {
//get variables to create a space designated for the intersection areas involved
int maxLengthY = Math.max(thisEntity.getMask().length, e.getMask().length);
int maxLengthX = Math.max(thisEntity.getMask()[0].length, thisEntity.getMask()[0].length);
int minX = Math.min(thisEntity.getX(), e.getX());
int minY = Math.min(thisEntity.getY(), e.getY());
int[][] map = new int[maxLengthX + minX][maxLengthY + minY]; //create a matrix which merges both Entity's mask's to compare
for(int curX = 0; curX < maxLengthX + minX; curX++) { //only loop through the co-ords that area affected
for(int curY = 0; curY < maxLengthY + minY; curY++) {
int this_x = thisEntity.getX();
int this_width = thisEntity.getImage().getWidth();
int this_y = thisEntity.getY();
int this_height = thisEntity.getImage().getHeight();
int[][] this_mask = thisEntity.getMask();
if(curX < (this_x + this_width) && curX > this_x) {//check that the co-ords used are relevant for thisEntity's mask
if(curY < (this_y + this_height) && curY > this_y) {
map[curX][curY] = this_mask[Math.abs(curX - this_x)][Math.abs(curY - this_y)]; // store data from mask to map
}
}
int other_x = e.getX();
int other_width = e.getImage().getWidth();
int other_y = e.getY();
int other_height = e.getImage().getHeight();
int[][] other_mask = e.getMask();
if(curX < (other_x + other_width) && curX > other_x) { //check that the co-ords used are relevant for e's mask
if(curY < (other_y + other_height) && curY > other_y) {
if(map[curX][curY] == 1) { //check if this segment is already written by thisEntity
map[curX][curY] = 2; //if yes, set to 2 instead of e's value to show collision
} else {
map[curX][curY] = other_mask[curX][curY]; // the minus to nullify minX and minY "requirements"
}
}
}
}
}
}
}
}
} catch (Exception excp) {
excp.printStackTrace();
}
return list.toArray(new Entity[1]);
}
另外,这是方法getMask():
public int[][] getMask() {
return mask;
}
...
private void createMask(BufferedImage image) {
final int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
final int width = image.getWidth();
final int height = image.getHeight();
final boolean hasAlphaChannel = image.getAlphaRaster() != null;
int[][] result = new int[height][width];
if (hasAlphaChannel) {
for (int pixel = 0, row = 0, col = 0; pixel < pixels.length; pixel += 4) {
int alpha = pixels[pixel];
if(alpha != 0) {
result[row][col] = 1;
} else {
result[row][col] = 0;
}
if (col == width) {
col = 0;
row++;
}
}
}
mask = result;
}
但是……这段代码没有按预期工作,在某些情况下,就像在将各个蒙版添加到地图时一样,我得到了IndexOutOfBounds,即使它应该有效,所以它可能只是我忽略了一些东西……
总而言之,我需要帮助我的代码:
>它有什么问题?
>我该如何解决?
>有没有更有效的方式来进行这种类型的碰撞?
>您是否推荐其他类型的碰撞?如果是这样,他们是什么?
解决方法:
创建实体时,是否从完全相同大小的图像创建蒙版?因为否则实体的掩码和图像映射将使用不同的坐标系(entity.mask [0] [0]可能位于其角落,当map [0] [0]位于“世界”的角落时,并且你在线上比较相同的指数:
map[curX][curY] = other_mask[curX][curY];
(上面的代码中你实际上得到的是与Math.abs(a-b)相同的坐标系)
至于更有效的方法来检测碰撞,您可以在*上的collision detection in general查看binary space partitioning及更多内容.