Ponieważ jest to oparte na twoim drugim pytaniu, dam rozwiązanie, kiedy prostokąt jest wyrównany względem osi.
Najpierw budujesz prostokąt bieżącego obiektu za pomocą następujących wartości:
int boxLeft = box.X;
int boxRight = boxLeft + box.Width;
int boxTop = box.Y;
int boxBottom = boxTop + box.Height;
Następnie musisz mieć pozycję starego obiektu (którą możesz zapisać na każdym obiekcie lub po prostu przekazać do funkcji), aby utworzyć prostokąt starego obiektu (gdy nie kolidował):
int oldBoxLeft = box.OldX;
int oldBoxRight = oldBoxLeft + box.Width;
int oldBoxTop = box.OldY;
int oldBoxBottom = oldBoxTop + box.Height;
Teraz, aby wiedzieć, skąd pochodzi kolizja, musisz znaleźć stronę, w której poprzednia pozycja nie znajdowała się w obszarze kolizji i gdzie jest nowa pozycja. Ponieważ, gdy o tym pomyślisz, dzieje się tak, gdy się zderzasz: strona, która nie zderzyła się, wchodzi w inny prostokąt.
Oto, jak możesz to zrobić (te funkcje zakładają, że istnieje kolizja. Nie należy ich wywoływać, jeśli nie ma kolizji):
bool collidedFromLeft(Object otherObj)
{
return oldBoxRight < otherObj.Left && // was not colliding
boxRight >= otherObj.Left;
}
Rince i powtórz.
bool collidedFromRight(Object otherObj)
{
return oldBoxLeft >= otherObj.Right && // was not colliding
boxLeft < otherObj.Right;
}
bool collidedFromTop(Object otherObj)
{
return oldBoxBottom < otherObj.Top && // was not colliding
boxBottom >= otherObj.Top;
}
bool collidedFromBottom(Object otherObj)
{
return oldBoxTop >= otherObj.Bottom && // was not colliding
boxTop < otherObj.Bottom;
}
Teraz, do faktycznego wykorzystania z odpowiedzią na kolizję z drugiego pytania:
if (collidedFromTop(otherObj) || collidedFromBottom(otherObj))
obj.Velocity.Y = -obj.Velocity.Y;
if (collidedFromLeft(otherObj) || collidedFromRight(otherObj))
obj.Velocity.X = -obj.Velocity.X;
Ponownie, to może nie być najlepsze rozwiązanie, ale zwykle tak wybieram wykrywanie kolizji.
Ponieważ pytanie jest częściowo identyczne z tym pytaniem , użyję ponownie niektórych części mojej odpowiedzi, aby spróbować odpowiedzieć na twoje pytanie.
Zdefiniujmy kontekst i niektóre zmienne, aby poniższe wyjaśnienie było bardziej zrozumiałe. Formularz reprezentacji, którego będziemy tutaj używać, prawdopodobnie nie pasuje do twoich danych, ale powinno być prostsze do zrozumienia w ten sposób (w rzeczywistości możesz skorzystać z następujących metod, używając innych rodzajów prezentacji, gdy zrozumiesz zasadę)
Rozważymy więc Wyrównaną Osie Obwiednię (lub Orientowaną Obramowanie ) i poruszającą się Istotę .
Obwiednia składa się z 4 boków, a my zdefiniujemy każdą z nich jako:
Side1 = [x1, y1, x2, y2] (dwa punkty [x1, y1] i [x2, y2])
Poruszająca się jednostka jest zdefiniowana jako wektor prędkości (pozycja + prędkość):
pozycja [posX, posY] i prędkość [speedX, speedY] .
Możesz ustalić, która strona AABB / OBB jest uderzona przez wektor, używając następującej metody:
1 / Znajdź punkty przecięcia między nieskończonymi liniami przechodzącymi przez cztery strony AABB i nieskończoną linią przechodzącą przez pozycję bytu (przed kolizją), które wykorzystują wektor prędkości bytu jako nachylenie. (Możesz znaleźć punkt kolizji lub niezdefiniowany numer, który odpowiada równoległym lub nakładającym się liniom)
2 / Po poznaniu punktów przecięcia (jeśli istnieją) możesz wyszukać te, które znajdują się w granicach segmentu.
3 / Na koniec, jeśli na liście wciąż znajduje się wiele punktów (wektor prędkości może przechodzić przez wiele stron), możesz wyszukać najbliższy punkt od początku bytu, używając wielkości wektora od przecięcia do początku bytu.
Następnie możesz określić kąt zderzenia za pomocą prostego iloczynu punktowego.
----------
Więcej szczegółów:
1 / Znajdź skrzyżowania
a / Określ linie nieskończone (Ax + Bx = D), używając ich postaci parametrycznych (P (t) = Po + tD).
Użyłem wartości punktów bytu do zilustrowania metody, ale jest to dokładnie ta sama metoda, aby określić 4 boczne nieskończone linie obwiedni (użyj Po = [x1, y1] i D = [x2-x1; y2-y1] zamiast).
b / Następnie, aby znaleźć przecięcie dwóch nieskończonych linii, możemy rozwiązać następujący układ:
co daje następujące współrzędne dla przechwytywania:
Jeśli mianownik ((A1 * B2) - (A2 * B1)) jest równy zero, wówczas obie linie są równoległe lub zachodzą na siebie, w przeciwnym razie powinieneś znaleźć skrzyżowanie.
2 / Test granic segmentu. Ponieważ jest to łatwe do zweryfikowania, nie ma potrzeby podawania dodatkowych szczegółów.
3 / Wyszukaj najbliższy punkt. Jeśli na liście nadal znajduje się wiele punktów, możemy dowiedzieć się, która strona jest najbliżej punktu początkowego encji.
a / Określ wektor przechodzący od punktu przecięcia do punktu początkowego elementu
b / Oblicz wielkość wektora
4 / Teraz, kiedy już wiesz, która strona zostanie trafiona, możesz określić kąt za pomocą iloczynu punktowego.
a / Niech S = [x2-x1; y2-y1] będzie wektorem bocznym, który zostanie trafiony, a E = [speedX; speedY] być wektorem prędkości bytu.
Używając reguły iloczynu wektorowego wiemy o tym
Możemy więc ustalić θ manipulując trochę tym równaniem ...
z
Uwaga: Jak powiedziałem w innym wątku pytania, prawdopodobnie nie jest to najskuteczniejszy ani najprostszy sposób na zrobienie tego, to właśnie przychodzi mi na myśl, a pewna część matematyki może pomóc.
Nie zweryfikowałem tego konkretnym przykładem OBB (zrobiłem to z AABB), ale to też powinno działać.
źródło
Prostym sposobem jest rozwiązanie kolizji, a następnie przełożenie pola kolizji ruchomego obiektu o jeden piksel w każdym kierunku z kolei i sprawdzenie, które z nich powodują kolizję.
Jeśli chcesz to zrobić „poprawnie” i przy obróconych kształtach kolizji lub dowolnych wielokątach, proponuję przeczytać o Twierdzeniu o Osiach Oddzielających. Na przykład oprogramowanie Metanet (ludzie, którzy stworzyli grę N) ma niesamowity artykuł dla programistów na temat SAT . Omawiają także związaną z tym fizykę.
źródło
Jednym ze sposobów byłoby obrócenie świata wokół prostokąta. „Świat” w tym przypadku to tylko przedmioty, na których Ci zależy: prostokąt i piłka. Obracasz prostokąt wokół jego środka, dopóki jego granice nie zostaną wyrównane z osiami x- / y, a następnie obrócisz piłkę o tę samą wartość.
Ważną kwestią jest to, że obracasz piłkę wokół środka prostokąta, a nie własnego.
Następnie możesz łatwo przetestować kolizję, tak jak w przypadku każdego innego nieobróconego prostokąta.
Inną opcją jest traktowanie prostokąta jako czterech odrębnych segmentów linii i testowanie kolizji z każdym z nich osobno. Pozwala to przetestować kolizję i dowiedzieć się, która strona zderzyła się w tym samym czasie.
źródło
Użyłem stałych kątów w moich obliczeniach, ale to powinno ci trochę pomóc
źródło