Robię szybką grę fizyki, która jest hokeja stołowego. Z dwoma młotkami i jednym krążkiem. Gra działa na iPhonie / iPadzie i robię część dla wielu graczy za pośrednictwem GameCenter.
Tak działa system sieciowy. Klient, który oznaczy dopasowanie jako gwiazdkę, zostanie rozliczony jako serwer, a tym, który akceptuje żądanie dopasowania, jest klient.
„Serwer” ma uruchomioną fizykę, a odpowiedź jest natychmiastowa, a klient ma również uruchomioną fizykę, dzięki czemu wygląda płynnie między wymianą wiadomości. Jako serwer robię to, że przesyłam klientowi moją prędkość krążka i moją pozycję, a klient dostosowuje swoją prędkość krążka / pozycję związaną z serwerem, aby zachować synchronizację. W przeciwnym razie fizyka desynchronizuje się i psuje to.
Gdy opóźnienie sieci jest dobre, poniżej 100 ms wyniki są całkiem dobre, mam płynną grę po stronie klienta, a dziwne zachowanie jest minimalne. Problem występuje, gdy opóźnienie wynosi około 150 do 200 ms. W takim przypadku zdarza się, że krążek mojego klienta już uderzył o krawędź i odwrócony kierunek, ale odbiera komunikat o opóźnieniu z serwera i cofa się nieco, powodując dziwne odczucie zachowania piłki.
Przeczytałem o tym kilka rzeczy:
Kliknij Przykład synchronizacji
Wikipedia na temat synchronizacji zegara
Jak mogę to rozwiązać? O ile przeczytałem najlepszą opcją, którą mam, jest synchronizacja zegara na serwerze / kliencie ze znacznikiem czasu, aby po otrzymaniu komunikatów opóźnień związanych z moim zegarem po prostu zignorowałem to i pozwoliłem symulacji klienta wykonać praca. Zgadzacie się z tym? A ponieważ wysyłam niewiarygodne dane (UDP), mogę otrzymywać wiadomości opóźnione lub wiadomości nieczynne.
Jeśli jest to najlepsze podejście, jak wdrożyć synchronizację zegara. Przeczytałem kroki, jak to zrobić, ale nie do końca to zrozumiałem.
Tu jest napisane:
- Klient stempluje bieżący czas lokalny na pakiecie „żądanie czasu” i wysyła do serwera.
- Po otrzymaniu przez serwer serwer stempluje czas serwera i zwraca
- Po otrzymaniu przez klienta klient odejmuje bieżący czas od czasu wysłania i dzieli przez dwa, aby obliczyć opóźnienie. Odejmuje bieżący czas od czasu serwera, aby określić różnicę czasu między klientem a serwerem, i dodaje opóźnienie o połowę, aby uzyskać prawidłową różnicę zegara. (Jak dotąd ten algothim jest bardzo podobny do SNTP)
- Klient powtarza kroki od 1 do 3 pięć lub więcej razy, za każdym razem wstrzymując kilka sekund. Tymczasowo dozwolony może być inny ruch, ale w celu uzyskania najlepszych rezultatów należy go zminimalizować. Wyniki odbioru pakietów są gromadzone i sortowane według kolejności od najniższego do największego opóźnienia. Mediana opóźnienia jest określana przez wybranie próbki punktu środkowego z tej uporządkowanej listy.
- Wszystkie próbki powyżej około 1 odchylenia standardowego od mediany są odrzucane, a pozostałe próbki są uśredniane przy użyciu średniej arytmetycznej.
Po tym przykładzie chciałbym to:
Udawajmy, że gra się załadowała, a mój czas klienta wynosi teraz 0, więc wysyłam na serwer, że mój czas wynosi 0.
Dostanie się do serwera zajmuje 150 ms, ale zegar serwera już się zaczął i jest o 1 sekundę przed klientem. Kiedy serwer otrzyma wiadomość, czas wyniesie: 1.15 i wyśle ten czas do klienta, czy jesteśmy w porządku? Udawajmy, że nasze opóźnienie jest stałe przy 150 ms.
Teraz klient odbiera czas 1.15 i odejmuje bieżący czas od czasu wysłanego i dzieli przez dwa, aby obliczyć opóźnienie. Które wynosi: 0,3 - 0 = 0,3 / 2 -> 150 ms.
Odejmuje bieżący czas od czasu serwera, aby określić deltę czasu klient-serwer, i dodaje pół opóźnienia, aby uzyskać poprawną deltę zegara:
Czas klienta: 0,3 Czas serwera 1,15
0,3 - 1,15 = 0,85 + opóźnienie (.15) = 1
Jak to jest zsynchronizowane? Czego mi brakuje?
To mój pierwszy raz w trybie dla wielu graczy i sieci, więc jestem trochę zdezorientowany.
Dziękuję Ci.
Odpowiedzi:
Algorytm opublikowany był poprawny, ale w twoim przykładzie zapominasz o czasie, jaki zajmuje pakiet serwera, aby dotrzeć do klienta, więc:
Teraz, jak widać, jeśli klient zmieni zegar na 1,15, będzie o 0,15 za serwerem, dlatego musisz dostosować się do Pinga (inaczej Round Trip Time [RTT]). Oto pełne obliczenie czasu delta na wielu etapach:
To daje nam prawidłowy czas delta wynoszący 1,00 sekundy
źródło