Platformówka dla wielu graczy - czy zwykle wymagane są poprawki na serwerze dla jednego klienta na serwerze?

10

Obecnie pracuję nad dość prostą platformówką dla wielu graczy. Czytam sporo artykułów na temat technik stosowanych do ukrywania opóźnień, ale wciąż nie potrafię zrozumieć niektórych z tych pojęć. Uważam ten temat za bardzo interesujący i lubię samodzielnie wypróbowywać pomysły, ale myślę, że pytanie o zmianę stosu gamedev będzie bardziej skuteczne w przypadku mojego pytania. Postaram się jak najlepiej opisać moją obecną sytuację i jakie pytanie pojawiło się po drodze.

W tej chwili chcę tylko zsynchronizować jednego gracza z serwerem. Teoretycznie założyłem, że sam gracz z prognozami po stronie klienta nie będzie wymagał poprawek serwera, ponieważ nie ma czynników zewnętrznych, które wpływają na jego ruch. Dlatego mój prototyp ma obecnie tylko jednego gracza zsynchronizowanego z serwerem bez wysyłania poprawek serwera.

Jeśli znasz się na grze w sieci, myślę, że możesz pominąć sekcje kontekstowe, chociaż mogłem również zrobić coś złego po drodze.

Pętla klienta (raz na ramkę, raz co ~ 16,67ms)

Uproszczona pętla klienta wygląda następująco:

  1. Sprawdź lokalne dane wejściowe (WASD) i spakuj je jako akcje (np Type=MoveLeft, Time=132.0902, ID=15.). Zachowujemy spakowane działania, aby ostatecznie wysłać je później. Ponadto bezpośrednio stosujemy pożądaną akcję do lokalnej symulacji fizyki gry. Na przykład, jeśli mamy MoveLeftakcję, przykładamy siłę do prędkości gracza w lewo.

  2. Zaznacz, aby wysłać działania. Aby zapobiec nadużywaniu przepustowości klienta, wysyłaj spakowane akcje tylko w określonych odstępach czasu (np. 30 ms).

  3. Zastosuj modyfikacje serwera. W pewnym momencie zajmie się to deltami i poprawkami otrzymanymi przez serwer i zastosuje je do lokalnej symulacji gry. W przypadku tego konkretnego pytania nie jest ono używane.

  4. Zaktualizuj lokalną fizykę. Uruchom pętlę fizyki na głównym odtwarzaczu. Zasadniczo robi to przewidywanie ruchu gracza po stronie klienta. To dodaje grawitacji prędkości gracza, stosuje prędkość gracza do jego pozycji, naprawia kolizje po drodze itp. Powinienem sprecyzować, że symulacja fizyki jest zawsze wykonywana z ustalonymi deltami sekund (wywoływanymi wielokrotnie w zależności od rzeczywistych delta sekund) .

Pomijam kilka szczegółowych szczegółów na temat fizyki i innych części, ponieważ uważam, że nie są one wymagane do pytania, ale proszę dać mi znać, czy będą one odpowiednie dla pytania.

Pętla serwera (co 15 ms)

Uproszczona pętla serwera wygląda następująco:

  1. Obsługuj działania. Sprawdź otrzymane pakiety akcji od klientów i zastosuj je do symulacji fizyki serwera. Na przykład, moglibyśmy otrzymać 5 MoveLeftakcji i 5 razy przyłożymy siłę do prędkości . Należy zauważyć, że cały pakiet akcji jest wykonywany na jednej „ramce” , w przeciwieństwie do klienta, w którym jest on stosowany natychmiast po wykonaniu akcji.

  2. Zaktualizuj logikę gry. Aktualizujemy fizykę gry, przesuwamy graczy i naprawiamy kolizje itp. Pakowamy również wszelkie ważne wydarzenia, które zostały wysłane do graczy (np. Spadek zdrowia gracza, śmierć gracza itp.) Później.

  3. Wyślij poprawki. Regularnie (np. Co 35 ms) wysyłamy delty innym graczom (np. Pozycje graczy, zdrowie itp.), Jeśli ostatnio się zmieniły. Ta część nie jest obecnie zaimplementowana, ponieważ chcę, aby symulacja pojedynczego gracza dawała te same wyniki na kliencie i serwerze bez poprawek, aby upewnić się, że przewidywanie po stronie klienta działa poprawnie.

Problem

Obecny system działa dobrze w prostych okolicznościach i byłem zaskoczony, widząc, że daje bardzo podobne wyniki przy prostych ruchach poziomych (uważam, że niedokładności wynikają z błędów precyzji zmiennoprzecinkowej):

Synchronizacja działa dobrze przy prostych kolizjach / ruchach

Zignoruj ​​prototypową grafikę. Biały prostokąt = gracz, Czerwone prostokąty = przeszkody, Niebieski = tło

Jednak dostaję błędy synchronizacji po wykonaniu ruchów wrażliwych na czas, takich jak skakanie i zbliżanie się do izolowanej przeszkody:

Synchronizacja nie działa, ponieważ przeskoczyłem określoną przeszkodę w momentach wrażliwych na czas

Teoretycznie spodziewałbym się, że oba zawsze będą miały takie same wyniki, ponieważ klient nie ma żadnych czynników zewnętrznych wpływających na jego pozycję. W praktyce myślę jednak, że rozumiem problem.

