使用旋转矩形进行碰撞检测

发布于 2024-11-01 01:23:20 字数 733 浏览 1 评论 0原文

我正在创建一个乒乓球游戏。然而,在我的游戏中,桨能够绕其中心旋转。

这些桨由矩形二维对象表示。现在,这些矩形应该能够击中球。球由一个 Circle2D 对象表示,当球击中球拍时(这是通过使用矩形的 intersects 方法完成的),球会反转方向。当桨不旋转时,此方法工作正常,但当它们旋转时,相交方法不起作用。当我使用此语句时:(

paddle2.intersects(xLocation, yLocation, diameter, diameter)

其中 paddle2 是其中一个矩形的名称,传递给它的参数表示圆的 x 坐标、y 坐标和半径)

圆的行为就像矩形未旋转一样。也就是说,它会从矩形的原始位置反弹。

我可能应该提到我正在使用仿射变换旋转矩形。这是我用来使矩形显示为旋转的命令:(

g2.rotate(Math.toRadians(angle), xLocation+(width/2), yLocation+(height/2)); 

其中参数是矩形的旋转角度以及中心的 x 和 y 坐标)。

然后,我将 g2 对象的仿射变换重置回常规仿射变换。

我已经研究这个问题有一段时间了,并且发现了一些关于这个问题的讨论。然而,它们似乎超出了我的理解范围,而且它们似乎涉及矩阵数学(作为一个从未学过必要数学的人,我完全迷失了)。因此,我希望有人可以提供一个简单的解决方案,或者引导我完成所需的数学运算。

谢谢!

I am creating a pong game. However, in my game, the paddles have the ability to rotate about their center.

These paddles are represented by rectangle2D objects. Now, these rectangles are supposed to hit the ball as it comes to them. The ball is represented by a circle2D object, and when the ball hits the paddle (this is done by using the intersects method of the rectangles), the ball reverses direction. This works fine when the paddles are not rotated, but when they are rotated, the intersects method doesn't work. When I use this statement:

paddle2.intersects(xLocation, yLocation, diameter, diameter)

(Where paddle2 is the name of one of the rectangles, and the parameters passed to it represent the x coordinate, y coordinate, and radius of the circle)

The circle acts as if the rectangle isn't rotated. That is, it will bounce off the rectangles original position.

I should probably mention that I am rotating the rectangles using affine transforms. This is the command I use to make the rectangle appear rotated:

g2.rotate(Math.toRadians(angle), xLocation+(width/2), yLocation+(height/2)); 

(where the parameters are the rotation angle of the rectangle, and the x and y coordinates of the center).

Then, I reset the affine transform of my g2 object back to a regular affine transform.

I have been researching this problem for awhile now, and I have found a couple discussions on the problem. However, they seem to be over my head, and they seem to deal with matrix mathematics (and as someone who has never learned the necessary math, I get quite lost). So, I was hoping that someone could provide a simple solution, or walk me through the required math.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

倒带 2024-11-08 01:23:20

也许这是一个老问题,但我认为为其他将阅读这篇文章的人提供了解决方案:

/** Rectangle To Point. */
boolean testRectangleToPoint(double rectWidth, double rectHeight, double rectRotation, double rectCenterX, double rectCenterY, double pointX, double pointY) {
    if(rectRotation == 0)   // Higher Efficiency for Rectangles with 0 rotation.
        return Math.abs(rectCenterX-pointX) < rectWidth/2 && Math.abs(rectCenterY-pointY) < rectHeight/2;

    double tx = Math.cos(rectRotation)*pointX - Math.sin(rectRotation)*pointY;
    double ty = Math.cos(rectRotation)*pointY + Math.sin(rectRotation)*pointX;

    double cx = Math.cos(rectRotation)*rectCenterX - Math.sin(rectRotation)*rectCenterY;
    double cy = Math.cos(rectRotation)*rectCenterY + Math.sin(rectRotation)*rectCenterX;

    return Math.abs(cx-tx) < rectWidth/2 && Math.abs(cy-ty) < rectHeight/2;
}

