Autor Wątek: Fizyka w platformówce 2D  (Przeczytany 2620 razy)

Offline Quavitor

  • Użytkownik

# Kwiecień 13, 2009, 18:14:20
Po tygodniu użerania się z fizyką w mojej platformówce, dochodzę do wniosku, że bez Waszej pomocy się nie obejdzie. Do rzeczy. W jaki sposób powinny wyglądać kolizje w platformówce? Kodem nie rzucę bo to jest bez sensu, ale z grubsza przedstawię jak to u mnie wygląda. Sprawdzam kolizje dla gracza z każdym klockiem na mapie (za pomocą prostokątów). Kiedy wykryję kolizję dosuwam gracza do maksymalnej pozycji w której może się znajdować nie powodując kolizji. Wszystko "prawie" działa. Prawie, bo często zdarza się, że ludek wejdzie w ścianę i nie może się ruszyć, lub nagle wyskakuje do góry albo też dzieją się dziwne nieprzewidziane rzeczy  :-\ Szukałem ale nie znalazłem żadnych materiałów o fizyce do platformówki, a z sampla Platformer Starter Kit (XNA) nie potrafię wyciągnąć tego co mi potrzeba. Jeśli ktoś ma link do materiałów na ten temat, ma czas napisać jak to powinno wyglądać, lub dysponuje źródłem jakiejś działającej platformówki to błagam o pomoc. Dodam jeszcze że korzystam z XNA (może warto wziąć jakiś silnik fizyczny?)

Pozdrawiam i z góry dziękuję za fatygę.  :)

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline C'mons

  • Użytkownik

# Kwiecień 13, 2009, 18:20:33
Z twojego opisu wynika, że kolizja powinna działać. Jeżeli nie działa to znaczy, że problem leży gdzieś indziej.

Offline Quavitor

  • Użytkownik

# Kwiecień 13, 2009, 18:42:18
Postaram się napisać coś więcej o kodzie

Najpierw sprawdzam w którą stronę porusza się gracz (góra-lewo, góra-prawo itd)
Potem przelatuję w pętli po wszystkich klockach i sprawdzam czy kolidują z graczem. Jeśli tak to przesuwam gracza do tyłu aby nie było kolizji (robię to w rożny sposób w zależności od kierunku poruszania się gracza) i wychodzę z pętli. Wydaje mi się, że tu leży problem, ale jeżeli kontynuuje pętlę to już całkiem cyrki wychodzą. Próbowałem zamiast sprawdzać wszystkie klocki opakować całe platformy w prostokąty i to na nich testować kolizje ale efekt jest taki jaki był.

Offline maro

  • Użytkownik

# Kwiecień 13, 2009, 19:46:53
Cytuj
Kiedy wykryję kolizję dosuwam gracza do maksymalnej pozycji w której może się znajdować nie powodując kolizji.
Pewnie gdzieś tutaj jest błąd.

W platformówkach podczas kolizji odwracam kierunek wektora prędkości, czyli coś bardziej zgodnego z fizyką.
If (kolizja) vx = -vx (* opcjonalny parametr "tłumiący")

Powoduje to, że gracz odbija się od ściany.

Offline C'mons

  • Użytkownik

# Kwiecień 13, 2009, 19:59:26
Myślę że problem leży w tym że po wykryciu jakiejkolwiek kolizji cofa gracza i nie sprawdza innych możliwych kolizji. Sprawę powinno rozwiązać usunięcie wychodzenia z pętli przed sprawdzeniem wszystkich kolizji. Ale mówisz że wtedy dzieją się cyrki. Powodem tych cyrków może być fakt że wykrywając jedną z kolizji cofa gracza a potem wykrywa kolejną kolizję i cofa gracza do miejsca gdzie znowu występuje ta pierwsza kolizja ale tym razem jej nie obsłuży ponieważ pętla już to sprawdziła i się nie cofnie by sprawdzić ponownie.
« Ostatnia zmiana: Kwiecień 13, 2009, 20:01:30 wysłana przez C'mons »

Offline Quavitor

  • Użytkownik

# Kwiecień 13, 2009, 21:09:54
W platformówkach podczas kolizji odwracam kierunek wektora prędkości, czyli coś bardziej zgodnego z fizyką.
If (kolizja) vx = -vx (* opcjonalny parametr "tłumiący")

To odpada bo zależy mi na tym, żeby gracz zatrzymywał się na ścianie a nie się od niej odbijał.

Pomyślałem żeby zrobić tak: jeśli została wykryta kolizja to przelatuję jeszcze raz po pętli aż nie znajdzie kolizji, jednak zdarza się że program w nieskończoność przelatuje po tych pętlach.

