Jak radzić sobie z szybszymi komputerami w grze wideo klient / serwer w czasie rzeczywistym

15

Pierwszą grę online tworzę przy użyciu socket.io i chciałbym, aby była to gra wieloosobowa w czasie rzeczywistym, taka jak agar.io lub diep.io.

Ale natknąłem się na problem z ustaleniem, jak sprawić, by wszystkie komputery działały z tą samą prędkością.

Mam trzy pomysły na modele, ale żaden z nich nie wydaje się odpowiedni i zastanawiam się, jak robią to normalne gry wideo. (Możesz pominąć czytanie moich pomysłów; dają one tylko sposób na sprawdzenie problemów, które mam).

  1. Serwer pozwala klientom na samodzielne uruchamianie i przekazywanie aktualizacji na serwer, który następnie przesyła je pozostałym klientom. Ma to problem polegający na tym, że niektóre komputery działają szybciej niż inne, pozwalając im na szybszą aktualizację i szybsze poruszanie się po ekranie.

  2. Niech serwer poinformuje klientów, kiedy należy zaktualizować. Mogę wtedy poczekać, aż ostatni klient odpowie (straszny pomysł, jeśli jedna osoba ma powolny komputer), poczekać, aż pierwszy klient odpowie (ponownie, czekając na komunikację przed każdą ramką), lub po prostu wysłać go tak szybko, jak to możliwe (co wydaje się napotykać ten sam problem co numer 1).

  3. Na początku gry poproś serwer, aby powiedział klientom, jak szybko dokonać aktualizacji. Oznaczałoby to, że klient byłby odpowiedzialny za ograniczenie ruchu między tym okresem. Na przykład, jeśli komuś uda się w jakiś sposób dwukrotnie nacisnąć przycisk w tym okresie, wyśle ​​tylko jedno zdarzenie naciśnięcia przycisku. Ma to problem polegający na tym, że niektóre działania będą ignorowane (np. Podwójne naciśnięcie przycisku), a interakcja będzie zależała od zegara klienta, który może nie być zgodny z zegarem serwera. Serwer musiałby wówczas śledzić każdego klienta i upewnić się, że jego aktualizacje są przesyłane we właściwym czasie.

Przeprowadziłem pewne badania , ale artykuły, które czytam, wydają się nie dotyczyć tego, co zrobić, jeśli klient wysyła aktualizacje szybciej niż inni klienci.

W moim szczególnym przypadku mam do czynienia z osobami, które mają większą szybkość klawiatury (ich komputer wysyła więcej aktualizacji klawiatury niż inne komputery).

Jak programiści zwykle sobie z tym radzą?

Pro Q
źródło
1
Z mojego doświadczenia wynika, że ​​nie. Właśnie dlatego istnieją automaty do gier; ci, którzy płacą 5 tysięcy za najnowocześniejszy miotacz ognia, automatycznie mają przewagę nad tymi, którzy nadal używają Commodore 64.
Robert Harvey
1
Więc moja gra będzie wyglądać powoli, ponieważ musimy grać według najniższego wspólnego mianownika? Wydaje się, że serwer gry powinien ustawić tempo i to zależy od klientów, aby nadążyć lub będziesz musiał po prostu opóźnić.
JeffO,
3
Być może nie rozumiem pytania, ale prawdopodobnie szukasz modelu klienta i serwera opartego na kleszczach. gamedev.stackexchange.com/questions/81608/... Zasadniczo po prostu przetwarzasz dane wejściowe i logikę co X razy (zwykle 1 / N sekund, np. 1/60 dla logiki 60 Hz)
Christopher Wirt
4
Po bliższym przeczytaniu pytania wydaje się, że jesteś zbyt skoncentrowany na aspektach gry klienta. Jeśli chcesz „uczciwej” gry wieloosobowej, twój serwer będzie musiał być autorytatywny. Oznacza to, że wszystko, co dzieje się z klientami, jest weryfikowane lub wykonywane przez serwer. Następnie ograniczasz rzeczy stąd, prawdopodobnie poprzez system oparty na kleszczach, jak powyżej.
Christopher Wirt
1
Ach, kod netto w czasie rzeczywistym. Najgłębsze, najciemniejsze miejsce do tworzenia gier. Witaj na statku, kolego!
T. Sar - Przywróć Monikę

