Przejdź do treści

Photon PUN vs Mirror vs Unity Netcode: co wybrać do sieciowej gry multiplayer?

Photon PUN vs Mirror vs Unity Netcode: co wybrać do sieciowej gry multiplayer?
Rate this post

Prototyp działał nienagannie na lokalnym komputerze. Dwie instancje gry otwarte obok siebie idealnie synchronizowały ruch postaci, pociski trafiały w cel bez najmniejszego opóźnienia, a fizyka zachowywała się w pełni przewidywalnie. Zderzenie z rzeczywistością nastąpiło w momencie pierwszej próby połączenia przez publiczny Internet: desynchronizacje, teleportujące się postacie i pytania o to, kto właściwie zapłaci za serwery, gdy do gry wejdzie tysiąc osób naraz.

Wybór frameworka sieciowego to jedna z nielicznych decyzji w produkcji gier w Unity, której cofnięcie w zaawansowanym stadium projektu graniczy z koniecznością napisania całego kodu rozgrywki od nowa. Logika multiplayer nie jest jedynie nakładką na grę jednoosobową; przenika kontrolery postaci, system ekwipunku, animacje, detekcję trafień i interfejs użytkownika. Wybrana technologia narzuca architekturę: to ona definiuje, kto podejmuje decyzje o stanie świata, w jaki sposób przesyłane są pakiety danych oraz jak wygląda późniejsze utrzymanie infrastruktury serwerowej.

Wokół silnika Unity przez lata wyrosło wiele rozwiązań do obsługi trybu wieloosobowego, co bywa mylące. Obok dojrzałych i powszechnie sprawdzonych narzędzi, takich jak Photon PUN 2 oraz otwartoźródłowy Mirror, dynamicznie rozwija się oficjalne rozwiązanie silnika — Unity Netcode for GameObjects (oraz jego wysokowydajny brat oparty na ECS, Netcode for Entities). Choć wszystkie te biblioteki mają wspólny cel – sprawić, by gracze mogli bawić się wspólnie w czasie rzeczywistym – każda z nich przyjmuje zupełnie inną filozofię działania, koszty wdrożenia i wymagania techniczne.

Wybór nie powinien być podyktowany modą ani liczbą gwiazdek na GitHubie. Zależy on wprost od specyfiki projektowanego tytułu: od tego, czy tworzysz kameralną grę kooperacyjną dla czterech znajomych, asymetryczny horror z pokojami prywatnymi, czy dynamiczną strzelankę z rankingiem i serwerami dedykowanymi. Zanim przyjrzysz się poszczególnym narzędziom, konieczne jest zrozumienie podstawowych modeli architektury sieciowej, które determinują sukces lub porażkę projektu.

Zanim porównasz narzędzia, określ model sieciowy swojej gry

Błędem popełnianym na etapie planowania jest wybór narzędzia sieciowego przed ustaleniem fundamentalnych zasad przepływu informacji między graczami. Framework jest jedynie zestawem bibliotek ułatwiających serializację, transport i wywoływanie zdalnych procedur; nie zadecyduje za twórcę o tym, kto ma władzę nad stanem świata gry.

Host, dedykowany serwer i model client-authoritative

Pierwszym kluczowym rozróżnieniem jest podział na to, gdzie faktycznie wykonuje się symulacja rozgrywki. W tradycyjnym modelu Dedicated Server (serwer dedykowany) gra działa w trybie bezgłowym (headless) na zewnętrznej maszynie w chmurze lub centrum danych. Żaden z graczy nie ma bezpośredniego wpływu na pamięć procesu serwerowego, a serwer jest jedynym autorytetem (server-authoritative). Sprawdza poprawność każdego kroku, strzału czy zakupu przedmiotu. Zapewnia to maksymalne bezpieczeństwo przed modyfikacjami pamięci i oszustwami (ang. cheating), ale wiąże się ze stałymi kosztami wynajmu infrastruktury obliczeniowej, niezależnie od tego, czy gra przynosi zyski. [2]

