Interpolacja pozycji w grze wieloosobowej

14

Aby zaoszczędzić przepustowość w mojej grze wieloosobowej , nie aktualizuję każdego obiektu co tik serwera, zamiast tego każdy obiekt ma updateRate, który informuje grę, że ten obiekt ma być aktualizowany co tik X serwera.

Kiedy otrzymuję komunikat o aktualizacji dla obiektu, obliczam czas, kiedy spodziewam się następnej aktualizacji:

origin = serverCurrentPosition
diff = serverNextPosition - origin
arriveTime = now + timeBetweenTicks * updateRate

Podczas rysowania obiektu obliczam czas pozostały do ​​następnej aktualizacji i odpowiednio interpoluję pozycję:

step = 100 / timeBetweenTicks * updateRate
delta = 1 - step * ((arriveTime - now) / 100)
position = origin + diff * delta

Działa ... ale na rysunku wciąż jest trochę drgania, chociaż w mojej teorii wszystko powinno działać dobrze, ponieważ skalowanie powinno zająć pewną ilość opóźnienia, prawda?

Pytanie brzmi więc, czy to najlepsze podejście? Czy powinienem umieścić rzeczywiste opóźnienie w obliczeniach? Jeśli tak, jak mam to zrobić? Przeprowadziłem kilka eksperymentów, ale drgania tylko się pogorszyły.

Ivo Wetzel
źródło
Cześć Ivo. Myślę, że to dobry temat, ale nie jest jasne, co robi twój kod - na przykład skąd pochodzi serverCurrentPosition, serverNextPosition, timeBetweenTicks?
CiscoIPPhone
To wysyła dane aktualizacji, które pochodzą z serwera.
Ivo Wetzel,

Odpowiedzi:

11

Masz fluktuacje, ponieważ opóźnienie ciągle się zmienia. Oznacza to, że chociaż serwer wysyła aktualizacje dokładnie co timeBetweenTickstyk, klient otrzymuje je po pewnym zmiennym czasie. Ten czas jest prawdopodobnie bliski timeBetweenTicksdobrego połączenia, ale nie do końca równy (a poza tym możesz mieć opóźnienie serwera i różne prędkości zegara na serwerze i kliencie).

Tak więc, kiedy polegasz na otrzymaniu aktualizacji w dokładnie określonym czasie, stale docierasz do miejsca docelowego nieco przed / po faktycznej aktualizacji. Stąd jitter.

Prostym podejściem do zmniejszenia jittera jest użycie „gumowania”, co sugeruje Martin w innej odpowiedzi. Zasadniczo po otrzymaniu aktualizacji nie zmienia się natychmiast pozycji obiektu. Zamiast tego, jeśli pozycja klienta i pozycja serwera różnią się tylko nieznacznie, zaczniesz interpolować pozycję klienta, aby po pewnym czasie (powiedzmy, w połowie drogi do następnej aktualizacji) pozycje klienta i serwera zbiegły się.

Kolejny pomysł na zmniejszenie drgań w konfiguracji: ponieważ przesyłasz zarówno współrzędne „bieżące”, jak i „następne”, możesz obliczyć prędkość obiektu. Następnie, gdy aktualizacja się opóźnia, nie zatrzymujesz obiektu w jego miejscu docelowym (tj. W pozycji „następnej”), ale kontynuujesz przesuwanie go z tą samą prędkością. Jeśli twoje obiekty nie zmieniają gwałtownie prędkości, to naprawdę poprawi płynność ruchu na kliencie.

Nieważne
źródło
Już jest tak, że obiekty się nie zatrzymują, poruszają się do momentu otrzymania następnej aktualizacji. Wydaje się również, że użycie przyspieszenia sprzętowego na kanwie HTML znacznie zmniejsza efekt fluktuacji. Może po prostu oszalałem po tak długiej pracy nad tym.
Ivo Wetzel,
To całkiem możliwe. Jeśli włączenie przyspieszenia powoduje zwiększenie liczby klatek na sekundę, wzrasta prawdopodobieństwo obsługi informacji o aktualizacji w odpowiednim momencie.
Nevermind,
9

Problem ten rozwiązałem już wcześniej z pewnym powodzeniem, stosując podejście, które nazywam „cieniami sieci”. Nie wiem, czy robią to inni ludzie, ale zawsze działało to dla mnie.

Każdy byt, który jest synchronizowany w sieci, ma niewidoczny byt sieciowy. Gdy aktualizacja nadchodzi z sieci, teleportujesz cień bezpośrednio do pozycji, w której sieć mówi, że powinna być, a następnie powoli interpolujesz lokalny widoczny obiekt w kierunku cienia w czasie.

W mojej poprzedniej odpowiedzi tutaj zamieściłem wiele szczegółów na temat tego podejścia

Jaskółka oknówka
źródło
Hm, zrobiłem coś takiego we wcześniejszej wersji, niedokładność zmiennoprzecinkowa czasami była naprawdę zła, mam dość duże przedziały czasowe między aktualizacjami, do 300 ms dla niektórych obiektów, ale może po prostu zrobiłem to źle, dam to strzał, kiedy znajdę trochę wolnego czasu :)
Ivo Wetzel
precyzja zmiennoprzecinkowa naprawdę nie powinna w to wchodzić! Czy przeczytałeś moją linkowaną odpowiedź na stackoverflow? Obejmuje wszystkie szczegóły dotyczące wdrażania tego rodzaju rzeczy.
Martin