Wykrywanie kolizji prostokąt okrąg.

0

Napisałem (a raczej znalazłem w necie) taki kod do wykrywania kolizji prostokąt okrąg:


struct TPoint {
    float x, y;
};

struct TSegment {
   TPoint a, b;
};

struct TRectangle {
    TPoint LeftTopCorner;
    float Width, Height;
};

struct TCircle {
    TPoint Center;
    float Radius;
};

bool Collision(TPoint APoint, TCircle ACircle) {
    float d = sqrt(pow(ACircle.Center.x - APoint.x, 2) + pow(ACircle.Center.y - APoint.y, 2));

    if (d <= ACircle.Radius) {
        return true;
    }
    else {
        return false;
    }
}

bool Collision(TCircle ACircle, TSegment ASegment) {
    if(Collision(ASegment.a, ACircle) || Collision(ASegment.b, ACircle)) {
        return true;
    }

    float A = ASegment.b.y - ASegment.a.y;
    float B = ASegment.a.x - ASegment.b.x;
    float C = ASegment.a.y * ASegment.b.x - ASegment.b.y * ASegment.a.x;

    float d = fabs(A * ACircle.Center.x + B * ACircle.Center.y + C) / sqrt(A*A + B*B);

    if (d <= ACircle.Radius) {
        return true;
    }
    else {
        return false;
    }
}

bool Collision(TCircle ACircle, TRectangle ARectangle) {
    TSegment segment1, segment2;

    TPoint RectCenter;
    RectCenter.x = ARectangle.LeftTopCorner.x + ARectangle.Width / 2;
    RectCenter.y = ARectangle.LeftTopCorner.y + ARectangle.Height / 2;

    TPoint RectLeftUpCorner, RectRightUpCorner, RectRightDownCorner, RectLeftDownCorner;
    RectLeftUpCorner = ARectangle.LeftTopCorner;

    RectRightUpCorner.x = RectLeftUpCorner.x + ARectangle.Width;
    RectRightUpCorner.y = RectLeftUpCorner.y;

    RectRightDownCorner.x = RectLeftUpCorner.x + ARectangle.Width;
    RectRightDownCorner.y = RectLeftUpCorner.y + ARectangle.Height;

    RectLeftDownCorner.x = RectLeftUpCorner.x;
    RectLeftDownCorner.y = RectLeftUpCorner.y + ARectangle.Height;

    if (ACircle.Center.x > RectCenter.x) {
        segment1.a = RectRightUpCorner;
        segment1.b = RectRightDownCorner;
    }
    else {
        segment1.a = RectLeftUpCorner;
        segment1.b = RectLeftDownCorner;
    }

    if (ACircle.Center.y > RectCenter.y) {
        segment2.a = RectLeftDownCorner;
        segment2.b = RectRightDownCorner;
    }
    else {
        segment2.a = RectLeftUpCorner;
        segment2.b = RectRightUpCorner;
    }

    if (Collision(ACircle, segment1) || Collision(ACircle, segment2)) {
        return true;
    }
    else {
        return false;
    }
}

I z tym kodem jest taki problem, że wykrywa kolizje okręgu z prostą na której leży którykolwiek bok prostokąta. Podejrzewam, że błąd leży w sprawdzaniu kolizji okręgu z odcinkiem, gdyż tam po sprawdzeniu końców odcinka następuje sprawdzenie odległości do prostej na której leży ten odcinek. Ktoś może mi podpowiedzieć jak to ograniczyć?

0

Zobacz jak to jest zrealizowane w ZenGL - w module zgl_collision_2d jest kupka funkcji do sprawdzania kolizji. Obstawiam, że to co potrzebujesz implementuje funkcja col2d_RectVsCircle.

PS: Używasz formatowania kodu odpowiedniego dla Pascala, niekoniecznie dobrego w C++ :]

0

Zobacz jak to jest zrealizowane w ZenGL - w module zgl_collision_2d jest kupka funkcji do sprawdzania kolizji. Obstawiam, że to co potrzebujesz implementuje funkcja col2d_RectVsCircle.

Sprawdzałem i kod działa w sumie spoko jednak zależy mi na kolizji okrąg<->odcinek gdyż mając tą funkcję mogę zrobić funkcję sprawdzającą kolizję okręgu z dowolnym wielokątem, a to się może przydać do bardziej zaawansowanych gier :P
Na razie stanęło na tym:

bool Collision(TCircle ACircle, TSegment ASegment) {
    if (Collision(ASegment.a, ACircle) || Collision(ASegment.a, ACircle)) {
        return true;
    }
    // TODO: Analyze how it works.
    float c1x = ACircle.Center.x - ASegment.a.x;
    float c1y = ACircle.Center.y - ASegment.a.y;
    float e1x = ASegment.b.x - ASegment.a.x;
    float e1y = ASegment.b.y - ASegment.a.y;

    float k = c1x * e1x + c1y * e1y;

    if (k > 0) {
        float len = sqrt(e1x * e1x + e1y * e1y);
        k = k / len;

        if (k < len) {
            if (sqrt(c1x * c1x + c1y * c1y - k * k) <= ACircle.Radius) {
                return true;
            }
        }
    }
    return false;
}

Działa dobrze ale jak widać po komentarzu nie analizowałem tego dokładnie :P (Do tej pory żałuję, że nie przykładałem się do geometrii analitycznej w technikum :S)

PS: Używasz formatowania kodu odpowiedniego dla Pascala, niekoniecznie dobrego w C++ :]

Wiem jednak nie znalazłem jakiegoś "poradnika" na temat konwencji nazewnictwa w c++ a w kodach jakie widziałem w necie to każdy pisze jak chce. Jedyne co zauważyłem to nazwy klas zaczynają się od C a nie od T. Ogólnie niedługo (może nawet jutro) wrzucę kod swojego arkanoida do oceny i może ktoś mi da wskazówki odnośnie nazewnictwa.

1 użytkowników online, w tym zalogowanych: 0, gości: 1