Na przeciwległym biegunie znajduje się architektura Peer-to-Peer oraz model Listen Server / Host-Client. W tym wariancie jeden z graczy staje się jednocześnie serwerem i klientem – jego maszyna przetwarza logikę świata i rozsyła dane do pozostałych uczestników. Rozwiązanie to drastycznie tnie koszty infrastruktury, ponieważ deweloper nie musi opłacać maszyn wirtualnych do symulacji. Pojawiają się jednak poważne wyzwania:

  • Zaleta gospodarza (Host Advantage): Gracz pełniący rolę hosta ma zerowe opóźnienie (ping 0 ms), podczas gdy inni gracze zmagają się z lagami, co w grach zręcznościowych natychmiast rodzi poczucie niesprawiedliwości.
  • Podatność na oszustwa: Host ma pełny dostęp do pamięci gry, może modyfikować wartości zdrowia, kolizji czy współrzędne bez żadnej weryfikacji ze strony niezależnego arbitra.
  • Migracja hosta (Host Migration): Jeśli gracz będący serwerem wyjdzie z gry lub straci połączenie z siecią, sesja zostaje przerwana, chyba że framework implementuje skomplikowany proces wyboru nowego hosta i bezbłędnego przekazania mu pełnego stanu rozgrywki.

Dla gier towarzyskich, symulatorów kooperacyjnych czy prostych gier logicznych model hosta jest zazwyczaj w zupełności wystarczający. W przypadku gier rankingowych, strzelanek typu battle royale czy gier z ekonomią opartą na cennych przedmiotach, odejście od autorytatywnego serwera dedykowanego niemal zawsze kończy się plagą oszustw.

Co faktycznie synchronizujesz: fizyka, wejścia i zdarzenia

Drugim fundamentalnym elementem przygotowawczym jest inwentaryzacja danych, które muszą wędrować przez sieć. Początkujący twórcy często próbują replikować każdy element sceny za pomocą gotowych komponentów synchronizujących transformację (pozycję, rotację i skalę) w każdej klatce. Przy kilkunastu obiektach i dwóch graczach podejście to zadziała, lecz przy większej skali szybko doprowadzi do nasycenia pasma sieciowego, skoków opóźnień (jitter) oraz zapychania kolejki serializacji.

W grach sieciowych wyróżnia się trzy główne kategorie danych:

  1. Stan ciągły: Pozycje graczy, rotacje pojazdów, prędkości liniowe. Wymagają one zaawansowanej interpolacji (wygładzania ruchu u innych graczy), ekstrapolacji oraz predykcji po stronie klienta (Client-Side Prediction), aby zniwelować wrażenie opóźnienia u sterującego.
  2. Zdarzenia jednorazowe: Wystrzał z broni, otwarcie drzwi, aktywacja umiejętności o długim czasie odnowienia. Przesyła się je za pomocą zdalnych wywołań procedur (RPC – Remote Procedure Calls) lub zdarzeń sieciowych, dbając o to, by pakiety dotarły w sposób niezawodny (reliable).
  3. Stan trwały gry: Wynik meczu, faza rundy, zawartość ekwipunku, poziom zdrowia. Dane te najczęściej synchronizuje się za pomocą zmiennych sieciowych replikowanych tylko wtedy, gdy ich wartość ulegnie faktycznej zmianie (tzw. dirty flags).

Gdy gra w dużym stopniu polega na deterministycznej fizyce (np. bilard, zaawansowane pojazdy kołowe), synchronizacja samych pozycji staje się koszmarem – silniki fizyczne w

Unity (jak PhysX) nie są w pełni deterministyczne między różnymi platformami czy architekturami procesorów. Próba puszczenia niezależnej symulacji równolegle na dwóch maszynach niemal natychmiast prowadzi do rozbieżności: po kilku sekundach ta sama kula bilardowa na jednym ekranie trafia do łuzy, a na drugim odbija się od bandy.

