# 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;
};

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

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

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.