Odpowiedzi:

8

Twój trzeci pomysł wydaje się być najbliższy temu, co uważam za branżowe rozwiązanie tego rodzaju problemu.

To, co opisujesz, jest powszechnie nazywane Kleszczami . W każdym ticku dla każdego klienta przetwarzana byłaby stała liczba akcji. Często serwery gier wykonują równoległe działania, jeśli jest to możliwe, ale jest to o wiele bardziej skomplikowany problem.

Kleszcz najprawdopodobniej będzie miał postać 1 / N sekund, gdzie N oznacza liczbę tyknięć na sekundę lub Tickrate. W zależności od przypadku użycia ten rytr może być bardzo często lub bardzo rzadki. Moją osobistą propozycją byłoby uniknięcie tykania powyżej 60 tyknięć na sekundę, chyba że jesteś pewien, że potrzebujesz więcej. Prawdopodobnie nie :)

Działania powinny być atomowe. Na przykład w slither.io akcja taka jak poruszanie się nie powinna natychmiast przetwarzać czegoś takiego jak zerwanie łańcucha, chyba że gracz, którego trafiłeś, już wykonał swój ruch. Może się to wydawać trywialne dla czegoś na poziomie pikseli, ale jeśli masz do czynienia z ruchem opartym na kafelkach, staje się to znacznie bardziej oczywiste i zapewnia uczciwość. Jeśli gracz A przesuwa się na kafelek X, Y, a gracz B znajduje się obecnie na tym kafelku, musisz upewnić się, że do końca tyknięcia gracz B będzie nadal na tym kafelku, aby mogły między nimi nastąpić jakiekolwiek działania.

Ponadto powiedziałbym, aby unikać wykonywania jakichkolwiek obliczeń po stronie klienta, chyba że są one wykonywane niezależnie po stronie serwera. To staje się skomplikowane i kosztowne z fizyką (wiele gier wybiera z tego powodu niższy wskaźnik tykania dla fizyki niż wiele innych akcji i wydarzeń z tego powodu)

Dla odniesienia, tutaj jest dobry link do uzupełnienia własnego zrozumienia serwerów gier i sieci dla wielu graczy.

Na koniec powiedziałbym, że nie pozwól, aby uczciwość zrujnowała twój serwer. Jeśli istnieją exploity, które powodują, że gra jest nieuczciwa, napraw je. Jeśli chodzi o lepszy komputer z niewielką przewagą, powiedziałbym, że może nie być aż tak wielkim problemem.

Christopher Wirt
źródło
3
@ProQ warto zauważyć, że pisanie dobrego kodu sieciowego nie jest trywialne! Jeśli twoja aplikacja nie działa ładnie od samego początku, a kod sieci wydaje się do bani, nie poddawaj się. Nawet ludzie, którzy robią to na co dzień, mają z tym problemy. to jest takie trudne!
T. Sar - Przywróć Monikę
0

Poniższy system zapewnia, że ​​wszyscy klienci i serwer mają ten sam stan gry w dowolnym momencie.

Mieć stan gry zarówno na kliencie, jak i na serwerze.

Gdy klient próbuje użyć polecenia (mysz, klawiatura itp. Inne dane wejściowe), sprawdź jego stan gry, jeśli jest prawidłowy.

Jeśli tak, wyślij polecenie na serwer, bez wykonywania go na wysyłającym kliencie.

Gdy serwer otrzyma polecenie, sprawdź jego stan gry, jeśli jest prawidłowy.

Jeśli tak, odeślij polecenie do WSZYSTKICH klientów z dokładną przyszłą datą po tym, co powinno zostać zakończone na serwerze, a następnie wykonaj działania wymagane przez polecenie z opóźnieniem równym minimalnemu czasowi wysłania polecenia do klientów . następnie zapisz datę, co pomoże w przewidywaniu przyszłości. Jeśli czas zmienia się zbyt mocno, spraw, aby system gry był bardziej deterministyczny.

Gdy klient otrzyma polecenie z serwera, sprawdź jego stan gry, jeśli jest prawidłowy, natychmiast wykonaj czynności wymagane przez polecenie, a następnie spójrz na bieżącą datę i porównaj ją z otrzymaną prognozą daty. Jeśli nie jest poprawny, klient nie jest zsynchronizowany. (Wszyscy klienci o podobnym połączeniu otrzymują jednocześnie)

