Jak znaleźć komórki siatki 2D omiatanej przez ruchomy okrąg?

9

Tworzę grę opartą na siatce 2D, z niektórymi komórkami możliwymi do przejścia, a niektóre nie. Obiekty dynamiczne mogą się poruszać w sposób ciągły, niezależnie od siatki, ale muszą zderzać się z nieprzejezdnymi komórkami.

Napisałem algorytm do śledzenia promienia na siatce, który daje mi wszystkie komórki, które się przecinają. Rzeczywisty obiekt nie ma jednak wielkości punktowej; Obecnie reprezentuję je jako kręgi. Ale nie mogę znaleźć skutecznego algorytmu do śledzenia poruszającego się koła. Oto zdjęcie tego, czego potrzebuję: wprowadź opis zdjęcia tutaj

Liczby pokazują, w jakiej kolejności koło zderza się z komórkami siatki. Czy ktoś zna algorytm znajdowania takich kolizji? Najlepiej w C #.

Aktualizacja Krąg może być większy niż pojedyncza komórka siatki.

Nieważne
źródło
mmh, dlaczego 3 zderzają się PRZED 4?
FxIII
@FxIII Właściwie przesunąłem koło na obrazku, a ono uderzyło 3 przed 4. Tylko ledwie, ale nadal przed.
Nevermind

Odpowiedzi:

6

Myślę, że twój rysunek jest trochę mylący, ponieważ wybierasz rysowanie pociągnięć od punktu na okręgu stycznego do twojego kierunku ruchu. Widzę, że zderzenia z krawędziami siatki zdarzają się, gdy TOP i LEWE punkty twojego okręgu dotykają krawędzi.

Niech C będzie twoim środkiem ir promieniem, więc P ' = C + ( r , 0) i P " = C + (0, r).

Jeśli D jest wektorem kierunku (versor), masz dwie linie:

R '= D · t + P' ,

R "= D · t + P"

Po prostu musisz znaleźć przecięcie tych linii z liniami równania:

y = i y = i, które są krawędziami twojej siatki!

Rozwiązanie jest łatwe, ponieważ musisz po prostu wziąć pod uwagę składową x lub y R 'i R ". Znajdziesz wartość t s dla każdego wstawienia, a punkty dla tych ts , po prostu posortuj te punkty według t, a ty są skończone.

Wierzę, że możesz łatwo powiedzieć, która komórka jest trafiona, jeśli znasz punkt przecięcia.

Działa to, jeśli r <1 (szerokość i wysokość komórki).

Działa to również w innych przypadkach, po prostu biorąc pod uwagę P i P " . Wybieramy GÓRA i LEWO ze względu na kierunek, DOLNĄ i PRAWĄ należy brać pod uwagę w przeciwnym kierunku, rozumiesz dlaczego.

Teraz spójrz na ten obraz: duże koło

Okrąg jest większy niż pojedyncza komórka i przypuszczamy, że zmierza w tym samym kierunku, co rysunek. P1 to pierwszy punkt, który się dotknie, P2 to drugi, P3 jest bezużyteczny, ponieważ znajduje się w dolnej połowie. Musisz tylko rzucić promienie z P1 i P2, jak widzieliśmy wcześniej, i zrobić to samo dla linii pionowych.

Ogólnie rzecz biorąc, będziesz mieć inne punkty początkowe oraz TOP i LEWE, z których strzelasz promieniami, im większy jest twój okrąg, tym więcej promieni rzucasz.

Szczerze mówiąc, można uniknąć strzelania do wszystkich promieni z uwzględnieniem geometrii, ale może to utrudnić zrozumienie.

