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).
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.
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).
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ą?
źródło
Odpowiedzi:
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.
źródło
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.
źródło
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ę.
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ć.
źródło