Programista piszący kod przy stanowisku pracy w nowoczesnym biurze
Źródło: Pexels | Autor: cottonbro studio

Klasycznym przykładem jest próba zbudowania zręcznościowej gry wyścigowej na bazie synchronizacji samych wciśnięć klawiszy, w nadziei, że fizyka na każdym komputerze zachowa się identycznie. Wystarczy ułamek sekundy opóźnienia wątku lub minimalna różnica w taktowaniu klatki, by pojazd u jednego gracza zderzył się ze ścianą, podczas gdy u drugiego czysto pokonał zakręt. Uniknięcie takich anomalii wymaga bezwzględnego narzucenia autorytetu jednej ze stron i wygładzania korekt wizualnych tak, by gracz nie odczuwał szarpnięć kamery ani nagłych przesunięć modelu.

Świadomość tego, co i jak często trzeba transmitować, diametralnie zmienia podejście do wyboru narzędzia. Tytuły oparte na powolnej turówce czy grze w karty zadowolą się rzadkimi komunikatami RPC przesyłanymi przez protokół niezawodny, nie generując niemal żadnego obciążenia pasma. Z kolei dynamiczne gry akcji wymagają stałego strumienia małych, surowych pakietów UDP wys

yłanych kilkadziesiąt razy na sekundę, gdzie strata pojedynczego pakietu pozycji jest bez znaczenia, lecz buforowanie i oczekiwanie na retransmisję byłyby zabójcze dla dynamiki walki.

Photon PUN — najszybsza droga do prototypu opartego na pokojach

Photon Unity Networking (w swojej najpopularniejszej odsłonie PUN 2) przez lata stanowił domyślny punkt wyjścia dla niezależnych deweloperów. Jego fundamentem jest model oparty na chmurze (Photon Cloud) oraz koncepcji wirtualnych pokojów (Rooms). Twórca gry nie musi stawiać własnej maszyny linuksowej, konfigurować portów ani martwić się przebijaniem przez zapory sieciowe (NAT Punchthrough) – klient łączy się bezpośrednio z regionalnymi serwerami firmy Exit Games, które pośredniczą w przekazywaniu pakietów. [3]

Kluczową rolę w sesji PUN pełni tzw. Master Client. To jeden z graczy (zazwyczaj ten, który utworzył pokój), któremu framework przypisuje zadanie symulowania logiki niezwiązanej bezpośrednio z konkretnym awatarem: ruchu sztucznej inteligencji, odliczania czasu rundy czy spawnowania przedmiotów na mapie. Gdy Master Client opuszcza grę, Photon automatycznie przekazuje tę rolę kolejnemu uczestnikowi.

Wdrożenie podstawowego poruszania się w PUN 2 zajmuje dosłownie kilkanaście minut. Wystarczy dodać do prefabu postaci komponent PhotonView, wskazać komponent PhotonTransformView i wywołać metodę instancjonowania sieciowego. Z perspektywy małych zespołów i prototypów jest to ogromna oszczędność czasu na wczesnym etapie produkcji.

Model ten wiąże się jednak z kilkoma poważnymi kompromisami, które ujawniają się dopiero po premierze:

  • Podatność na manipulacje: Serwery Photon Cloud w modelu PUN są przekaźnikami danych (relays), a nie autorytatywnymi sędziami. Oznacza to, że gracz pełniący rolę Master Clienta ma pełną techniczną możliwość sfałszowania wyniku meczu, poziomu zdrowia wrogów czy zachowania bossa.
  • Model kosztowy CCU: Photon Cloud rozlicza się w oparciu o liczbę jednocześnie połączonych użytkowników (Concurrent Users). Darmowy pakiet obejmuje 20 CCU, co wystarcza na testy, lecz nagły, wiralowy sukces gry może wygenerować wysokie comiesięczne rachunki, jeśli monetyzacja tytułu nie została precyzyjnie skalkulowana.
  • Cykl życia technologii: Dobrze mieć na uwadze, że PUN 2 wszedł w fazę długofalowego utrzymania (maintenance mode). Exit Games kieruje obecnie nowe projekty w stronę bibliotek Photon Fusion (łączącej zalety serwerów dedykowanych i zaawansowanej predykcji) oraz Photon Quantum (opartej na w pełni deterministycznym silniku symulacji). [1]