A może zrobić tak: w pętli sprawdzić z którymi klockami wystąpiła kolizja, a potem na podstawie ich ułożenia i takich tam dobierać akcję? Jest szansa, że to zda egzamin?

Offline C'mons

  • Użytkownik

# Kwiecień 13, 2009, 21:21:22
Tak. To jest dobry pomysł ale mógłbyś od razu sprawdzić zamiast nas pytać. ;)

Offline Quavitor

  • Użytkownik

# Kwiecień 13, 2009, 21:45:41
Tak. To jest dobry pomysł ale mógłbyś od razu sprawdzić zamiast nas pytać. ;)

Pytam, bo straciłem już mnóstwo czasu na kolejne "genialne" rozwiązania (nie będę przytaczać jakich bo spalę się ze wstydu :-[) a implementacja czegoś takiego wydaje się nie być banalna i wole się upewnić czy nie gadam głupot  :)

Offline soku11

  • Użytkownik

# Kwiecień 14, 2009, 02:20:46
Tez wlasnie pisze platformowke na kafelkach :) Ja kolizje rozwiazalem nieco inaczej. Rozbilem ruch gracza na poziomy i pionowy (ruch jest zalezy od dwoch sil). Przy wcisnieciu strzalki w prawo/lewo ustalam punkt w swiecie do ktorego chce isc bohater. Teraz przychodzi czas na kolizje wzgledem osi OX. Tak wiec obliczam poczatkowy i koncowy kafelek na mapie zajmowany przez gracza w osi OY. Pozniej obliczam kafelek aktualnie zajmowany w osi OX oraz kafelek do ktorego nalezy 'punkt celu'. Teraz poprostu przelatuje podwojna petla najpierw po osi OY, pozniej po osi OX od gracza do celu. Jesli po drodze znajde kafelek zajety, to obliczam jego miejsce i zwracam polozenie :) Mozna tutaj tez latwo dodac odbijanie sie: jesli pozycja ostateczna (po funkcji kolizji) rozni sie od tej dla ktorej zostala wywolana, znaczy to ze nastapila kolizja. Wystarczy wtedy ustali graczowi zamiast wektora w osi OX 0 jakas wartosc odbicia i tyle.
Dla osi OY dziala to u mnie analogicznie :)

Mam nadzieje, ze troche pomoglem.
Pozdrawiam.

Offline Quavitor

  • Użytkownik

# Kwiecień 15, 2009, 20:17:51
Uffff wreszcie działa (choć co prawda rozdęło się na >400 linijek. Jak zwykle nie zawiodłem się na Was. Dzięki dla wszystkich, którzy odpowiedzieli (wszystko się przydało). :)

Offline dario

  • Użytkownik

# Kwiecień 15, 2009, 21:44:55
Mimo że problem rozwiązany, dołożę swoje trzy grosze...

Proponowałbym zainteresować się poniższą metodą:

http://www.codeproject.com/KB/GDI-plus/PolygonCollision.aspx?display=Print

SAT (Separating Axes Theorem). Jest to świetna metoda do wykrywania kolizji pomiędzy wielokątami wypukłymi. Korzystam z tego u siebie, również w platformówce.

Przykład uproszczony.
Załóżmy że wszystkie obiekty przechowujesz w tablicy i chcesz sprawdzić czy gracz koliduje z jakimś elementem otoczenia (platformą). Iterujesz przez całą tablicę i sprawdzasz za pomocą SAT czy wystąpiła kolizja gracz -> platforma. Po każdym takim sprawdzeniu otrzymujesz dwie wartości zawierające informację o minimalnym dystansie na jaki należy odsunąć od siebie dwa obiekty, tak aby nie kolidowały ze sobą. Dodajesz tą wartość do pozycji gracza (nie platformy) i już masz problem z głowy. Gracz odsunął się od ściany. Nie musisz wcale zerować jego prędkości. Za każdym razem gdy sprawdzisz kolizję, gracz zostanie przesunięty w odpowiednią stronę, tak aby nie kolidował z danym elementem otoczenia. To wszystko jest przystępnie wyjaśnione w tutorialu (dla języka C#) który ci podałem. Autor umieścił tam również kod źródłowy gotowej klasy.

Jest to naprawdę dobra metoda, korzystam z niej z powodzeniem. Oczywiście jest to dobre rozwiązanie dla nie-kaflowanych map. Dodatkowo należy pamiętać iż ta metoda nie jest ultra-szybka. Można świetnie to połączyć z quad tree aby odrzucić to co jest daleko od gracza i efekty są naprawdę świetne.