Obecnie mam platformówkę z kafelkami terenu (grafika zapożyczona z Cave Story). Gra została napisana od podstaw za pomocą XNA, więc nie używam istniejącego silnika ani silnika fizyki.
Zderzenia kafelków są opisane dokładnie tak, jak opisano w tej odpowiedzi (z prostym SAT dla prostokątów i kół) i wszystko działa dobrze.
Z wyjątkiem sytuacji, gdy gracz wpada na ścianę podczas upadku / skoku. W takim przypadku złapią się płytki i zaczną myśleć, że uderzyli o podłogę lub sufit, których tak naprawdę nie ma.
Na tym zrzucie ekranu gracz porusza się w prawo i spada w dół. Więc po ruchu kolizje są sprawdzane - i po pierwsze, okazuje się, że postać gracza zderza się z płytką 3 od podłogi i pcha w górę. Po drugie, koliduje z kafelkiem obok niego i pcha się na boki - końcowym rezultatem jest to, że postać gracza myśli, że leży na ziemi i nie spada, i „łapie” kafelek tak długo, jak długo na niego wpadnie. .
Mógłbym to rozwiązać, definiując zamiast tego płytki od góry do dołu, co sprawia, że spada on płynnie, ale wtedy zdarza się odwrotna sprawa i uderzy w sufit, którego nie ma, skacząc w górę o ścianę.
Jak podejść do rozwiązania tego problemu, aby postać gracza mogła po prostu spaść wzdłuż ściany, tak jak powinna?
źródło
Odpowiedzi:
Najprostszym, bardziej odpornym na awarie podejście jest po prostu nie sprawdzanie kolizji na ukrytych krawędziach. Jeśli masz dwie płytki ścienne, jedną bezpośrednio nad drugą, to nie należy sprawdzać, czy dolna krawędź górnej płytki i górna krawędź dolnej płytki nie kolidują z graczem.
Możesz określić, które krawędzie są prawidłowe podczas prostego przejścia przez mapę kafelków, przechowując krawędzie zewnętrzne jako flagi w każdej lokalizacji kafelka. Możesz to również zrobić w czasie wykonywania, sprawdzając sąsiadujące płytki podczas wykrywania kolizji.
Istnieją bardziej zaawansowane wersje tej samej techniki, które ułatwiają i przyspieszają również obsługę płytek innych niż kwadratowe.
Zalecam przeczytanie poniższych artykułów. Są przyzwoitymi, prostymi wprowadzeniami do wykonywania podstawowej fizyki i wykrywania kolizji we współczesnych platformówkach (takich jak Cave Story). Jeśli szukasz bardziej oldschoolowego stylu Mario, musisz martwić się kilkoma sztuczkami, ale większość z nich polega na skakaniu i animacjach, a nie na kolizji.
http://www.metanetsoftware.com/technique/tutorialA.html http://www.metanetsoftware.com/technique/tutorialB.html
źródło
Tutaj rozkaz bym zrobił rzeczy ....
1) Zapisz bieżące X, Y znaku
2) Przesuń kierunek X.
3) Sprawdź cały narożnik znaku, pobierając dane kafelka i sprawdź, czy jest ono solidne, wykonując następujące czynności: (X i Y to pozycja znaku)
... aby uzyskać prawidłowe dane kafelkowe z danych mapy
4) Jeśli którykolwiek z kafelków jest solidny, musisz zmusić X do najlepszej możliwej pozycji, przywracając zapisane X i ...
5) Powtórz 2-4, używając Y
Jeśli twoja postać jest wyższa niż płytka, musisz sprawdzić więcej płytek. Aby to zrobić, musisz zapętlić i dodać tileHeight do pozycji postaci Y, aby uzyskać kafelek
Jeśli znak jest szerszy niż 1 blok, zrób to samo, ale zamień characterY, characterHeight, tileHeight itp. Na characterX, characterWidth itp.
źródło
Co się stanie, jeśli zaznaczysz możliwość kolizji w ramach metody ruchu gracza i odrzucisz ruch, który spowodował, że gracz wślizgnął się w inny obiekt? Uniemożliwiłoby to graczowi „wejście” do bloku, a zatem nie mógł znajdować się „na szczycie” bloku pod nim.
źródło
W grze, nad którą obecnie pracuję, napotkałem prawie ten sam problem. Sposób, w jaki to rozwiązałem, polegał na zapisaniu obszaru nakładającej się części podczas testowania kolizji, a następnie obsługiwaniu tych kolizji na podstawie ich priorytetu (najpierw największy obszar), a następnie podwójnym sprawdzaniu każdej kolizji, aby sprawdzić, czy została już rozwiązana wcześniej obsługa.
W twoim przykładzie obszar kolizji na osi X byłby większy niż oś Y, więc byłby obsłużony jako pierwszy. Następnie, zanim spróbuje poradzić sobie z kolizją na osi y, sprawdzi i zobaczy, że nie koliduje już po przesunięciu na osi x. :)
źródło
Prostym, ale nie idealnym rozwiązaniem jest zmiana kształtu pola kolizji gracza, aby nie był kwadratem. Odetnij rogi, aby był podobny do ośmiokąta lub czegoś podobnego. W ten sposób, gdy zderzy się z płytką podobną do tej w ścianie, ześlizgnie się z niej i nie zostanie złapany. Nie jest to idealne, ponieważ nadal można zauważyć, że trochę łapie na zakrętach, ale nie utknie i jest bardzo łatwy do wdrożenia.
źródło
Bardzo podobny problem omówiono w tym samouczku: Wprowadzenie do tworzenia gier . Odpowiednia część filmu jest o 1:44 , wyjaśniając za pomocą diagramów i fragmentów kodu.
Uwaga 14-tilemap.py wykazuje problem z przycinaniem, ale został naprawiony w 15-blocker-sides.py
Nie potrafię dokładnie wyjaśnić, dlaczego ostatni przykład samouczka nie jest przycinany, gdy robi to Twój kod, ale myślę, że ma to coś wspólnego z:
self.resting
w kodzie służy tylko do sprawdzenia, czy gracz może skoczyć. Mimo to nie mogę zmusić gracza do wykonania „podwójnego” skoku ze ściany. Teoretycznie może to być możliwe)źródło
Inną metodą (do której odpowiedziałem na pytanie powiązane z Byte56) byłoby sprawdzenie, czy rozwiązanie kolizji stawia znak w pustym miejscu, czy nie. Tak więc w twoim problemie dochodzi do kolizji z sufitu wewnętrznego prostokąta, aby przesunąć go w górę, co byłoby nielegalne (ponieważ nadal kolidujesz z inną płytką). Zamiast tego przenosisz go tylko wtedy, gdy zostaniesz przeniesiony na wolne miejsce (na przykład, jak kolizja z górnej płytki przesunęłaby cię w lewo), a kiedy znajdziesz tę kolizję, to koniec.
Odpowiedź, którą podałem, miała kod, ale stało się to zbyt skomplikowane. Śledzę wszystkie kolizje w tym czasie i biorę tylko te, które prowadzą do wolnego miejsca. Jednak gdyby ich nie było, myślę, że uciekłem się do zresetowania pozycji postaci do jej ostatniej pozycji, jednak jest to naprawdę brzydkie i może wolisz zaimplementować coś takiego jak oryginalny Mario, w którym porusza się tylko w jednym kierunku lub coś, gdy nie ma rozdzielczości wolnego miejsca jest możliwe. Możesz także posortować tę listę rozdzielczości kolizji i przejść do wolnej przestrzeni tylko w najkrótszej odległości (myślę, że to rozwiązanie byłoby najkorzystniejsze, chociaż nie kodowałem tego).
źródło
Zrobiłem tylko 3 SAT w 3D, więc może nie rozumiem tego dobrze. Jeśli rozumiem twój problem, może to wynikać z nawiązania kontaktów z osią kontaktu, co nie powinno być możliwe, w wyniku czego gracz zachowuje się, jakby istniała podłoga. Jednym z obejść może być użycie zamiast tego kształtu koła dla twojego caracter, wtedy osie kontaktowe uzyskasz tylko w kierunku osi x po uderzeniu w ścianę.
źródło