Jeśli data jest wcześniejsza, masz problem w poprzednim kroku, napraw to. Jeśli data jest nieco później, nic nie rób, jeśli data jest długo później, klient nie jest zsynchronizowany, tj. Klient jest zbyt opóźniony.

Gdy klient nie jest zsynchronizowany, poproś o kopię całego stanu gry na serwerze i użyj go. Jeśli zdarza się to zbyt często, napraw to, ponieważ jest droższe niż wysyłanie poleceń.

Na klientach wyświetlaj rzeczy na ekranie TYLKO wtedy, gdy nie ma już nic do roboty. W prostych scenariuszach funkcja renderowania przyjmuje tylko aktualny stan gry jako dane wejściowe.

Ponadto możesz zoptymalizować wiele, używając systemów predykcyjnych, grupując polecenia, renderując tylko różnice itp.

Sprawdzanie poprawności powinno się różnić, na przykład od serwera zależy ograniczenie żądań poleceń / jednostki czasu.

Walle Cyril
źródło
0

Nie wiem, czy jest to problem bibliotek lub środowiska, z którego korzystasz, ale myślę, że podchodzisz do tego całkowicie źle.

W zdecydowanej większości gier wieloosobowych tylko serwer dokonuje prawdziwych obliczeń. Klientami są tylko głupie maszyny IO, w których prawdziwym problemem związanym z wydajnością jest rysowanie grafiki 3D. I w takim przypadku nie ma znaczenia, czy klient może uruchomić przy 20 lub 200 klatkach na sekundę, ponieważ wpływa to tylko na efekty wizualne. Oznacza to, że „aktualizacja klienta” nie ma absolutnie żadnego znaczenia. Klient może próbować „przewidzieć”, co może obliczyć serwer, ale ma to jedynie na celu złagodzenie poczucia rozgrywki i nie ma faktycznego wpływu na samą rozgrywkę.

wyższe prędkości klawiatury

Nawet nie wiem co to znaczy. Większość ludzi nie potrafi nawet nadążyć za klawiaturami z niższej półki, więc jak wpłynęłoby to na wydajność graczy?

W przeciwnym razie pytanie wydaje się zbyt ogólne i powinieneś skupić się na pojedynczym, rzeczywistym problemie, zamiast próbować rozwiązać „ogólny” problem, którego możesz nawet nie mieć.

Euforyk
źródło
większa szybkość klawiatury nie polega na pisaniu, chodzi o liczbę poleceń, które można wysłać, jeśli przytrzymasz klawisz „przesuń do przodu” lub klawisz „strzelaj”.
gbjbaanb
@gbjbaanb A jak to jest problem? Powinieneś dbać tylko o wciśnięte i zwolnione polecenia. Nie powinieneś się przejmować szybkością aktualizacji.
Euforyczny
Dbasz o to, czy zajmowałeś się wszystkimi zdarzeniami, jakich oczekiwał OP - na kliencie. Więc naciśnięcie w sprawiło, że posunąłeś się do przodu na niewielką odległość, a twoja klawiatura była szybsza niż czyjaś inna, szybciej. Ostatnią rzeczą, którą chcesz, jest stworzenie gry wyścigowej, którą musisz naciskać klawisz, aby przejść do przodu!
gbjbaanb
@ gbjbaanb Nie. To źle. Serwer wie, „gracz idzie naprzód”, a następnie co 1/60 sekundy aktualizuje pozycje WSZYSTKICH graczy na podstawie tego, czy idą naprzód. Tak działają WSZYSTKIE gry. Pętla aktualizacji jest taka sama dla wszystkich podmiotów w grze, a aktualizacje NIE SĄ oparte na zdarzeniach z interfejsu użytkownika.
Euforyczny
1
Nie, to nie było zrozumienie OP, dlatego o to zapytał i dlatego powiedziałeś „Nawet nie wiem co to znaczy”. Jeśli rozumiesz pozycję PO, jego pytanie ma sens. Jeśli OP zakodował swoją grę do pracy z pętlą gry opartą całkowicie na szybkości dostarczania zdarzeń od klienta, to właśnie o to pyta - nie masz racji, stosując hipotetyczny projekt gry do tego, o co OP pyta, niezależnie od tego, czy jego projekt jest zły według większości standardów.
gbjbaanb