/** Circle To Segment. */
boolean testCircleToSegment(double circleCenterX, double circleCenterY, double circleRadius, double lineAX, double lineAY, double lineBX, double lineBY) {
    double lineSize = Math.sqrt(Math.pow(lineAX-lineBX, 2) + Math.pow(lineAY-lineBY, 2));
    double distance;

    if (lineSize == 0) {
        distance = Math.sqrt(Math.pow(circleCenterX-lineAX, 2) + Math.pow(circleCenterY-lineAY, 2));
        return distance < circleRadius;
    }

    double u = ((circleCenterX - lineAX) * (lineBX - lineAX) + (circleCenterY - lineAY) * (lineBY - lineAY)) / (lineSize * lineSize);

    if (u < 0) {
        distance = Math.sqrt(Math.pow(circleCenterX-lineAX, 2) + Math.pow(circleCenterY-lineAY, 2));
    } else if (u > 1) {
        distance = Math.sqrt(Math.pow(circleCenterX-lineBX, 2) + Math.pow(circleCenterY-lineBY, 2));
    } else {
        double ix = lineAX + u * (lineBX - lineAX);
        double iy = lineAY + u * (lineBY - lineAY);
        distance = Math.sqrt(Math.pow(circleCenterX-ix, 2) + Math.pow(circleCenterY-iy, 2));
    }

    return distance < circleRadius;
}

/** Rectangle To Circle. */
boolean testRectangleToCircle(double rectWidth, double rectHeight, double rectRotation, double rectCenterX, double rectCenterY, double circleCenterX, double circleCenterY, double circleRadius) {
    double tx, ty, cx, cy;

    if(rectRotation == 0) { // Higher Efficiency for Rectangles with 0 rotation.
        tx = circleCenterX;
        ty = circleCenterY;

        cx = rectCenterX;
        cy = rectCenterY;
    } else {
        tx = Math.cos(rectRotation)*circleCenterX - Math.sin(rectRotation)*circleCenterY;
        ty = Math.cos(rectRotation)*circleCenterY + Math.sin(rectRotation)*circleCenterX;

        cx = Math.cos(rectRotation)*rectCenterX - Math.sin(rectRotation)*rectCenterY;
        cy = Math.cos(rectRotation)*rectCenterY + Math.sin(rectRotation)*rectCenterX;
    }

    return testRectangleToPoint(rectWidth, rectHeight, rectRotation, rectCenterX, rectCenterY, circleCenterX, circleCenterY) ||
            testCircleToSegment(tx, ty, circleRadius, cx-rectWidth/2, cy+rectHeight/2, cx+rectWidth/2, cy+rectHeight/2) ||
            testCircleToSegment(tx, ty, circleRadius, cx+rectWidth/2, cy+rectHeight/2, cx+rectWidth/2, cy-rectHeight/2) ||
            testCircleToSegment(tx, ty, circleRadius, cx+rectWidth/2, cy-rectHeight/2, cx-rectWidth/2, cy-rectHeight/2) ||
            testCircleToSegment(tx, ty, circleRadius, cx-rectWidth/2, cy-rectHeight/2, cx-rectWidth/2, cy+rectHeight/2);
}

这是测试圆形(球)和矩形(可以旋转)之间的碰撞的代码。

Maybe this is an old question, but I think to have the solution for anyone else that will read this post:

/** Rectangle To Point. */
boolean testRectangleToPoint(double rectWidth, double rectHeight, double rectRotation, double rectCenterX, double rectCenterY, double pointX, double pointY) {
    if(rectRotation == 0)   // Higher Efficiency for Rectangles with 0 rotation.
        return Math.abs(rectCenterX-pointX) < rectWidth/2 && Math.abs(rectCenterY-pointY) < rectHeight/2;

    double tx = Math.cos(rectRotation)*pointX - Math.sin(rectRotation)*pointY;
    double ty = Math.cos(rectRotation)*pointY + Math.sin(rectRotation)*pointX;

    double cx = Math.cos(rectRotation)*rectCenterX - Math.sin(rectRotation)*rectCenterY;
    double cy = Math.cos(rectRotation)*rectCenterY + Math.sin(rectRotation)*rectCenterX;

    return Math.abs(cx-tx) < rectWidth/2 && Math.abs(cy-ty) < rectHeight/2;
}

