prosty algorytm kolizji prostokąta 2D, który określa również, które boki zderzają się z prostokątami?

16

Początkowo próbowałem zastosować prostokątne przecięcie, które działa dobrze. Kiedy jednak muszę zastosować układ fizyki, taki jak prędkość, przyspieszenie i wektory kierunkowe, musiałbym znaleźć sposób na określenie, która strona kolizji zderza się. Teraz w moim systemie nie ma obróconego prostokąta, więc uprościło to problem. Nie znalazłem jednak łatwego sposobu na określenie, która strona prostokąta zderzyła się. Kiedyś już miałem do czynienia z tym problemem, ale poniosłem porażkę.

To, co zrobiłem w przeszłości, to określenie odległości między każdym równoległymi prostokątnymi bokami i sprawdzenie, czy odległość jest bliska 0 (użyj pewnego wstępnie zdefiniowanego zakresu odległości) lub wynosi 0. Jednak w przypadku arytmetyki zmiennoprzecinkowej okazuje się to niestabilne, ponieważ upływ czasu nieznanego czasu. Czasami prostokąty przecinają się, zanim osiągną zdefiniowany zakres.

Z drugiej strony myślałem o spawnowaniu wielu prostokątów, każdy prostokąt dla każdej strony. Jednak po ponownym przemyśleniu byłoby to tym samym, co równoległa strona ze sprawdzaniem zasięgu odległości, tyle że ten zasięg odległości jest szerokością każdego mini-prostokąta.

Dlatego jakieś sugestie dotyczące tego problemu?

użytkownik1542
źródło
Czy używasz dyskretnych lub ciągłych aktualizacji pozycji? (czy aktualizujesz prędkość przez przyspieszenie raz na każdą klatkę, a następnie obliczasz pozycję, czy używasz funkcji do ekstrapolacji pozycji)
Casey Kuball

Odpowiedzi:

24

Na podstawie mojej odpowiedzi na pytanie „Która strona została trafiona?” :

Sugeruję obliczenie sumy B i A Minkowskiego , która jest nowym prostokątem, i sprawdzenie, gdzie środek prostokąta A leży w stosunku do tego nowego prostokąta (aby wiedzieć, czy dochodzi do kolizji) i jego przekątnych (aby wiedzieć, gdzie kolizja dzieje się):

float w = 0.5 * (A.width() + B.width());
float h = 0.5 * (A.height() + B.height());
float dx = A.centerX() - B.centerX();
float dy = A.centerY() - B.centerY();

if (abs(dx) <= w && abs(dy) <= h)
{
    /* collision! */
    float wy = w * dy;
    float hx = h * dx;

    if (wy > hx)
        if (wy > -hx)
            /* collision at the top */
        else
            /* on the left */
    else
        if (wy > -hx)
            /* on the right */
        else
            /* at the bottom */
}
sam hocevar
źródło
1
Chciałbym dodać, że „góra” i „dół” odnoszą się do twojego układu współrzędnych. Na przykład w mojej grze (0,0) znajduje się w lewym górnym rogu, więc są odwrócone od twojego przykładu. Tylko coś do zapamiętania.
Neikos,
świetne rozwiązanie, działało bardzo dobrze dla moich potrzeb.
Opiatefuchs
1
Czy jest jakaś usterka, gdy dx staje się 0 lub dy staje się 0 lub oba? Pozwól mi to wyjaśnić ... jeśli dx = 0 && dy == 0, oznacza to, że oba prostokąty mają ten sam początek, to czy algorytm domyślnie zwraca wartość dna? jeśli jeden z nich jest równy 0, oczekiwany jest poprawny wynik. Myślę, że ten algorytm jest poprawny, z wyjątkiem przypadku, gdy dx == 0 && dy == 0, które powinny być nieokreślone, a nie dno. Uważajcie więc i dziękuję.
Prasanth
1
Zastanawiałem się teraz, co się stanie, gdy dx == dy, w == h ... to też kod decyduje, że wynikiem jest jedna strona, gdy w rzeczywistości jest nieokreślona .. wyobraź sobie, że dwa kwadraty przecinają się tak, że środek jednego kwadratu jest na róg innego kwadratu, a środek drugiego kwadratu znajduje się w rogu pierwszego kwadratu. Tutaj strona powinna być nieokreślona - nie jest prawa ani dolna. Oba są?
Prasanth