\chapter{Vývoj hry} \label{chap:main} Přenos starého projektu na~další major verzi~UE nebyl nijak problematický, dokonce v~editoru je~možnost rychlého exportu assetů do~jiného projektu. Rozhodně tomu pomohlo, že~se~C++~kód nepřenášel, ale~napsal znovu. UE~citelně rozšířil seznam dostupných tříd, ale~zaroveň některé jsou~již deprecated nebo~odstraněny úplně. Tak~například byly~odstraněny třídy Matinee (bývalý format animací pohybu objektů) pro~podporu novejší třídy Sequencer nebo~starý PhysX rozhraní (Fyzický engine), které~je nahrazeno systémem Chaos. Přesto se~něco pokazilo při~exportu objektů s~dynamickou fyzikou (závěsy, které~reagují na~simulaci větru, se~museli předělat). Přenos byl~odůvodněn převážně malou velikostí starého projektu a~taky lákavou nabídkou nových technologií zejména Nanite a~Lumen. Navíc pátá verze Unrealu -- přesněji verze~5.5 -- přinesla značná vylepšení jako: \begin{itemize} \item Nový systém zpracování vstupu Enhanced Input\footnote{https://dev.epicgames.com/documentation/en-us/unreal-engine/enhanced-input-in-unreal-engine}. Místy má~příliš mnoho objektové abstrakce, ale~rozhodně velký krok vpřed. Umožňuje snadné dynamické přepínání různých sad ovládání (multiplayer hry, gameplay/menu), dynamické modifikátory a~spouštěče vstupu (změna senzitivity, víceklik, podržení tlačítka určitou dobu), podpora vstupu více než~jedné periferie naraz a~podpora přeřazení vstupu (např.~změna tlačítka odpovídající za~skok herní postavy). Předtím tohle a~spoustu dalšího se~muselo naprogramovat ručně. \item Podporu vektorové grafiky v~UI. Veškeré staré UI~elementy byly~tvořeny pomocí základních vektorových obdélníkových tvarů práve proto, aby~se~vyhnulo použití rastrové grafiky, která~je~hodně závislá na~rozlišení. Aktuálně všechny UI~elementy jsou tvořeny ještě starou metodou, pro~udržení konzistentního vzhledu. Dnes bychom určitě využili této~možnosti. \item Přepracované vykreslování textů -- rychlejší vykreslování a~efektivnější využití paměti. \item MetaSound\footnote{https://dev.epicgames.com/documentation/en-us/unreal-engine/metasounds-the-next-generation-sound-sources-in-unreal-engine} pro~přehrávaní nebo procedurální generování zvuků, který~nahrazuje starou třídu~Cue. De-facto se~jedná o~Digital Signal Processing (DSP) grafový engine a~editor. Bohůžel jsem nestihl tento nastroj využit v~práci. \item World partition systém\footnote{https://dev.epicgames.com/documentation/en-us/unreal-engine/world-partition-in-unreal-engine} který~dokáže automaticky rozdělit jeden velký svět na~streamovací kousky a~propojit sdílení dat mezi nimi i~při multiplayer hře přes internet. Taky není využit v~této práci. \end{itemize} Samozřejmě je~toho daleko víc, ale~většina ostatních vylepšení jako~například nový systémy animací postav Motion Matching\footnote{https://dev.epicgames.com/documentation/en-us/unreal-engine/motion-matching-in-unreal-engine} nebo~nový fyzikální engine Chaos\footnote{https://dev.epicgames.com/documentation/en-us/unreal-engine/destruction-overview} neměli vliv na~rozhodnutí. Podrobné informace jak každá implementace funguje a jak vývojaři s ní pracovat jsou popsané v programatorské dokumentaci. \section{Herní logika a systémy} \subsection{Architektura} Protože Unreal Engine byl na začátku vývíjen primárně pro online multiplayer hru Unreal Tournament a dnes stejně tak vyvíjen spolu s extremně velkou online multiplayer hrou Fortnite, je backend enginu dost abstraktní. Například tak každý svět musí obsahovat vlastní game mode (třída AGameMode), který funguje jako správce dáneho světu -- přestože svět se může spravovát sám. Veškerá funkcionalita používaná v singlplayer hrách mohla by být přímo v kódu levelu nebo v globální instanci celé hry. Důvodem teto abstrakce je právě nativní podpora multiplayer her, která potom vývoj takových her zjednodušuje. Protože tento projekt je zaměřen pro hru jednoho hráče, práce je často programováná navzdory ustaleným UE C++ guidelines pro pohodlí a rychlost vývoje. Proto často třídy managerů systémů, game modů, instance hráče a další jsou na architektuře singletonu. Šetří od tří do desetí různých volání getteru, castu reflexe, vyhledávání v hash tabulkach a iteraci polí v každém místě použití. Přesto nemá žádný vliv na stabilitu programu a dokonce šetří výkonem zařízení. Jen pro představu co obnaší klasické ziskání reference na instanci vlastní třídy hráče na pozadí. GetGameMode() \textrightarrow GetPlayerController(index) \textrightarrow GetPlayerPawn() \textrightarrow Cast(). A blueprinty disponují zkrácenou verzí GetPlayerPawn(index) \textrightarrow Cast(). V případě C++ je potřeba navíc ověřovat zda nějaké z volání nevratílo nullptr. \subsection{Scény a ukládání hry} Scény resp. levely (třídy UWorld a ALevelScriptActor)\footnote{UWorld instance je přímo celý svět, který funguje jako balík metadat a kontejner pro veškeré instancované objekty v něm. ALevelScriptActor je objekt instancovaný v UWorld automaticky a obsahuje uživatelskou logiku světa.} taktéž lze získat v podobě singletonu. Základní implementace byla rozšířená pro high level mechanismus volání událostí ve scéně. Ten je za potřebí například, když hráč aktivuje spínací plošinu ve hře a ta následně otevře dveře. Narozdíl od jiných enginů, v UE objekty ve světě nemůžou referencovat jiné nezávislé objekty. Jednoduše referenci nejde přiřadít z důvodu abstrakce popsané v předchozí podsekci, protože každý objekt může mít vlastní herní svět (a nejen to). Proto pokud plošina z našeho príkladu chce otevřít dveře, musí zkusit poslat požádavek správcí herního světa, ten požadavek se nějak zpracuje a jen potom správce buď provede akci otevírání dveří samostatně nebo zavolá odpovidající funkci v instanci objektu. Pokud by byla potřeba zbavit se použití singleton architektury pro podporu paralelní existenci světů, stači předělat member funkci instance světa na statický multicast delegate\footnote{Delegate jsou obaly na C++ funkce, lambdy, funkce s reflexi a funkce z Blueprintu. Delegate může být typu single, pro uložení reference na jednou funkci, nebo multicast pro uložení dynamického seznamu funkcí. Podrobněji jsou popsané v programatorské dokumentaci.}, ke kterému se každý svět při konstrukci bude vázat. Navíc hra byla rozšířena o implementaci obnovení hry z úložených dat. Při návrhu byla snaha udělat postup nejvíc triviální. Hru ukládá globální herní instance (třída GameInstance)\footnote{GameInstance je první objekt vytvořený enginem hned po úvodním načtení základu enginu a taky poslední objekt na destrukci při vypínání hry.} při vypínání hry a načíta taktéž při spouštění. Využit byl existující v UE systém serializace, který ukládá inventař postavy, jmeno levlu a checkpoint na něm spolu s posledním stavem levlu. \subsection{Interakce} Interakce jsou často řešeny pomoci architektury interface tříd\footnote{Interface třídy jsou konkurenčním přístupem komponentní architektuře. Interface je běžná praktika v OOP, která funguje jako domluva, že objekt bude obsahovat určité member funkce. Komponentny jsou samostatné určité podinstance objektu. Komponentní přístup se osvědčuje jako intuitivnější a více flexibilní zatímco Interface přístup při vývoji her je spíše nepřijemné vynucení ze světu OOP.} především kvůli populárním návodům vyzdvihující tuto metodu jako nejlepší ještě z doby, kdy jen vzníkal Unreal Engine 4. Nevýhodou je potřeba v obsáhlem a repetetivním nastavení každeho objektu, který chceme zapojit do mechaniky interakce. Byl navržen kompletní systém pro spravu každého interačního objektu a komponent (viz.\Cref{fig:InteractableSystemDiagram}). Objekt dědicí třídu AInteractable při instancování samostatně nastaví a následně přepína potřebné kolize. Navíc spravuje interakční komponenty a reaguje na požadavky k ním. Komponenty se dělí na aktivatory a modifikatory. \begin{figure} \centering \includegraphics[width=1\linewidth]{img/InteractableScreenCapture.pdf} \caption{Debug náhled aktivace interakčních objektů v zornem poli hráče.} \label{fig:InteractableScreenCapture} \end{figure} \paragraph{AInteractableActivator} Aktivátory jsou komponenty s úrčitými mechanismy detekce objektů. Instance hráče automaticky vytváří pro sebe jednu podinstanci každého aktivatoru zaregistrovaného v enginu. Libovolný objekt taky může obsahovat libovolný aktivator. Práce obsahuje klasický způsob detekce objektů pomoci raytracingu a castu objektu v případě nárazu paprsku. Navíc je k dispozici detekce objektů v zornem poli hráče. Ta funguje na zpomaleném snímání určité stencil vrstvy s vynecháním většiny render pipliny a v malém rozlišení. Zachycený snímek obsahuje pouze viditelné hráčem interakční objekty v podobě masky. Nasledně maska v grafickém vlakně je zpracovaná pomocí algoritmu vyhledávání komponent z počítačového vidění, kterou poskytuje kníhovna OpenCV. Nakonec do středu nalezených komponent se promítné paprsek a zachytí objekty (viz. \Cref{fig:InteractableScreenCapture}). Původně bylo předpokládáno využití HLSL compute shaderu pro vyhledání komponent v textuře, ale z časových důvodu jsem nedodělal přenos dat mezi CPU a GPU, jelikož dohledat dokumentaci o použití shaderu je dost náročné. Proto aktuální vyhledávání komponent je spouštěno na procesoru a v renderovacím vlakně na moderních zařízeních trvá pět až deset milisekund. \begin{figure} \centering \includegraphics[width=1\linewidth]{img/InteractableScreenCapture.pdf} \caption{Debug náhled aktivace interakčních objektů v zornem poli hráče.} \label{fig:InteractableScreenCapture} \end{figure} \paragraph{AInteractableModificator} Modifikátory jsou komponenty s úrčitou logikou libovolné modifikace objektu, ve kterém jsou instancovány. Tyto komponenty mohou obsahovat pouze objekty označené jako interakční (dědí třídu interákčního objektu). Aktuální implementace nabízí modifikátory pro aktivaci nějaké události pomoci dosahu ,,ruky'' nebo zahlednutím ,,očí'' hráče, pohyb a rotace předmětu v prostoru, ukládání předmětu do inventáře hráče. Z časových důvodu byla zamítnuta implementace modifikace meshe objektu, která by využivala nového rozhraní Chaos. Právě u modifikátorů nejvíc přispěl nový system vstupu pro Unreal Engine 5. Modifikatory využívájí možnosti přidávání resp. odstranění kontextů vstupu za běhu. \subsection{Cutscény} \subsection{Quick Time Eventy} \subsection{Dialogy} \subsection{Minihry} \subsection{Nehratelné postavy} \subsection{API načítání nového obsahu za běhu} \subsection{Nastavení} \section{Grafika} \subsection{Statické objekty} \subsection{Dynamické a procedurální objekty} \subsection{Osvětlení, efekty, Post-Processing} \subsection{Materiály a shadery} \subsection{UI} \subsection{Načítací obrazovka} \subsection{Textové překlady} \section{Audio} \subsection{Kategorie a parametry audio assetů} \subsection{Dynamický hudební doprovod} \section{Tipy při vývoji v UE} \paragraph{Skripty pro editor} % Blueprunty a python \paragraph{C++ typy a reflexe} \paragraph{Kompilace a export projektu}