Implementacja Unity wykorzystuje kilka kluczowych wzorców projektowych:
\paragraph{Wzorzec Bootstrap}
Klasa \texttt{GameBootstrap} wykorzystuje atrybut \texttt{[Runtime\-Initialize\-OnLoad\-Method]} do zapewnienia, że obiekt \texttt{GameInitializer} istnieje w~scenie przed rozpoczęciem gry. Jest to eleganckie rozwiązanie problemu inicjalizacji singletonów w~Unity.
\paragraph{Object Pooling}
System \texttt{BulletPool} stanowi rdzeń optymalizacji wydajnościowej. Zamiast ciągłego tworzenia i niszczenia obiektów pocisków (co generowałoby znaczące obciążenie garbage collectora), pociski są recyklingowane z puli:
\begin{lstlisting}[language=C, caption={Fragment implementacji object poolingu w Unity}, label={lst:unity-pool}]
public Bullet Spawn(Vector2 position, Vector2 direction,
Pula jest wstępnie rozgrzewana (\textit{warm capacity}) podczas inicjalizacji, co eliminuje alokacje podczas rozgrywki.
\paragraph{Singleton Pattern}
Klasy \texttt{GameDirector} i \texttt{EnemySpawner} wykorzystują wzorzec Singleton z właściwością \texttt{Instance}, zapewniając globalny punkt dostępu do kluczowych systemów gry.
\subsubsection{System spawnu przeciwników}
\texttt{EnemySpawner} implementuje system eskalującej trudności poprzez interpolację czasu między spawnami:
\begin{lstlisting}[language=C, caption={Interpolacja trudności w Unity}, label={lst:unity-difficulty}]
Przeciwnicy są definiowani przez strukturę \texttt{EnemyBlueprint}, która zawiera parametry takie jak prędkość, zdrowie, wzorce strzelania i zachowania. To podejście data-driven pozwala na łatwe tworzenie różnorodnych typów wrogów.
\subsubsection{Wyzwania napotkane w Unity}
Podczas implementacji napotkano następujące wyzwania:
\begin{enumerate}
\item\textbf{Garbage Collection} -- początkowa implementacja bez object poolingu powodowała zauważalne spadki klatek przy dużej liczbie pocisków
\item\textbf{Kolejność inicjalizacji} -- konieczność użycia wzorca Bootstrap wynikała z~nieprzewidywalnej kolejności wywoływania metod \texttt{Awake()} i~\texttt{Start()}
\item\textbf{Serializacja} -- atrybuty \texttt{[SerializeField]} wymagały starannego rozplanowania, które pola powinny być edytowalne w~inspektorze
\item Interfejs użytkownika nie jest odświeżany po otwarciu menu \cite{linux_editor_does_not_redraw} -- wymagało to ręcznego wymuszenia odświeżenia inspektora
\item Uzyskanie dostępu do oficjalnego repozytorium GitHub Epic Games i samodzielna kompilacja silnika ze źródeł \cite{unreal_arch_installation_source}
\item Pobranie prekompilowanej wersji binarnej \cite{unreal_arch_installation_binary}
Czas instalacji (Linux) &$\sim$30 min &$\sim$2-4 h \\
\hline
Wsparcie natywne 2D & Tak & Nie (symulowane) \\
\hline
Język programowania & C\#& C++ / Blueprinty \\
\hline
Próg wejścia & Niski & Średni/Wysoki \\
\hline
Czas kompilacji & Szybki & Wolny (C++) \\
\hline
Object pooling & Prosty & Bardziej złożony \\
\hline
Hot reload & Tak & Ograniczony \\
\hline
Rozmiar projektu & Mały & Duży \\
\hline
\end{tabular}
\end{table}
\subsection{Wnioski z implementacji}
Doświadczenia z implementacji gry bullet-hell potwierdzają, że wybór silnika powinien być uzależniony od typu projektu:
\begin{enumerate}
\item\textbf{Dla gier 2D} -- Unity oferuje znacznie lepsze wsparcie natywne, niższy próg wejścia i szybszy cykl iteracji
\item\textbf{Dla gier 3D AAA} -- Unreal Engine dysponuje lepszymi narzędziami do tworzenia fotorealistycznej grafiki
\item\textbf{Dla prototypowania} -- Unity pozwala na szybsze testowanie koncepcji dzięki hot reloadowi i prostszej konfiguracji
\item\textbf{Dla zespołów mieszanych} -- Blueprinty Unreal mogą być wartościowe dla współpracy z designerami, choć problemy z kontrolą wersji stanowią wyzwanie