Autor Wątek: Multiplayer 2D - poruszanie się  (Przeczytany 4972 razy)

Offline Bula

  • Użytkownik

# Październik 29, 2011, 14:38:38
Witam.

Mam pewien problem z moją grą MMORPG 2D. Mam coś takiego, że klient wysyła do serwera swoją pozycję na mapie, serwer odczytuje to i wysyła do klientów. Na lanie wszystko działa pięknie, ale np. przez Hamachi już postacie chodzą 3x wolniej. Przypuszczam że to przez to, że przy Delay(15) klient męczy serwer swoimi pakietami, a serwer po prostu nie wyrabia żeby w takim czasie poodsyłać to wszystko do każdego klienta i stąd ta zmułka.
I tutaj mam problem z zaplanowaniem jak to ma działać. Chcę jakoś przerobić ten skrypt, żeby był wydajniejszy. Gra to typowe MMORPG 2D z widokiem od góry i plansza zrobioną z kafelków (http://warsztat.gd/projects.php?x=view&id=2232).
No i mam ten delay 15ms i załóżmy że zwiększam go. I tutaj postać która przesuwa się o 2px zaczyna chodzić jeszcze wolniej po kratkach. Mogę zmienić przeskok na 4 px i to faktycznie działa, ale przy 4px przeskok jest już bardzo widoczny.
Zamotałem się już w tym, możecie coś poradzić?

Offline Mr. Spam

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

Offline SnowyMan

  • Użytkownik

# Październik 29, 2011, 15:08:13
Od razu mówię, że to co tutaj napiszę może być dalekie od prawdy gdyż ostatnio kodowaniem sieciowym zajmowałem się jakiś rok temu.

No więc tak - są dwa typy wysyłki pakietów - przez TCP lub UDP. Jak dobrze pamiętam TCP kolejkuje wszystko i stąd twoje spowolnienia. UDP nie kolejkuje i wysyła kolejny pakiet jeszcze zanim dojdzie poprzedni <- ten sposób jest wskazany dla ciebie. Poza tym nie ma według mnie sensu trzymać pozycji graczy w klientach i ją wysyłać - lepiej trzymać wszystko co dotyczy gracza na serwerze a od klienta przesyłać tylko zdarzenia jak np. ruch do przodu albo atak.

edit.
Aha i zupełnie nie rozumiem o co ci chodzi z tym Delay() ale poruszanie się postaci powinno być zrobione na timerach a nie wstrzymywaniu czasu...

edit2.
Tak może poza tematem... masz w planach wersją dla linux'a? Projekt bardzo mi się podoba i chętnie bym sobie w coś takiego pograł na laptopie :)
« Ostatnia zmiana: Październik 29, 2011, 15:13:20 wysłana przez SnowyMan »

Offline Xender

  • Użytkownik

# Październik 29, 2011, 15:24:33
Różnica między TCP a UDP jest taka, że TCP jest zorientowany na połączenie tj. gwarantuje, że wszystkie pakiety dotrą do odbiorcy (przesyłanie potwierdzeń), że zostaną przez odbiorcę przetworzone w kolejności, w jakiej zostały wysłane, a wypadku nagłego zerwania (nie ładnego zakończenia, tylko zerwania) połączenia nadający dowie się o tym przy najbliższej operacji na danym sockecie.

UDP jest bezpołączeniowy - po prostu wysyła pakiet i jego dalsze losy go nie obchodzą. Korzystanie z UDP w tym przypadku jest bez sensu - niezauważalna utrata pakietów i zmiana ich kolejności jest niedopuszczalna, więc konieczna by była implementacja własnych mechanizmów kolejkowania i potwierdzania - wyważanie otwartych drzwi.

fakt, UDP jest szybszy, ale ma to jak widać swoją cenę. A implementacja własnych mechanizmów zabezpieczeń w UDP raczej nie będzie wydajniejsza od tego co już jest w TCP.

Offline Bula

  • Użytkownik

# Październik 29, 2011, 15:38:16
Czyli powinienem przerobić mechanike poruszania się?
Aktualnie jest tak, że:
Wciskam przycisk np. strzałkę w prawo > klient przesuwa mapę (rusza się mapą, a nie postacią, jak w kżdym rpg 2D) a następnie wysyła do serwera informacje o położeniu mapy. Serwer rozsyła to do reszty klientów i tak wyświetlane są postacie.

Myślę żeby przerobić to tak:
Wciskam klawisz > klient wysyła do serwera że klawisz został wciśnięty, serwer modyfikuje położenie gracza i odsyła wynik do klientów. Co sądzicie?
A może jest jeszcze lepsze rozwiązanie jakieś o którym nie wiem?

Offline Rydwan

  • Użytkownik

# Październik 29, 2011, 15:44:30
Temat rzeka.

Przy 10 polaczeniach nie bedzie roznicy czy to TCP czy UDP.

Wiekszosc liderow Real-Time MMORPG uzywa TCP/UDP, zaleznie od priorytetu/waznosci wysylanych danych.

Jak to powinno wygladac w skrocie:
Pamietaj ze klient, to nie tylko pusty bezmozgi robot, ktory wykonuje na slepo polecenia serwa. On rowniez sprawdza kolizje i wykonuje czynnosci przed tym jak otrzyma pakiet. Gwarantuje to plynnosc gry, nawet jak czasem troszke przylaguje.
Dodatkowo pamietaj, by obslugiwac wiekszy obszar niz widoczny na ekranie, tak ze 2-3 kratki zapasu(nie musza to byc wszystkie info z tych pol wyslane).

Mysle, ze Cie to nakieruje troche.
« Ostatnia zmiana: Październik 29, 2011, 15:46:15 wysłana przez Rydwan »

Offline Bula

  • Użytkownik

# Październik 29, 2011, 15:52:10
Kolizje mam w kliencie :)
Ale wracając do poruszania się.
Czy takie rozwiązanie jak:
serwer wysyła dane tym na którym kafelki stoi gracz lub przechodzi z którego na który (2 wartości, stoi na xy, idzie z xy na sąsiadujący), a za odtworzenie płynnego przejścia między kafelkami odpowiada klient
byłoby ok?
Bo aktualnie jest tak że kafelek ma 32x32 i serwer wysyła sobie że gracz jest np na pozycji 325 co daje 10 kafelków i 5/32 następnego. No i fakt faktem musi wysyłać to 32 razy przy każdym poruszeniu się o pixel postaci.
To rozwiązanie jakie mam teraz chyba nie jest dobre, nie?