PUN 2 nadal sprawdza się znakomicie w projektach casualowych, grach kooperacyjnych dla wąskiego grona znajomych, asynchronicznych planszówkach oraz interaktywnych prezentacjach architektonicznych, gdzie ryzyko oszustw nie wpływa na satysfakcję z rozgrywki.

Mirror — kontrola nad serwerem i klasyczny model client-server

Mirror powstał jako bezpośrednia, oddolna odpowiedź społeczności na porzucenie przez Unity archaicznego modułu UNet. Zamiast wymyślać koło na nowo, twórcy Mirrora zachowali znajomy dla tysięcy programistów interfejs API (atrybuty [Command], [ClientRpc], [SyncVar]), gruntownie przepisując niskopoziomową warstwę transportową, eliminując błędy pamięci i zdejmując z silnika narzut wydajnościowy.

Podstawową zaletą Mirrora jest pełna niezależność i bezpłatność na licencji open-source. Brak zewnętrznych opłat abonamentowych za CCU oznacza, że koszty infrastruktury zależą wyłącznie od tego, jak deweloper zdecyduje się hostować swoją grę. Framework wspiera architekturę serwera dedykowanego w trybie bezgłowym oraz klasyczny model gospodarza (Host-Client), co pozwala tworzyć zarówno bezkosztowe gry wieloosobowe, jak i profesjonalne projekty z centralną weryfikacją logiki.

Istotnym atutem Mirrora jest modularna architektura transportowa. Programista nie jest przywiązany do jednego protokołu. Może wybrać transport oparty na protokole KCP (niezawodny UDP o niskich opóźnieniach), Telepathy (oparty na TCP) czy SimpleWebTransport dla przeglądarek WebGL. Dodatkowo Mirror posiada doskonałą integrację z usługami platformowymi, takimi jak Steam Networking Sockets (poprzez integrację FizzySteamworks), co rozwiązuje problem łączenia graczy przez NAT bez konieczności utrzymywania własnych serwerów pośredniczących. [4]

Próg wejścia w Mirrorze jest jednak zauważalnie wyższy niż w Photonie. Framework nie zapewnia w standardzie gotowej chmury do matchmakingu ani lobby. Kwestia znalezienia przeciwnika, zestawienia połączenia czy utrzymania bazy danych leży w całości po stronie twórcy, co wymaga wiedzy z zakresu administracji serwerami i sieci komputerowych.

Programista w niebieskiej koszuli kodujący na iMacu
Źródło: Pexels | Autor: Lee Campbell

Unity Netcode for GameObjects — oficjalny standard środowiska Unity

Unity Netcode for GameObjects (NGO) to oficjalne, rozwijane przez firmę Unity rozwiązanie sieciowe wysokiego poziomu, stworzone z myślą o projektach opartych na tradycyjnej strukturze komponentów MonoBehaviour. Zastąpiło ono wcześniejsze, eksperymentalne biblioteki, wprowadzając nowoczesne podejście do replikacji obiektów sceny.

Architektura NGO bazuje na komponentach NetworkObject i NetworkBehaviour, wykorzystując do komunikacji struktury NetworkVariable<T> oraz typowane procedury [ServerRpc] i [ClientRpc]. Zmienne sieciowe w NGO posiadają rozbudowany system uprawnień, pozwalający precyzyjnie zdefiniować, kto ma prawo do zapisu danej wartości (np. wyłącznie serwer), a kto może ją tylko odczytywać. Mechanizm ten domyślnie wymusza pisanie kodu w bezpiecznym, autorytatywnym paradygmacie serwera.