/** Circle To Segment. */
boolean testCircleToSegment(double circleCenterX, double circleCenterY, double circleRadius, double lineAX, double lineAY, double lineBX, double lineBY) {
    double lineSize = Math.sqrt(Math.pow(lineAX-lineBX, 2) + Math.pow(lineAY-lineBY, 2));
    double distance;

    if (lineSize == 0) {
        distance = Math.sqrt(Math.pow(circleCenterX-lineAX, 2) + Math.pow(circleCenterY-lineAY, 2));
        return distance < circleRadius;
    }

    double u = ((circleCenterX - lineAX) * (lineBX - lineAX) + (circleCenterY - lineAY) * (lineBY - lineAY)) / (lineSize * lineSize);

    if (u < 0) {
        distance = Math.sqrt(Math.pow(circleCenterX-lineAX, 2) + Math.pow(circleCenterY-lineAY, 2));
    } else if (u > 1) {
        distance = Math.sqrt(Math.pow(circleCenterX-lineBX, 2) + Math.pow(circleCenterY-lineBY, 2));
    } else {
        double ix = lineAX + u * (lineBX - lineAX);
        double iy = lineAY + u * (lineBY - lineAY);
        distance = Math.sqrt(Math.pow(circleCenterX-ix, 2) + Math.pow(circleCenterY-iy, 2));
    }

    return distance < circleRadius;
}

/** Rectangle To Circle. */
boolean testRectangleToCircle(double rectWidth, double rectHeight, double rectRotation, double rectCenterX, double rectCenterY, double circleCenterX, double circleCenterY, double circleRadius) {
    double tx, ty, cx, cy;

    if(rectRotation == 0) { // Higher Efficiency for Rectangles with 0 rotation.
        tx = circleCenterX;
        ty = circleCenterY;

        cx = rectCenterX;
        cy = rectCenterY;
    } else {
        tx = Math.cos(rectRotation)*circleCenterX - Math.sin(rectRotation)*circleCenterY;
        ty = Math.cos(rectRotation)*circleCenterY + Math.sin(rectRotation)*circleCenterX;

        cx = Math.cos(rectRotation)*rectCenterX - Math.sin(rectRotation)*rectCenterY;
        cy = Math.cos(rectRotation)*rectCenterY + Math.sin(rectRotation)*rectCenterX;
    }

    return testRectangleToPoint(rectWidth, rectHeight, rectRotation, rectCenterX, rectCenterY, circleCenterX, circleCenterY) ||
            testCircleToSegment(tx, ty, circleRadius, cx-rectWidth/2, cy+rectHeight/2, cx+rectWidth/2, cy+rectHeight/2) ||
            testCircleToSegment(tx, ty, circleRadius, cx+rectWidth/2, cy+rectHeight/2, cx+rectWidth/2, cy-rectHeight/2) ||
            testCircleToSegment(tx, ty, circleRadius, cx+rectWidth/2, cy-rectHeight/2, cx-rectWidth/2, cy-rectHeight/2) ||
            testCircleToSegment(tx, ty, circleRadius, cx-rectWidth/2, cy-rectHeight/2, cx-rectWidth/2, cy+rectHeight/2);
}

This is the code to test Collisions between a circle (The Ball) and a rectangle (That can rotate).

彡翼 2024-11-08 01:23:20

intersect 方法不起作用的原因是您实际上并未旋转 Rectangle2D。您告诉图形上下文进行旋转,这样它绘制的任何内容(例如未旋转的 Rectangle2D )都会旋转绘制,但实际的 Rectangle2D 实例不会被修改。

也许您可以使用 Polyon 作为桨,而不是 Rectangle2D,并像 这个答案。这样,实际实例将被旋转(因此您不需要旋转 Graphics2D 实例)并且碰撞检测应该正常工作。

The reason the intersect method doesn't work is because you aren't actually rotating the Rectangle2D. You are telling the graphics context to rotate such that anything it does draw (such as an unrotated Rectangle2D) is drawn rotated, but the actual Rectangle2D instance isn't modified.

Maybe you can use Polyon for the paddles, instead of Rectangle2D, and rotate them as in this answer. That way the actual instance will be rotated (so you won't need to rotate your Graphics2D instance) and collision detection should work properly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文