Offline Snejk47

  • Użytkownik

# Październik 29, 2011, 15:56:18
Cytuj
Myślę żeby przerobić to tak:
Wciskam klawisz > klient wysyła do serwera że klawisz został wciśnięty, serwer modyfikuje położenie gracza i odsyła wynik do klientów. Co sądzicie?
Tak działa to przynajmniej w Tibii i się sprawdza.

Offline Rydwan

  • Użytkownik

# Październik 29, 2011, 16:05:05
Chcesz by poruszal sie co pixel, czy to tylko dla animacji?
Jesli dla animacji, to klinet sie tym zajmuje. Sererw wysyla tylko pozycje gracza.
I klinet sie rusza nie czekajac na serwer, jesli bedzie niepoprawne, cofnie sie, na pozycje, ktora przyslal serwer.

Ale to tylko tak prosto brzmi, bo tutaj najwarzniejszy i zarazem najtrudniejszy element to poprawna synchronizacja i to u Ciebie jest lub bedzie glownym problem.

Offline Bula

  • Użytkownik

# Październik 29, 2011, 16:06:34
No ale oprócz pozycji gracza musi wysyłać też w którą stronę porusza się gracz (jeśli nie stoi w miejscu), tak?

Offline Rydwan

  • Użytkownik

# Październik 29, 2011, 16:09:48
No ale oprócz pozycji gracza musi wysyłać też w którą stronę porusza się gracz (jeśli nie stoi w miejscu), tak?
To nie jest najlepszym pomyslem, gdyz rozwala/utrudnia synchronizacje.
A na co dla serwera wysylac nasza pozycje?


Docelowa pozycje, na ktora chcemy sie udac.

Offline Bula

  • Użytkownik