Największa siła Netcode for GameObjects tkwi w bezszwowej integracji z pakietem Unity Gaming Services (UGS). Narzędzia takie jak:

  • Unity Relay: Pozwala na bezpieczne łączenie graczy w modelu Host-Client z pominięciem ograniczeń routerów i zapór sieciowych, eliminując konieczność otwierania portów u hosta.
  • Unity Lobby & Matchmaker: Zapewniają kompletną obsługę poczekalni, wyszukiwania gier i filtrowania pokoi na bazie parametrów rozgrywki.
  • Multiplay: Umożliwia skalowalne orkiestrowanie serwerami dedykowanymi na maszynach wirtualnych w zależności od bieżącego obciążenia.

Sprawiają, że konfiguracja pełnego zaplecza sieciowego odbywa się w ramach jednego ekosystemu i jednego panelu administracyjnego. Minusem tego rozwiązania bywa zmienne tempo rozwoju dokumentacji oraz konieczność śledzenia zależności między kolejnymi wersjami silnika a wersjami pakietów sieciowych.

Dopasowanie narzędzia do realiów projektu

Ostateczny wybór nie sprowadza się do pytania, który framework jest obiektywnie najlepszy, lecz który z nich optymalizuje czas pracy zespołu i minimalizuje ryzyko budżetowe. Każde z tych rozwiązań reprezentuje inną filozofię tworzenia gier.

Jeśli tworzysz niewielką grę towarzyską, zależy ci na błyskawicznym postawieniu prototypu bez zagłębiania się w architekturę sieciową, a twój model biznesowy uwzględnia opłaty za chmurę – ekosystem Photon (ze szczególnym uwzględnieniem nowszego Fusion dla dynamicznych projektów) pozwoli zaoszczędzić tygodnie pracy nad infrastrukturą.

Gdy celem jest pełna kontrola nad kodem źródłowym, niezależność od zewnętrznych dostawców usług chmurowych, brak ukrytych opłat licencyjnych oraz możliwość swobodnego przełączania się między serwerem dedykowanym a rozgrywką przez platformę Steam – Mirror pozostaje najbardziej elastycznym, dojrzałym i stabilnym wyborem wspieranym przez aktywną społeczność.

W przypadku nowych projektów, które planują wykorzystać pełny potencjał ekosystemu Unity, celują w platformy mobilne lub konsole i potrzebują zintegrowanych usług takich jak Relay, Voice Chat (Vivox) czy zaawansowany Matchmaking – Unity Netcode for GameObjects stanowi obecnie najbezpieczniejszą ścieżkę pod kątem długoterminowej kompatybilności z kolejnymi wersjami silnika LTS.

Weryfikacja wyboru w praktyce: zanim napiszesz pierwszą linię logiki

Nawet najbardziej przemyślana analiza dokumentacji nie zastąpi wczesnego testu bojowego na surowej scenie. Zanim zespół zaangażuje się w pełną implementację mechanik poruszania się, ekwipunku czy walki, warto poświęcić kilka dni na stworzenie tzw. szkieletu sieciowego (network greybox). Wystarczy prosta scena z kilkoma sześcianami, podstawową synchronizacją pozycji oraz symulacją przesyłania danych o zdrowiu czy interakcji z otoczeniem.

Podczas tego testu kluczowe jest natychmiastowe porzucenie idealnych warunków lokalnych. Testowanie gry w edytorze z dwoma instancjami uruchomionymi na jednym komputerze (np. przez Unity ClonesManager) daje złudne poczucie płynności, ponieważ opóźnienie wynosi zero, a pakiety nigdy nie giną. Każdy z omawianych frameworków zachowuje się zupełnie inaczej, gdy narzuci się sztuczne ograniczenia łącza:

Warto od pierwszych godzin skorzystać z wbudowanych narzędzi do symulacji opóźnień sieciowych (jak Network Simulator w Mirrorze czy Network Simulator w pakiecie Unity Transport) i ustawić parametry odpowiadające przeciętnemu połączeniu internetowemu: ping na poziomie 80–120 ms, jitter rzędu 15 ms oraz 2–3% losowo traconych pakietów. Taki eksperyment natychmiast obnaża ograniczenia wybranej technologii i pozwala ocenić:

Jak framework radzi sobie z wygładzaniem ruchu zdalnych obiektów (interpolacją), czy wbudowane komponenty transformacji radzą sobie bez widocznych drgań kamery oraz jak skomplikowane staje się napisanie mechanizmu przewidywania ruchu po stronie klienta (client-side prediction), jeśli tworzona gra wymaga natychmiastowej reakcji na wciśnięcie klawisza.

Decyzja o wyborze warstwy sieciowej nie musi być paraliżująca, o ile zachowasz czystość kodu rozgrywki. Oddzielenie logiki gry (systemu obrażeń, poruszania się czy statystyk) od samego kodu sieciowego za pomocą prostych interfejsów sprawia, że ewentualna zmiana biblioteki z Mirrora na Netcode for GameObjects w połowie preprodukcji pozostanie jedynie operacją wymiany przekaźników danych, a nie koniecznością przepisywania całego projektu od podstaw.

Co warto zapamiętać

  • Wybór frameworka sieciowego powinien wynikać z modelu rozgrywki, wymagań dotyczących autorytetu serwera oraz planowanej skali projektu.
  • Photon PUN 2 ułatwia szybkie tworzenie prototypów opartych na pokojach i ogranicza konieczność samodzielnego utrzymywania infrastruktury.
  • Model Master Client w PUN nie zapewnia takiej ochrony przed oszustwami jak dedykowany, autorytatywny serwer.
  • Przed wyborem technologii trzeba określić, które dane będą synchronizowane jako stan ciągły, zdarzenia jednorazowe lub trwały stan gry.
  • Synchronizacja transformacji w każdej klatce nie jest uniwersalnym rozwiązaniem; dynamiczne gry wymagają predykcji, interpolacji i odpowiedniego zarządzania pakietami.
  • Gry rankingowe i tytuły z cenną ekonomią powinny szczególnie ostrożnie podchodzić do architektury hostowanej przez gracza.

Pytania od czytelników

Pytanie czytelnika

Czy Photon PUN nadaje się do gry z większą liczbą graczy?

Odpowiedź redakcji: PUN może sprawdzić się w sesjach opartych na pokojach, ale przed wdrożeniem trzeba przeanalizować limit jednocześnie połączonych użytkowników, obciążenie oraz wymagania dotyczące autorytetu serwera.
Pytanie czytelnika

Czy synchronizowanie pozycji obiektów w każdej klatce jest dobrym rozwiązaniem?

Odpowiedź redakcji: Tylko w prostych prototypach i przy małej liczbie obiektów. W większych projektach warto ograniczać przesyłane dane oraz stosować interpolację, predykcję i synchronizację wyłącznie istotnych zmian.
Pytanie czytelnika

Kiedy model hosta może być wystarczający?

Odpowiedź redakcji: Zwykle w kameralnych grach kooperacyjnych, towarzyskich i prostych tytułach logicznych, w których koszty infrastruktury są ważniejsze niż pełna ochrona przed oszustwami.
Pytanie czytelnika

Dlaczego fizyka może desynchronizować się między komputerami?

Odpowiedź redakcji: Fizyka Unity nie jest w pełni deterministyczna między różnymi platformami i architekturami. Dlatego sama synchronizacja wejść nie gwarantuje identycznego przebiegu symulacji.

Źródła

Tekst przygotowany przezJakub BorowskiRedakcja ExcelRaport.pl