轴对齐矩形碰撞检测 - Java

Axis Aligned Rectangle Collision Detection - Java

我在检查 2 个矩形是否与 4 点 碰撞时遇到一些问题,所以我有一个 rect1p1(x,y)表示左下角p2(x,y)表示右上角,同rect2.


这是我的图表插图:

到目前为止,这是我的示例代码:

    int[][] rect1 = {{2,0},{3,1}};
    int[][] rect2 = {{0,0},{1,2}};
    if(rect1[1][0] >= rect2[0][0] && rect1[1][1] >= rect2[0][1] && rect1[0][0] <= rect2[1][0] && rect1[0][1] <= rect2[1][1])
    {
        System.out.println("Collision");
    } else {
        System.out.println("No Collision");
    }

我不太确定我用这段代码是否正确,任何人都可以给我一些想法吗? (我是初学者!)

简短回答:是

基本上你有四个条件你必须检查以确保你有碰撞矩形:

  • 第一个矩形的右上角必须在第二个矩形左下角的右边
  • 第一个矩形的右上角必须在第二个矩形的左下角上方
  • 第一个矩形的左下角必须在第二个矩形右上角的左边
  • 第一个矩形的左下角必须低于第二个矩形的右上角

像下面这样重构你的代码,上面四个条件是如何满足的会变得更清楚:

public class HelloWorld {

     public static void main(String []args){
        int[][] rect1 = {{1,5},{4,8}};
        int[][] rect2 = {{4,1},{7,4}};
        if( isRect1UpperRightCornerRightOfRect2BottomLeftCorner(rect1, rect2) && 
            isRect1UpperRightCornerAboveRect2BottomLeftCorner(rect1, rect2) && 
            isRect1BottomLeftCornerLeftOfRect2UpperRightCorner(rect1, rect2) && 
            isRect1BottomLeftCornerBelowRect2UpperRightCorner(rect1, rect2) ) {
            System.out.println("Collision");
        } else {
            System.out.println("No Collision");
        }
     }

     private static boolean isRect1UpperRightCornerRightOfRect2BottomLeftCorner(int[][] rect1, int[][] rect2) {
        return rect1[1][0] >= rect2[0][0];
     }

     private static boolean isRect1UpperRightCornerAboveRect2BottomLeftCorner(int[][] rect1, int[][] rect2) {
         return rect1[1][1] >= rect2[0][1];
     }

     private static boolean isRect1BottomLeftCornerLeftOfRect2UpperRightCorner(int[][] rect1, int[][] rect2) {
         return rect1[0][0] <= rect2[1][0];
     }

     private static boolean isRect1BottomLeftCornerBelowRect2UpperRightCorner(int[][] rect1, int[][] rect2) {
         return rect1[0][1] <= rect2[1][1];
     }
}

同时 here is a good interactive website 直观地展示了上面的工作原理。注意角被翻转了。

首先,您的代码不会在 if 块中编译。有一个不匹配的左括号。我会删除它。

所以,让我们添加一些中间变量以更好地理解代码的含义:

int[][] rect1 = {{2,0},{3,1}};
int[][] rect2 = {{0,0},{1,2}};

int rect1X1 = rect1[0][0];
int rect1X2 = rect1[1][0];
int rect1Y1 = rect1[0][1];
int rect1Y2 = rect1[1][1];

int rect2X1 = rect2[0][0];
int rect2X2 = rect2[1][0];
int rect2Y1 = rect2[0][1];
int rect2Y2 = rect2[1][1];

if (rect1X2 >= rect2X1 && rect1Y2 >= rect2Y1 && rect1X1 <= rect2X2 && rect1Y1 <= rect2Y2)
{
    System.out.println("Collision");
} else {
    System.out.println("No Collision");
}

现在,让我们分开每个轴的逻辑:

int[][] rect1 = {{2,0},{3,1}};
int[][] rect2 = {{0,0},{1,2}};

int rect1X1 = rect1[0][0];
int rect1X2 = rect1[1][0];
int rect1Y1 = rect1[0][1];
int rect1Y2 = rect1[1][1];

int rect2X1 = rect2[0][0];
int rect2X2 = rect2[1][0];
int rect2Y1 = rect2[0][1];
int rect2Y2 = rect2[1][1];

boolean xCollides = rect1X2 >= rect2X1 && rect1X1 <= rect2X2;
boolean yCollides = rect1Y2 >= rect2Y1 && rect1Y1 <= rect2Y2;

if (xCollides && yCollides)
{
    System.out.println("Collision");
} else {
    System.out.println("No Collision");
}

我们怎样才能得到一个轴的碰撞?有 15 种形式的两个对象如何沿轴相对于彼此定位:

案例 1 - 完全重合碰撞:

X-----X
X-----X

案例 2、3、4、5、6 和 7 - 完全非重合碰撞:

X---X              X---X          X-----X
X-----X          X-----X            X---X


X-----X            X-X            X-----X
  X-X            X-----X          X---X

情况 8 和 9 - 部分碰撞:

X---X              X---X
  X---X          X---X

案例 10 和 11 - 勉强相撞:

X--X                X--X
   X--X          X--X

案例 12 和 13 - 只是接触(不是碰撞):

X--X                 X-X
    X-X          X--X

情况 14 和 15 - 相距甚远(未碰撞):

X-X                  X-X
    X-X          X-X

您的代码应该在每个轴上将案例 1 到 11 与案例 12 到 15 分开。让我们看看它做了什么:

boolean xCollides = rect1X2 >= rect2X1 && rect1X1 <= rect2X2;
  • 情况一:真与真->真
  • 情况2:真与真->真
  • 情况3:真与真->真
  • 情况4:真与真->真
  • 情况5:真与真->真
  • 情况6:真与真->真
  • 情况7:真与真->真
  • 情况8:真与真->真
  • 情况9:真与真->真
  • 案例10:真与真->真
  • 案例11:真与真->真
  • 案例 12:假与真 -> 假
  • 案例 13:真假 -> 假
  • 案例 14:假与真 -> 假
  • 案例 15:真假 -> 假

因此,您的代码能够将情况 1 到 11 与情况 12 到 15 分开,因此它对于 X 轴是正确的。Y 轴的代码等同于 X 轴的代码(在不同的轴),所以它也是正确的。 最后,我们得出结论,您的整个代码都是正确的。