FxIII
źródło
Tak, sam wymyśliłem punkty P 'i P ", ale nie mogłem wymyślić, co zrobić, gdy okrąg jest większy niż pojedyncza komórka. Dodatkowe punkty naprawdę mają sens (i oczywiście potrzebuję tylko dodać promienie między P' i P ”)
Nevermind
Można dokonać rozważań geometrycznych, które upraszczają obliczenia, ale korzystanie z implementacji może prowadzić do takich samych wyników z doświadczenia.
FxIII
Czy jasne jest, że musisz osobno testować poziome i pionowe linie siatki?
FxIII
Myślę, że musisz również sprawdzić, kiedy okrąg pokrywa wierzchołek siatki, ponieważ koło zderzy się z sąsiednią komórką po przekątnej w jego rogu, ale niekoniecznie będzie to górny / lewy / dolny / skrajny prawy punkt na okręgu, który go dotyka jako pierwszy (a kolizję wykryjesz zbyt wcześnie). Przykład: kwadraty 3,4,5 na przykładowym diagramie w pytaniu. Są one trafiane w kolejności (3, a następnie 4, a następnie 5), ale algorytm wykryłby jednocześnie 4 i 5.
finnw
@ finnw dotykają jednocześnie tylko wtedy, gdy cicle jedzie dokładnie w kierunku dwusiecznej.
FxIII
1

Jeśli chcesz użyć algorytmu kolizji promieni, możesz wybrać osiem punktów na każdym kole (w przyrostach co 45 stopni, wyrównanych z kwadratową siatką) i użyć kolizji promieni między odpowiednimi punktami (tj. Od góry jednego kółko na górę drugiego). Połączenie wszystkich tych zderzeń promieni stanowi cały zestaw przecinających się komórek.

Prawdopodobnie można by to nieco poprawić - na przykład używając odcinka linii od środka jednego koła do środka drugiego, ale przedłużonego po obu stronach o promień koła, a także równoległych odcinków linii na po obu stronach na końcach kręgów.

TreDubZedd
źródło
8 promieni prawdopodobnie zagwarantuje wszystkie skrzyżowania, ale nie da ich we właściwej kolejności. A do kolizji potrzebuję porządku, a nie tylko listy komórek.
Nevermind
Rozszerz swój algorytm kolizji promieni, aby zachować wartość t dla każdej kolizji. Po uzyskaniu unii komórek można sortować według wartości t, aby uzyskać prawidłową kolejność.
TreDubZedd
Ale jak mogę porównać wartość t różnych promieni?
Nevermind
Jeśli zawsze zaczynasz z tego samego okręgu, punktami przecięcia będą odległości od tego okręgu. Kiedy dojdziesz do komórki, którą już widziałeś, jeśli wartość t bieżącej kolizji jest mniejsza niż poprzednia, użyj jej ... w przeciwnym razie odrzuć przecięcie (zachowując oryginał).
TreDubZedd
1
Możesz być w stanie uciec tylko dwoma promieniami po bokach koła prostopadłego do ruchu, wtedy możesz zobaczyć, które płytki zostaną uderzone przez promienie, a możesz sprawdzić resztę, aby sprawdzić, czy ich środki spadają między dwoma promieniami. Jedyne, co powinno być pominięte, to kolizje na początku lub na końcu koła, ale to tylko dwa koła i można je łatwo obsłużyć. To może być nieco wolniejsze niż osiem promieni, nie jestem pewien; ale nie trzeba będzie skalować liczby na podstawie rozmiaru koła.
Lunin
1

Nie twierdzę, że jest to idealna analogia, ale możesz pomyśleć o algorytmie liniowym Bresenhama . Pomocna może być modyfikacja tego algorytmu lub jednego z jego rozszerzeń, zwłaszcza jeśli połączymy go z innymi postami i komentarzami. Zazwyczaj ten algorytm nie dotyczy zamawiania, ale wydaje mi się, że można go dodać dość trywialnie.

Ryan
źródło
Też o tym myślałem, ale moim zdaniem nie jest to właściwy algorytm. Bresenham wybiera tylko jeden piksel, potrzebuje wszystkiego. Trudno byłoby przystosować bresenham do okręgu o wielkości zaledwie jednego piksela.
zacharmarz
Używany przeze mnie znacznik promienia jest właściwie trochę oparty na algorytmie Bresenhama. Mam problem z uogólnieniem go od cienkiej linii do „grubej”, a konkretnie zamiatanej po okręgu.
Nevermind