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:
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 mamyMoveLeft
akcję, przykładamy siłę do prędkości gracza w lewo.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).
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.
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:
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
MoveLeft
akcji 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.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.
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):
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:
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:
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.
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).
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.