# Październik 29, 2011, 16:22:54
No, ale wtedy przeskakuje pozycja do kafelek. A skąd klient ma wiedzieć w którą stronę przez ten czas ma iść o 32px płynnie (animacja)? Mowa tutaj oczywiście nie o postaci którą kierujemy, ale o innych graczach.
Załóżmy gracz stoi na pozycji x=34; y=21; I serwer wysyła to 34 u 21, gracz jest wyświetlany na tej pozycji. Ale np idzie sobie dalej i przeszedł na 35. No i serwer wysyła że jest na 35 i gracz pojawia się na x=35 po prostu przeskakując...

Offline Xender

  • Użytkownik

# Październik 29, 2011, 16:30:58
@Bula - możesz to animować w kliencie. Rozumiem, że problemem jest to, że rozpoczęcie animacji przejścia z pola 34->35 w momencie, gdy serwer prześle komunikat że postać JUŻ jest na polu 35 spowoduje opóźnienie. Pierwsza moja myśl: niech klient przesyła swoje ruchy natychmiast (gdy tylko ruch się zacznie) do serwera, a serwer niech rzesyła do klienta pole, na którym postać dopiero MA się pojawić, i KIEDY ma się poawić (wyliczone z szybkości postaci).

Albo przesyłanie z serwera informacji w którą stronę zmierza postać - nie wiem, w czym to niby przeszkadza synchronizacji. Tu nawet jest prościej - klient wysyła do serwera informacje o rozpoczęciu i zakończeniu ruchu. Serer wysyła to samo do klientów, w których polu widzenia jest postać. Klient docelowy to sobie ładnie animuje z czasu trwania ruchu i prędkości postaci która się porusza. Synchronizację robi TCP więc nie ma nic do tego.

Ewentualnie jeśli nie chcemy uzależniać tego od czasu: klient wysyła informacje o każdym ruchu z pola na pole (kierunku), a serwer to przesyła do pozostałych klientów.
« Ostatnia zmiana: Październik 29, 2011, 16:33:30 wysłana przez olo16 »

Offline ison

  • Użytkownik

# Październik 29, 2011, 16:33:49
Też kiedyś klepałem kafelkowe mmorpg, ja rozwiązałem problem w ten sposób:
Klient się rusza -> wysyła pakiet do serwera o tym, w którą stronę chce się poruszyć -> serwer decyduje czy może się tam ruszyć -> wysyła pakiety do innych klientów zawierające tylko i wyłącznie aktualną pozycję owego gracza. To klient już sam zdecyduje, jaką animację powinien wyświetlić oraz to, w którym miejscu między 2 kaflami (podczas ruchu) ma się znajdować aktualnie gracz.
Klient wie, że gracz i jest na pozycji 30,30 -> dostaje pakiet z pozycją 31,30 więc odpala animację ruchu w prawo oraz płynne przejście z kafla na kafel.
« Ostatnia zmiana: Październik 29, 2011, 16:36:15 wysłana przez ison »

Offline Bula

  • Użytkownik

# Październik 29, 2011, 16:38:27
Dzięki za odpowiedzi!
Jutro postaram się zmodernizować to co mam aktualnie i zobaczymy co z tego wyjdzie.
Jeszce raz dzięki, pomogliście mi bardzo :)

Offline Bula

  • Użytkownik

# Październik 30, 2011, 14:58:49
Witam ponownie.
Zaobserwowałem jedną ważną rzecz. Pomijając już konstrukcje systemu chodzenia, problem jest chyba innej natury. Zrobiłem coś takiego, że postać przeskakuje co 1 kratkę i nic to nie dało - to nie muli sama mechanika poruszania się, tylko cały klient.

Wymiana informacji z serwerm wygląda tak:
Jest sobie gra, w SDL, gdzie wszystko wykonuje się w pętli while(!exit).
Pętla ma ustawiony delay 15ms, czyli przerwa między jedną pętlą a drugą wynosi właśnie tyle.
W pętli znajdują się fukncje wysyłania i odbierania informacji.
Czyli klient męczy serwer co 15ms.

Przypuszczam że właśnie przez to są te zmuły. Bo jak już mówiłem, nie muli samo chodzenie tylko cały klient, który oczekuje odpowiedzi od serwera co 15ms a że w tak krótkim czasie jej nie otrzymuje, zacina się na kolejne milisekundy aż ją otrzyma.

I tutaj mam problem, jak to 'odmulić'? Zwiększenie delaya skutkuje tym, że owszem, połączenie działa lepiej, ale znowu klient zaczyna klatkować.