Od skakanie wokół przeszkody jak to jest bardzo zależny od czasu odtwarzacza małe wariacje , gdy prędkość jest stosowany do pozycji będą miały repercutions na wynik (np klient mógł odejść tylko w czasie, aby uniknąć kolizji z przeszkoda, podczas gdy serwer zrobi to, ponieważ później odbierze cały pakiet akcji i pozostanie utknięty na przeszkodzie przez krótki czas, zmieniając ostateczny wynik). Różnica między sposobem obsługi klienta i serwera polega głównie na tym, że klient wykonuje wszystkie swoje działania w momencie ich wystąpienia, a serwer wykonuje je wszystkie zbiorczo, gdy je odbiera.

Pytanie

Ten długi kontekst w końcu prowadzi do mojego pytania (dziękuję za przeczytanie do tej pory): Czy normalne jest wymaganie poprawek serwera, nawet jeśli z serwerem jest zsynchronizowany tylko jeden gracz, czy powinienem użyć pewnych technik, aby uniknąć desynchronizacji w sytuacjach wrażliwych na czas ?

Zastanawiałem się nad pewnymi możliwymi rozwiązaniami, z których niektóre nie są dla mnie wygodne:

  1. Wprowadź poprawkę serwera. Po prostu załóż, że jest to normalne zachowanie i koryguj występujące błędy. I tak chciałem to wdrożyć, ale chciałem tylko upewnić się, że to, co do tej pory zrobiłem, jest dopuszczalne.

  2. Użyj podanego czasu klienta, aby zastosować pożądane działania. Myślę, że byłoby to podobne do kompensacji opóźnień, wymagającej „cofnięcia się w czasie” i sprawdzenia ruchu. Coś w stylu korekty serwera, cofnij się w czasie i ponownie zastosuj kolejne działania. Naprawdę nie podoba mi się ten pomysł. Wygląda na skomplikowane, kosztowne w zasobach i wymaga zaufania do czasu klienta (chociaż planuję naprawdę sprawdzić, czy czas wygląda względnie legalnie).

  3. Poproś GameDevelopment StackExchange o świetny nowy pomysł, który naprawi wszystkie moje problemy.

Zaczynam dopiero w świecie gier sieciowych, więc nie krępuj się, poprawiaj / krytykuj / obrażaj dowolne z powyższych koncepcji lub podaj pomysły / zasoby, które mogą pomóc mi w mojej podróży po Cudownym Świecie Sieci. Wybacz mi, gdybym mógł znaleźć swoją odpowiedź gdzie indziej, nie udało mi się.

Dziękuję bardzo za Twój cenny czas.

Jesse Emond
źródło
Twój serwer i klient uruchamiają ramki w różnym tempie. Co się stanie, jeśli klient wykona dwie akcje na kolejnych ramkach, ale serwer dostrzeże między nimi jedną klatkę?
user253751,
@immibis oparł się na stronie gafferongames.com/game-physics/fix-your-timestep, aby zminimalizować ten efekt.
Jesse Emond,

Odpowiedzi:

11

W takich przypadkach lepiej jest pozwolić klientowi być nieco autorytatywnym. W przypadku tak precyzyjnej kontroli bardzo mało prawdopodobne jest uzyskanie dobrego zachowania, nawet przy naprawdę zaawansowanej korekcji i przewidywaniu.

Klient musi przejść od wysyłania wiadomości „skoczyłem” do wysyłania wiadomości „skoczyłem z X, Y w chwili T”. Serwer sprawdza następnie, czy lokalizacja znajduje się w bliskiej odległości od tego, co myśli, że gracz był w czasie T (który można ograniczyć do stosunkowo niewielkiego czasu w przeszłości) w celu ochrony przed oszustwem, a następnie symuluje skok z pozycji klienta wysłane Serwer koryguje klienta tylko wtedy, gdy jest daleko od bicia (zwykle z powodu opóźnienia lub tym podobnych).

Tego rodzaju technika jest używana w połączeniu z korekcją i interpolacją, aby gra czuła się szybko na lokalnym kliencie i wyglądała gładko na zdalnych klientów.

Sean Middleditch
źródło
Bardzo interesujące. Spróbuję to zaimplementować i zobaczę, jak to będzie. Dziękuję bardzo za poświęcenie czasu na udzielenie odpowiedzi. Nawiasem mówiąc, wspomniałeś o „w bliskiej odległości” i „stosunkowo krótkim czasie w przeszłości”, czy po prostu sprawdziłbyś odpowiednio przy stałej odległości i czasie? A może użyłbyś bardziej wyrafinowanych technik, takich jak prowadzenie historii pozycji i średni czas podróży w obie strony klienta (czy cokolwiek innego, naprawdę)?
Jesse Emond
Cokolwiek działa w twojej grze. Zacznij od prostoty, komplikuj ją tylko w takim stopniu, w jakim uznasz to za konieczne. Niektóre serwery ~max(RTT)w przeszłości przechowują historię migawek w poszukiwaniu tyknięć na serwerze, ale nie wiem, czy potrzebujesz konkretnej gry. Może być jeszcze bardziej przydatny w grach typu strzelanka, w których również chcesz wykonać pewien poziom wykrywania trafień / strzału na kliencie i musisz nie tylko wiedzieć, gdzie gracz był 46 ms temu, ale także gdzie jego cel był 46 ms temu i gdziekolwiek ruchome platformy zamykające, gdzie.
Sean Middleditch,
Doskonały. Eksperymentuję i zobaczę, co działa najlepiej. Oznaczając to jako zaakceptowaną odpowiedź, jeszcze raz dziękuję!
Jesse Emond