Update
This commit is contained in:
+41
-46
@@ -566,21 +566,22 @@ Důvod, proč nevytvořit thread pro každou odeslanou zprávu je, že vyžaduje
|
||||
|
||||
\section{Hra}
|
||||
|
||||
Pro zkoušku různých technik jsme vytvořili hru pro více hráčů. V ní budou hráči používat program klienta, kterým se připojí na společný server. Po připojení hráči uvidí herní svět, ve kterém se mohou pohybovat. Systém hry automaticky synchronizuje stavy hráčů mezi klienty. Server bude celou hru řídit a bude mít autoritu. Program klienta tento stav vykreslí svému uživateli.
|
||||
V této kapitole představíme hru, kterou jsem vyvinuli pro implementaci různých technik a jejich následného měření. Ve hře má každý hráč svou postavu, se kterou může volně pohybovat ve 3D prostoru. Hra simuluje na postavách hráčů realistickou fyziku. Pokud se do hry připojí více hráčů, tak se navzájem vidí. Každý hráč spustí program klienta, který zobrazuje stav hry a postavy hráčů v 3D prostoru. V další kapitole porovnáme plynulost pohybu a rychlost odezvy, které jsou pro hratelnost důležité.
|
||||
|
||||
Nejprve představíme, jak vypadá softwarová architektura hry jednoho hráče. Popíšeme jak vypadá herní engine a z jakých komponent se program hry skládá.
|
||||
V první části popíšeme architekturu hry a našeho enginu. Následně rozšíříme a jinak upravíme tento model pro hru více hráčů. Vytvoříme tak distribuovaný systém.
|
||||
|
||||
V další části navážeme a rozšíříme hru pro více hráčů. Představíme architekturu. První implementace využívá klient-server. Vytvořili jsme dva programy: server a klient. Podrobně popíšeme komponenty, ze kterých se skládá server a klient. Ve hře se jednotlivý hráči uvidí, budou se moct pohybovat. Budeme porovnávat plynulost pohybu a rychlost odezvy, které jsou pro hratelnost důležité.
|
||||
Naše první implementace využívá model klient-server, kde máme dva různé programy: server a klient. Podrobně popíšeme, které komponenty jsme přidali, které pouze přesunuli do programu serveru a které naopak ponechali v programu klienta.
|
||||
|
||||
Mezi hlavní prvky patří náš vlastní komunikační protokol transportní vrstvy: \uv{QUICr}. Je to obousměrný protokol pro posílání zpráv, který upravuje QUIC pro využití ve hrách. Náš protokol lépe zachycuje závislosti mezi zprávami a umožňuje posílat zprávy nespolehlivě. Díky tomu se úplně zbavuje ahead-of-line blokování.
|
||||
Mezi hlavní prvky patří náš vlastní komunikační protokol transportní vrstvy: \uv{QUICr}. Je to obousměrný protokol pro posílání zpráv jako n-tic bytů, který se inspiruje protokolem QUIC, ale upravuje ho pro lepší využití pro hry. Náš protokol lépe zachycuje závislosti mezi zprávami a umožňuje i posílat zprávy nespolehlivě. Díky tomu se úplně zbavuje ahead-of-line blokování.
|
||||
|
||||
Zjistili jsme, že důležitým vylepšením je vlastní serializace primitivních zpráv. Pokud například obsahuje pouze seznam pozic, může být vlastní serializace rozdíl mezi hratelnou a nehratelnou odezvou. Popíšeme, jak jsme rychlost měřili a jaké metody jsme pro vlastní serializaci použili.
|
||||
|
||||
Nakonec představíme i architekturu peer-to-peer, kdy umožníme, aby v systému bylo více spolupracujících serverů, které si mezi sebou budou rozdělovat práci. Zároveň porovnáme i případ, kdy není žádný autoritativní server a hráči se mezi sebou synchronizují samovolně.
|
||||
|
||||
|
||||
\subsection{Engine}
|
||||
|
||||
\subsection{Softwarová Architektura}
|
||||
Pro hru jsme vyvinuli vlastní herní engine tak, abychom mohli celý systém do hloubky upravovat. V této části popíšeme jeho základní komponenty. Implementace je v jazyce C++, protože je v tomto jazyce napsáno spousty nástrojů a knihoven právě pro vývoj her. Díky tomu se vývoj značně akceleroval. Zároveň je to vhodný jazyk pro práci na nižší úrovni, a to je důležité pro některé metody optimalizace. Engine je implementovaný jako modulární monolit. Jednotlivé moduly představíme.
|
||||
|
||||
% Vstupy od hráče -> derivace
|
||||
% Derivace + Stav -> integrace
|
||||
@@ -592,37 +593,24 @@ Nakonec představíme i architekturu peer-to-peer, kdy umožníme, aby v systém
|
||||
|
||||
Program hry jsme rozdělili na \uv{stav} a \uv{řídící logiku}. Stav obsahuje množinu entit, které jsou ve hře a jejich vlasnosti a atributy. Entity jsou objekty v herním světě, jako postava hráče, truhly s poklady nebo nepřátele. Entita nepřítele může mít vlastnost "množství životů" a truhla vlastnost "poklad", která definuje, co je v truhle obsaženo. Stavu hry se někdy říká pouze \uv{svět}.
|
||||
|
||||
% Detaily k implementaci, ale stále dost abstrahované.
|
||||
% Zmínit svět, ve kterém držíme stav hry. Zmínit derivaci (proces sbírání vstupů, prozatím jen od hráče). Zmínit integraci jako aplikaci derivace na stav.
|
||||
|
||||
% Stav hry reprezentujeme kompletně ve třídě \inlcpp{World}. Ta obsahuje registr z knihovny Entt. Řídící logika je ve třídě \inlcpp{WorldController}. Obsahuje smyčku, která v každé iteraci posbírá vstupy od hráče, převede je na akce a aplikuje je společně s další definovanout logikou. Například v naší hře má vstup: stisknutí klávesy W, definovaný příkaz: \uv{posuň dopředu}, která změní vektor zrychlení hráče. Dalšími prvky, které mění změnu stavu je například fyzický engine, který upravuje zrychlení podle nárazů a nebo vlivů sil, například gravitace.
|
||||
|
||||
Druhá část je řídící logika, která po iteracích mění stav hry. Tato změna může být pouze na základě stavu světa, například posune objekt, který má nenulový vektor zrychlení. Mimo to může řídící logika reagovat na údalosti. Například stisk tlačítka W je událost, který vyvolá změnu vektoru zrychlení hráče, který tlačítko stiskl. V důsledku toho se postava hráče pohne.
|
||||
|
||||
Každá iterace řídící logiky trvá přibližně stejně dlouho, většinou 1/60 sekundy nebo 1/24 sekundy. Vyšší frekvence znamená nižší odezvu a lepší plynulost. Nižší frekvence znamená menší výpočetní náročnost. Pro pomalejší hry bez rychlých akčních pasáží se využívá frekvence 24Hz a u kompetentních her i 120Hz.
|
||||
|
||||
https://www.riotgames.com/en/news/peeking-valorants-netcode
|
||||
|
||||
\subsubsection{Entity-Component-System}
|
||||
|
||||
V programu využíváme architekturu entity-component-system, která je pro hry běžná. Entity už jsme popsali výše. Ke konkrétním entitám vážeme instance komponent, které entitě dají stav. Většinou je komponenta přiřazena právě jedné entitě. Řídící logika hry se skládá ze \uv{systémů}, je řídící logika, která prochází komponenty a aktualizuje je. Systémů máme více a každý se stará o nějakou část.
|
||||
|
||||
Herní stav se skládá z \uv{entit}, které jsou v herním světě a jejich \uv{vlastností}. Každou iteraci řídící logika všechny entity aktualizuje. Některá logika může být pro dvě entity společná, nebo velmi malá. Obecně ale předpokládáme, že každá entita přidá na výpočetní náročnosti a moderní hry mohou mít miliony entit. Zároveň každá entita může být jiná.
|
||||
|
||||
Architektura her je tomu přizpůsobená. Entity tvoříme skládáním různých komponent a řídící logika mění jejich stav pomocí \uv{systému}. Systém se skládá z iterátoru přes n-tici typů komponent a aplikační funkce na prvky této n-tice. Výhody jsou téměř žádná virtualizovaná volání, která by se ve velkém počtu negativně projevila na výkonu a lepší \uv{datová lokalita}. To znamená, že procesor je schopný lépe předpovědět, kterou část paměti si má připravit dopředu, protože na ni bude provádět výpočet. Horší lokalita znamená, že bude často načítat zbytečné části, které nepotřebuje a výpočet bude delší.
|
||||
|
||||
https://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/
|
||||
|
||||
Této architektuře se říká entity-component-system, zkráceně ECS. Existují různé knihovny, které poskytují registry a nástroje pro tvorbu systémů, jako například Entt, kterou využíváme my.
|
||||
|
||||
|
||||
|
||||
\subsection{Engine}
|
||||
|
||||
Pro hru jsme vyvinuly vlastní herní engine tak, abychom mohli celý systém do hloubky upravovat. Implementace je v jazyce C++, protože je v tomto jazyce napsáno spousty nástrojů a knihoven právě pro vývoj her. Díky tomu se vývoj značně akceleroval. Zároveň je to vhodný jazyk pro práci na nižší úrovni, a to je důležité některé metody optimalizace. Engine je implementovaný jako modulární monolit. Jednotlivé moduly představíme.
|
||||
|
||||
\subsubsection{Fyzický engine}
|
||||
|
||||
Hra je 3D a chtěli jsme simulovat otevřený svět, ve kterém platí zákony fyziky. Pro simulaci jsme využili existující fyzický engine \uv{Jolt} a zabalili ho do modulu. Jolt je populární projekt, který je využíván například v Horizon: Forbidden West nebo Death Stranding 2.
|
||||
|
||||
Pro použití jsme vytvořili instanci fyzického světa, do kterého naskládáme objekty a jejich vlastnosti, jako hmotnost a tvar. Zavoláním metody pro aktualizaci engine posune stav entit (zrychlení a pozice). Vše jsme obalili do \inlcpp{JoltPhysicsWorld}.
|
||||
|
||||
Jolt umí využít více vláken procesoru a podporuje \uv{rollback}, který umožňuje vracet stav v historii simulace dozadu. Je to důležitá věc pro hry více hráčů v případě, že se stav dvou vrcholů v systému neshoduje i když by měl.
|
||||
Jolt umí využít více vláken procesoru a podporuje \uv{rollback}, který umožňuje vracet stav v historii simulace dozadu. Je to důležitá věc pro hry více hráčů a obecně distribuovaných systémů, pro řešení desynchronizace.
|
||||
|
||||
\subsubsection{Vykreslování}
|
||||
|
||||
@@ -632,9 +620,15 @@ Mezi operacemi v grafu definujeme závislosti. Díky tomu můžeme definovat ope
|
||||
|
||||
V našem případě máme právě operaci pro vykreslení statických objektů, jako povrchu, po kterém se hráči pohybují apod. Druhá operace vykreslí samotné hráče a jiné dynamické objekty. Poslední operaci vykreslí uživatelské rozhraní obsahující různé nástroje pro různé ladění programu.
|
||||
|
||||
\subsubsection{Entt}
|
||||
\subsubsection{Entity-Component-System}
|
||||
|
||||
Pro ECS využíváme knihovnu \uv{Entt}, která umožňuje vytvářet registry entit a jejich komponent a aplikovat na ně funkce. Entita je v tomto případě pouze unikátně identifikační číslo a komponenta je libovolný typ. V registru pak můžeme vytvářet \uv{pohledy} na n-tici typů komponent, které jsou seznam právě všech entit v registru, které všechny tyto komponenty mají. Ten můžeme procházet a libovolně měnit atributy komponent.
|
||||
V programu využíváme architekturu entity-component-system, zkráceně ECS, která je pro hry běžná. Entity už jsme popsali výše. Ke konkrétním entitám vážeme instance komponent, které entitě dají stav. Většinou je komponenta přiřazena právě jedné entitě. Poslední částí jsou systémy, které reprezentují řídící logiku. Systém je definován funkcí, která prochází entity, které splňují definovanou podmínku a mění stav její komponent. Tato podmínka většinou pouze omezuje na entity, které mají přiřazené komponenty pro určité typy. Systém může například simulovat fyziku, a to přičítáním zrychlení k pozici. K tomu definuje podmínku, která procházenou množinu omezí na entity, které mají potřebné komponenty. Těmi jsou komponenta transformace a komponenta zrychlení.
|
||||
|
||||
Motivací této architektury je jednoduché skládání různých entit, které jsou pro rozmanité herní světy typické. Pomocí stromu dědičnosti bychom tyto různé scénáře hůře skládali. Další výhoda je zlepšení výkonu. Protože si engine může poskládat entity a jejich komponenty do paměti jak chce, může umístění optimalizovat pro definované systémy tak, aby iterování bylo co nejrychlejší. Tomuto se říká problém lokality.
|
||||
|
||||
https://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/
|
||||
|
||||
Pro ECS využíváme knihovnu \uv{Entt}, která usnadňuje definici entit, přiřazování komponent a definici systémů. Entita je v této knihovně pouze unikátně identifikační číslo a komponenta je libovolný typ. V registru pak můžeme vytvářet \uv{pohledy} na n-tici typů komponent, které jsou seznam právě všech entit v registru, které všechny tyto komponenty mají. Ten můžeme procházet a libovolně měnit atributy komponent. Příklad použití vidíme na TODO, kde nejprve vytvoříme registr do kterého přidáme novou entity a přiřadíme ji komponentu typu Transform. Nakonec definujeme pohled na všechny entity, které mají komponentu obou typů: Transform i CharacterBody. Před tento pohled iterujeme a v každé iteraci kopírujeme.
|
||||
|
||||
\begin{kicode}{cpp}{}{Příklad použití knihovny Entt}
|
||||
entt::registry registry;
|
||||
@@ -675,28 +669,25 @@ Představíme komponenty, které jsme pro hru definovali a proč:
|
||||
|
||||
|
||||
|
||||
\subsubsection{Stav hry}
|
||||
|
||||
% Detaily k implementaci, ale stále dost abstrahované.
|
||||
% Zmínit svět, ve kterém držíme stav hry. Zmínit derivaci (proces sbírání vstupů, prozatím jen od hráče). Zmínit integraci jako aplikaci derivace na stav.
|
||||
|
||||
Stav hry reprezentujeme kompletně ve třídě \inlcpp{World}. Ta obsahuje registr z knihovny Entt. Řídící logika je ve třídě \inlcpp{WorldController}. Obsahuje smyčku, která v každé iteraci posbírá vstupy od hráče, převede je na akce a aplikuje je společně s další definovanout logikou. Například v naší hře má vstup: stisknutí klávesy W, definovaný příkaz: \uv{posuň dopředu}, která změní vektor zrychlení hráče. Dalšími prvky, které mění změnu stavu je například fyzický engine, který upravuje zrychlení podle nárazů a nebo vlivů sil, například gravitace.
|
||||
|
||||
% Budou existovat dvě verze: pro hru jednoho hráče a pro hru více hráčů. Verze pro jednoho hráče bude vstupy číst přímo z periferií od hráče. Druhá verze bude tyto vstupy transformovat na příkazy, a posílat je na server. Aktualizovat stav světa bude až v moment, co od serveru dostane snapshot nebo událost.
|
||||
|
||||
\subsection{Hra více hráčů}
|
||||
\newpage
|
||||
|
||||
Nejprve her více hráčů je často klient-server model, protože poskytuje nižší celkovou odezvu. Stav hry řídí autoritativní server, který ho replikuje klientům a ti ho zobrazí hráči. Autorita serveru zjednodušuje konzistenci a detekci podvádění. Klienti na server neposílají jak vypadá jejich stav, ale pouze akce, které chtějí provést. Příkladem může být akce pohybu dopředu, kterou vyvolal hráč. Server rozesílá klientům snapshoty pro průběžně měnící se stav (např. pozice entit) a události pro jednorázové akce (např. událost o konci hry).
|
||||
\section{Hra více hráčů}
|
||||
|
||||
Druhá varianta je model peer-to-peer. Model je složitější z hlediska synchronizace. Účastníci si mezi sebou posílají akce a každý si udržuje svůj stav, který nikomu nereplikuje. Je potřeba, aby každý měl kompletní historii akcí všech účastníků systému ve správném pořadí. Tomuto se říká \uv{event-sourcing}. Nevýhoda je, že každý hráč
|
||||
V předchozí části jsme představili základní implementaci hry pro jednoho hráče. V této části ukážeme, jak jsme hru rozšířili na síťový systém a umožnili hru více hráčů. To znamená, že více hráčů se může připojit do stejné instance hry a navzájem spolu interagovat.
|
||||
|
||||
Navíc musí výsledek každé aplikace akce být všude stejný. Komplikací může být fyzický engine, který postupně integruje pozice entit podle derivace, která je reprezentována vektorem zrychlení. Každá integrace musí definovat, o jak velký časový krok se jedná (tzv. delta-time) a všichni účastníci se na něm musejí shodnout. Různé délky by rychle způsobily desynchronizaci. Zároveň všechny pseudonáhodné generátory musejí mít stejný seed a musíme si dát pozor, protože na různých platformách může aritmetrika s plovoucí desetinou čárkou dopadnout trochu jinak. I malé rozdíly by se mohli rychle projevit.
|
||||
Jako první jsme implementovali model klient-server. Diagram systému vidíme na obrázku \ref{fig:client_server_architecture}. Stav hry řídí autoritativní server, který ho replikuje klientům posíláním snapshotů. Klient zobrazuje stav hry hráči, stejně jako v případě hry jednoho hráče. Autorita serveru zjednodušuje konzistenci a detekci podvádění. Klienti na server neposílají svůj stav, ale pouze akce, které chtějí provést. Příkladem může být akce pohybu dopředu, kterou vyvolal hráč. Server má možnost akce odmítnout a libovolně interpretovat, protože konečné slovo má právě server. Server rozesílá klientům zprávy zvané snapshoty, které obsahují aktuální stav hry (např. pozice entit) a události pro jednorázové akce (např. událost o konci hry).
|
||||
|
||||
\subsection{Klient-Server architektura}
|
||||
Druhá varianta je model peer-to-peer. Ten je složitější z hlediska konzistence. Účastníci si mezi sebou posílají akce a každý si udržuje svůj stav, který ale nikomu nereplikuje. Každý se tak chová jako server v modelu klient-server. Je potřeba, aby každý účastník měl kompletní historii akcí všech ostatních v systému ve správném pořadí. Tomuto se říká \uv{event-sourcing}. Nevýhoda je, že všichni hráči musejí mít historii stejnou, jinak dochází k desynchronizaci.
|
||||
|
||||
Pro systém jsem zvolili model klient-server, který je pro hry vhodnější, protože usnadňuje synchronizaci. V té jsou dva programy: server a klienta. Řídící logika probíhá na serveru, a ten svůj stav synchronizuje na klienty. Každý hráč, který chce hrát, musí mít svůj proces pro klienta a připojit se na server. Aplikace klienta na server posílá akce od hráče a zobrazuje aktuální stav hráči, který ze serveru přišel.
|
||||
Druhá komplikace je, že výsledek každé aplikace akce být všude stejný. Problém nastává u generování pseudo-náhodných čísel nebo u integrace. Například fyzický engine postupně integruje pozice entit podle derivace, která je reprezentována vektorem zrychlení. Každá integrace musí definovat, o jak velký časový krok se jedná (tzv. delta-time) a všichni účastníci se na něm musejí shodnout. Různé délky by rychle způsobily desynchronizaci. Zároveň všechny pseudonáhodné generátory musejí mít stejný počáteční seed. Je třeba si dát pozor na aritmetriku s plovoucí desetinou čárkou, která na různých platformách může dopadnout trochu jinak. I malé rozdíly se mohou rychle projevit.
|
||||
|
||||
Každá akce, která přijde na server, musí být autorizována. Například ověřit, že se hráč nestaží interagovat s objektem, od kterého je moc daleko. Pokud vše proběhne v pořádku, bude přidána do fronty pro aktuální iteraci, kterou pak celou aplikuje na stav podle definované logiky. V případě, že autorizace selže, může server, s určitou tolerancí, klienta odpojit. Svůj stav průběžně replikuje klientům. Frekvence závisí na typu hry a pohybuje se od 20Hz pro pomalejší nekompetentní hry, až po 120Hz pro e-sport hry, jako například hra Valorant TODO ODKAZ.
|
||||
Řídící logiku jsme rozdělili na Server World Controller a Client World Controller. Toto rozdělení nás motivovalo dále oddělit integraci světa do vlastní třídy tak, aby logika mohla být sdílená mezi ovladačem pro jednoho hráče a pro více hráčů.
|
||||
|
||||
% Každá akce, která přijde na server, musí být autorizována. Například ověřit, že se hráč nestaží interagovat s objektem, od kterého je moc daleko. Pokud vše proběhne v pořádku, bude přidána do fronty pro aktuální iteraci, kterou pak celou aplikuje na stav podle definované logiky. V případě, že autorizace selže, může server, s určitou tolerancí, klienta odpojit. Svůj stav průběžně replikuje klientům. Frekvence závisí na typu hry a pohybuje se od 20Hz pro pomalejší nekompetentní hry, až po 120Hz pro e-sport hry, jako například hra Valorant TODO ODKAZ.
|
||||
|
||||
\begin{figure}
|
||||
\begin{center}
|
||||
@@ -718,13 +709,13 @@ Obě tyto komponenty, společně se stavem a řídící logikou, jsou ve tříd
|
||||
|
||||
\subsubsection{Registr klientů}
|
||||
|
||||
Komponenta, která spravuje spojení s hráči, se nazývá \uv{registr spojení}. Slouží jako sifon pro všechny zprávy, které klienti odesílají. Zároveň z ní lze zjistit kdo se právě připojil a kdo odpojil. K tomu slouží metody: \inlcpp{\\popDisconnectedPlayers} a \inlcpp{\\popConnectedPlayers}. Udržuje seznam nových připojení od posledního zavolání \inlcpp{\\popConnectedPlayers}.
|
||||
Komponenta, která spravuje a udržuje spojení s klienty hráčů, se nazývá \uv{registr klientů}. Slouží jako sifon pro všechny zprávy, které klienti odesílají. Zároveň z ní lze zjistit kdo se právě připojil a kdo odpojil. K tomu slouží metody: \inlcpp{popDisconnectedPlayers} a \inlcpp{popConnectedPlayers}. Udržuje seznam nových připojení od posledního zavolání \inlcpp{popConnectedPlayers}.
|
||||
|
||||
Třída si u každého klienta hlídá počet po sobě jdoucích selhání. Jakmile počet překročí určitou hranici, např. 5 chyb, relaci s klientem ukončí. Díky tomu, že zbytek aplikace přímo nepoužívá n-tici klientů, nemusí odpojení řešit. Pro získání seznamu existuje metoda \inlcpp{\\getClients}.
|
||||
Třída si u každého klienta hlídá počet po sobě jdoucích selhání. Jakmile počet překročí určitou hranici, např. 5 chyb, relaci s klientem ukončí. Tato komponenty skrývá samotné připojení s klientem a zbytek systému tak odpojení a připojení nemusí řešit. Pro získání seznamu existuje metoda \inlcpp{getClients}.
|
||||
|
||||
\subsubsection{Server Replikátoru}
|
||||
|
||||
Komponenta, která se snaží synchronizovat stav klientů s lokálním stavem na serveru, se nazývá \uv{replikátor}. Pro každého klienta si drží seznam entit, které musí danému klientovi synchronizovat, aby svůj úkol splnil. V případě klient-server architektury odesílá server svůj stav klientům. Základní implementace by posílala každý snímek kompletní stav entity se všemi komponentami. Lepší varianta je posílat pouze změny. Pokud se například pozice nezmění, není třeba posílat stejnou pozici jako minule. Na druhé straně u klienta máme klienta replikátoru. Ten se stará o dekódování zpráv a správné aktualizaci stavu.
|
||||
Komponenta, která se snaží synchronizovat stav klientů s lokálním stavem na serveru, se nazývá \uv{replikátor}. Pro každého klienta si drží seznam entit, které musí danému klientovi synchronizovat, aby svůj úkol splnil. Tento seznam entit lze z venku nastavovat, většinou komponentou pro správu zájmů, kterou představíme v další podkapitole. Základní implementace by posílala každý snímek kompletní stav entity se všemi komponentami. Lepší varianta je posílat pouze změněnou část stavu. Pokud se například pozice entity $X$ nezmění, není třeba posílat stejnou pozici pro entitu $X$ jako minule. Na druhé straně u klienta máme klienta replikátoru. Ten se stará o dekódování zpráv a správné aktualizaci stavu.
|
||||
|
||||
\subsubsection{Správa zájmů}
|
||||
|
||||
@@ -738,7 +729,7 @@ Dotazu na všechny body, které jsou dostatečně blízko od konkrétního bodu,
|
||||
|
||||
\subsection{Klient}
|
||||
|
||||
Program klienta se skládá z třídy \texttt{World}, která reprezentuje stav a \texttt{ClientWorldController}, která obsahuje jednodušší řídící logiku. Řídící logika posbírá každou iteraci vstupy, převede je na akce a ty odešle na server.
|
||||
Program klienta se skládá z třídy \inlcpp{World}, která reprezentuje stav a \inlcp{ClientWorldController}, která obsahuje jednodušší řídící logiku. Řídící logika posbírá každou iteraci vstupy, převede je na akce a ty odešle na server.
|
||||
|
||||
\subsubsection{Klient Replikátoru}
|
||||
|
||||
@@ -1155,13 +1146,17 @@ Systémovou architekturu vidíme na obrázku \ref{fig:zone_cluster_architecture}
|
||||
\end{figure}
|
||||
|
||||
|
||||
\subsection{Komprese}
|
||||
|
||||
Poslední optimalizací, kterou jsem pro přenos informací použili, byla komprese. Nejprve jsme nahradili byte buffer, který pracuje pouze s byty, bit bufferem, který nám umožnil pracovat s jednotlivými bity.
|
||||
|
||||
\subsubsection{Bit Buffer}
|
||||
\section{Výsledná hra}
|
||||
|
||||
V této kapitole představíme hru.
|
||||
|
||||
|
||||
|
||||
\section{Měřění}
|
||||
|
||||
|
||||
Snadným zmenšením paketů je zaměřit se na bity namísto bytů. Původně jsem nově příchozí datagramy obalil pomocí ByteBuffer, který umožnil dekódovat postupně příchozí byty. Často ale potřebujeme mít možnost zakódovat informaci pomocí jednotlivých bitů.
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user