Обнаружение столкновения с повернутыми прямоугольниками - PullRequest
2 голосов
/ 13 апреля 2011

Я создаю игру в понг.Однако в моей игре весла имеют возможность вращаться вокруг своего центра.

Эти весла представлены объектами rectangle2D.Теперь эти прямоугольники должны ударить по мячу, как только они придут к ним.Мяч представлен объектом 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 обратно в обычное аффинное преобразование.

Я уже некоторое время исследую эту проблему, и я нашел пару обсуждений этой проблемы.Тем не менее, они, кажется, над моей головой, и они, кажется, имеют дело с матричной математикой (и как человек, который никогда не изучал необходимую математику, я совершенно растерялся).Итак, я надеялся, что кто-нибудь сможет найти простое решение или помочь мне с математическим анализом.

Спасибо!

Ответы [ 2 ]

3 голосов
/ 06 января 2012

Возможно, это старый вопрос, но я думаю, что есть решение для всех, кто прочтет этот пост:

/** 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);
}

Это код для проверки столкновений между кругом (The Ball) и прямоугольником (который может вращаться).

1 голос
/ 13 апреля 2011

Причина, по которой метод пересечения не работает, заключается в том, что вы на самом деле не вращаете Rectangle2D.Вы говорите графическому контексту вращаться так, чтобы все, что он рисует (например, не повернутый Rectangle2D), рисовалось повернуто, но фактический экземпляр Rectangle2D не изменяется.

Возможно, вы можете использовать Polyon для весла вместо Rectangle2D и вращать их, как в в этом ответе .Таким образом, фактический экземпляр будет повернут (поэтому вам не нужно будет поворачивать Graphics2D экземпляр), и обнаружение столкновений должно работать правильно.

...