开发者

Collision Detection with Rotated Rectangles

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!


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).


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