aboutsummaryrefslogtreecommitdiff
path: root/design.tex
diff options
context:
space:
mode:
Diffstat (limited to 'design.tex')
-rw-r--r--design.tex383
1 files changed, 305 insertions, 78 deletions
diff --git a/design.tex b/design.tex
index 131031f..6bef7dc 100644
--- a/design.tex
+++ b/design.tex
@@ -15,7 +15,7 @@ similar to Jetpack Joyride.
The cr\^epe engine is designed to ease the transition for developers familiar with
Unity, ensuring minimal friction when switching platforms. Our aim is to preserve
-many of Unity’s core features while introducing a lightweight and open-source
+many of Unity's core features while introducing a lightweight and open-source
alternative, licensed under the MIT License.
The engine is primarily aimed at indie developers who have prior experience with
@@ -114,116 +114,307 @@ the main part of the \gls{ecs}. The design of these eight systems in combination
\gls{ecs}, will be briefly discussed in the next parts of this design document.
\section{Design}
+
\subsection{Game Loop}
-\subsubsection{Problem statement:}
-A game loop is essential for maintaining a continuous flow of game actions, ensuring that updates to game logic, physics, and rendering occur in a synchronized manner. Without a game loop, the game would lack consistent timing and leading to unpredictable behavior.
-The game loop is mainly responsible for these 2 purposes:
+
+\subsubsection{Problem statement}
+
+A game loop is essential for maintaining a continuous flow of game actions, ensuring
+that updates to game logic, physics, and rendering occur in a synchronized manner.
+Without a game loop, the game would lack consistent timing and leading to
+unpredictable behavior.
+
+The game loop is mainly responsible for these 2 purposes:\noparbreak
\begin{itemize}
- \item Updating all systems in the correct order.
+ \item Updating all systems in the correct order
\item Making sure the gameloop timer is up to date
\end{itemize}
-The game loop can be external where the user has the ability to update the systems themselves or an intergrated game loop which is managed by the gameloop.
-Both of these approaches have advantages and disadvantages when it comes to flexibility and reliability.
+The game loop can be external where the user has the ability to update the systems
+themselves or an intergrated game loop which is managed by the gameloop. Both of
+these approaches have advantages and disadvantages when it comes to flexibility and
+reliability.
-\subsubsection{Design:}
-The game loop of this engine is integrated into the engine, this is done for the following reasons:
-\begin{itemize}
- \item \emph{Simplify development} The user only has to call startGame().
- \item \emph{Uniform system calls} The systems are always updated in the same order limiting overwrites and undefined system behavior.
- \item \emph{Reliable timer update} Each cycle the game loop timer is always updated limiting timing issues.
-\end{itemize}
-As seen in figure \ref{gameloop-flow} the gameloop is divided into different steps.
+\subsection{Texture}
+
+% FIXME: our
+The textures in our game engine are represented by the \codeinline{Texture} class. It
+is implemented a \gls{facade} around the \gls{sdl} library.
+
+\subsubsection{Architecture}
+
+\Cref{fig:class-texture} shows a class diagram of the texture \gls{facade}. It
+contains the following classes:\noparbreak
+\begin{description}
+ \item[SDLContext] This is a facade around the \codeinline{SDL2} library which is
+ used around different parts of the engine, and is therefore implemented as a
+ singleton. This class is friends with \codeinline{Texture},
+ \codeinline{LoopManager}, \codeinline{RenderSystem} and
+ \codeinline{AnimatorSystem}.
+ \item[Texture] This is a wrapper around the \codeinline{SDL_Texture} class, and
+ uses cr\^epe's \codeinline{Asset} class to load an Texture instead.
+\end{description}
+
+\begin{figure}
+ \centering
+ % TODO: export as vector format instead
+ \includegraphics[width=\textwidth]{img/texture.png}
+ \caption{User texture class diagram}
+ \label{fig:class-texture}
+\end{figure}
+
+\subsection{AssetManager}
+
+The AssetManager is a \gls{api} class that the user can use to make a
+\codeinline{Asset} available from different scenes.
+
+\subsubsection{Architecture}
+
+\Cref{fig:class-assetmanager} shows a class diagram of the AssetManager. It contains
+the following classes:\noparbreak
+\begin{description}
+ \item[AssetManager] is a Singleton class, meaning only one instance of this class
+ exists throughout the application. This ensures a single point of access and
+ control over asset management, simplifying resource handling and avoiding
+ duplicated assets in memory.
+\end{description}
+
+\begin{figure}
+ \centering
+ % TODO: export as vector format instead
+ \includegraphics[width=0.5\textwidth]{img/AssesManager.png}
+ \caption{User AssetManager class diagram}
+ \label{fig:class-assetmanager}
+\end{figure}
+
+\subsection{Rendering}
+
+Every game engine has an rendering structure to present all the different enities and
+components on the screen.
+
+\subsubsection{Architecture}
+
+% TODO: anyone read this?
+\Cref{fig:class-rendering} shows a class diagram of the RenderSystem. It contains the
+following classes:\noparbreak
\begin{itemize}
- \item \emph{Update loop timer} The loop timer gets updated and the expected frame time is calculated.
- \item \emph{Check events} Queued events get dispatched and callback functions are handled acordingly.
- \item \emph{Process input} The input system is called and user input is processed.
- \item \emph{Fixed update} A fixed loop for timing sensitive systems such as physics.
- \item \emph{Update} A per frame update for all per frame updates.
- \item \emph{Render} Calling the render system to render the frame.
+ \item The system architecture is centered around rendering and component
+ management, with the following key components:\noparbreak
+ \begin{description}
+ \item[\codeinline{System}] An interface class containing the virtual
+ \codeinline{update()} function.
+ \item[\codeinline{RenderSystem}] A derived class of \codeinline{System}
+ responsible for rendering operations.
+ \end{description}
+ \item The \codeinline{System::get_instance()} function provides a static, singleton
+ instance for managing system-wide operations.
+ \item The \codeinline{RenderSystem} class implements various rendering
+ functions:\noparbreak
+ \begin{description}
+ \item[\codeinline{sort_layers()}] Organizes the rendering layers.
+ \item[\codeinline{clear_screen()}] Clears the screen prior to rendering.
+ \item[\codeinline{update_sprites()}] Updates sprite positions and states.
+ \item[\codeinline{update_camera()}] Manages the camera view.
+ \item[\codeinline{present_screen()}] Presents the final rendered image to the
+ screen.
+ \end{description}
+ \item The \codeinline{SdlContext} class, another singleton, manages the \gls{sdl}
+ and has a friendship relationship with \codeinline{ComponentManager} for tighter
+ integration with component management.
+ \item Components are organized as follows:\noparbreak
+ \begin{itemize}
+ \item The \codeinline{Component} base class allows for generic handling of
+ components.
+ \item Derived component classes include:\noparbreak
+ \begin{description}
+ \item[\codeinline{Sprite}] Represents visual elements with attributes like
+ \codeinline{sprite}, \codeinline{color}, \codeinline{flip},
+ \codeinline{sortingLayer}, and \codeinline{orderInLayer}.
+ \item[\codeinline{Transform}] Manages positional attributes, including
+ \codeinline{position}, \codeinline{rotation}, and \codeinline{scale}.
+ \end{description}
+ \end{itemize}
+ \item Both \codeinline{Sprite} and \codeinline{Transform} components provide a
+ \codeinline{get_instances_max()} function to retrieve the maximum instance count.
\end{itemize}
-This is done as illustrated in Figure \ref{gameloop-flow}, the game loop continues to call the fixed update function as long as sufficient time is available.
-Delta time, calculated using the time between the start of the last frame and the current frame, is used to measure the duration of each frame.
-This value is converted into a time-based unit, enabling other systems or game developers to create behavior independent of frame rate.
-
-Rendering and animations are handled separately on a per-frame basis. A delay, in conjunction with the delta time calculation,
-is applied to maintain consistent visual behavior, even when frame rates vary.
-As seen in figure Figure \ref{gameloop-class} to access the deltaTime anywhere in the system a timerClass is created using a singleton desing pattern which ensures only one instance of the class is created; the gameloop updates the timing and delta time of this class to ensure it is accurate.
-The gameloops two main functions are the setup() and loop(). The first is called when the game starts and handles all startup procedures this function only runs once.
-The loop() function keeps looping as long as the game is running.
-The gamedeveloper start the game engine/game using the code example below:
+
+\begin{figure}
+ \centering
+ % TODO: export as vector format instead
+ \includegraphics[width=\textwidth]{img/Rendering.png}
+ \caption{System Rendering class diagram}
+ \label{fig:class-rendering}
+\end{figure}
+
+\subsubsection{System}
+
+\begin{figure}
+ \centering
+ % TODO: export as vector format instead
+ \includegraphics[width=\textwidth]{img/flowchart_rendering.png}
+ \caption{System Rendering flowchart }
+ \label{fig:class-renderingflowchart}
+\end{figure}
+
+\subsubsection{Design}
+
+The game loop of this engine is integrated into the engine, this is done for the
+following reasons:\noparbreak
+\begin{description}
+ \item[Simplify development] The user only has to call \codeinline{startGame()}.
+ \item[Uniform system calls] The systems are always updated in the same order
+ limiting overwrites and undefined system behavior.
+ \item[Reliable timer update] Each cycle the game loop timer is always updated
+ limiting timing issues.
+\end{description}
+
+As seen in \cref{fig:gameloop-flow} the gameloop is divided into different
+steps:\noparbreak
+\begin{description}
+ \item[Update loop timer] The loop timer gets updated and the expected frame time is
+ calculated.
+ \item[Check events] Queued events get dispatched and callback functions are handled
+ acordingly.
+ \item[Process input] The input system is called and user input is processed.
+ \item[Fixed update] A fixed loop for timing sensitive systems such as physics.
+ \item[Update] A per frame update for all per frame updates.
+ \item[Render] Calling the render system to render the frame.
+\end{description}
+
+This is done as illustrated in \cref{fig:gameloop-flow}, the game loop continues to call
+the fixed update function as long as sufficient time is available. Delta time,
+calculated using the time between the start of the last frame and the current frame,
+is used to measure the duration of each frame. This value is converted into a
+time-based unit, enabling other systems or game developers to create behavior
+independent of frame rate.
+
+Rendering and animations are handled separately on a per-frame basis. A delay, in
+conjunction with the delta time calculation, is applied to maintain consistent visual
+behavior, even when frame rates vary. As seen in \cref{fig:gameloop-class} to access the
+deltaTime anywhere in the system a timerClass is created using a singleton desing
+pattern which ensures only one instance of the class is created; the gameloop updates
+the timing and delta time of this class to ensure it is accurate. The gameloops two
+main functions are the setup() and loop(). The first is called when the game starts
+and handles all startup procedures this function only runs once. The loop() function
+keeps looping as long as the game is running.
+
+The gamedeveloper start the game engine/game using the code example below:\noparbreak
\begin{blockcode}
- Gameloop loop;
- loop.start();
+Gameloop loop;
+loop.start();
\end{blockcode}
-This starts calls the setup() and loop() functions and starts the game loop timer;
-To get the current frames Delta time \codeinline{LoopTimer::getInstance().getDeltaTime()} can be used which will return the expected frame time.
+
+This starts calls the setup() and loop() functions and starts the game loop timer; To
+get the current frames' delta time, the \codeinline{getDeltaTime()} method on the
+\codeinline{LoopTimer} singleton can be used, which will return the expected frame
+time.
\begin{figure}
\centering
\includepumldiag{img/gameloop-flow.puml}
- \caption{Gameloop Flowchart Diagram} \label{gameloop-flow}
+ \caption{Gameloop Flowchart Diagram}
+ \label{fig:gameloop-flow}
\end{figure}
\begin{figure}
\centering
\includepumldiag{img/gameloop-class.puml}
- \caption{Gameloop Flowchart Diagram} \label{gameloop-class}
+ \caption{Gameloop Flowchart Diagram}
+ \label{fig:gameloop-class}
\end{figure}
+
\subsection{Event system}
-\subsubsection{Problem Statement:}
-The game engine utilizes the Entity-Component-System (ECS) architecture, where components store data,
-and systems process that data to apply changes. Each system is responsible for managing a specific domain,
-such as physics in the physics system and rendering in the rendering system.
-To facilitate communication between systems without introducing direct dependencies,
-a method of inter-system communication is required to maintain loose coupling.
-Additionally, a mechanism that allows one object's trigger to manipulate adn affect multiple other objects is beneficial for game developers, providing greater flexibility in designing interactions within the game.
-
-
-\subsubsection{Architecture:}
-The sollution to connect the various systems and BehaviorScripts together without inducing high coupling is an event system that facilitates communication between systems and BehaviorScripts using various types of events.
-The event system includes several pre-defined events, all derived from a parent Event class, capable of handling user input and application-level events, such as window resizing.
-Furthermore, a specific event is designated for the collision handler within the physics system, which can be triggered when two objects collide.
-The event system also allows developers to create custom events, such as "onPlayerDeath," and assign callback functions that execute when the event is triggered.
+
+\subsubsection{Problem Statement}
+
+The game engine utilizes the \gls{ecs} architecture, where components store data, and
+systems process that data to apply changes. Each system is responsible for managing a
+specific domain, such as physics in the physics system and rendering in the rendering
+system. To facilitate communication between systems without introducing direct
+dependencies, a method of inter-system communication is required to maintain loose
+coupling. Additionally, a mechanism that allows one object's trigger to manipulate
+adn affect multiple other objects is beneficial for game developers, providing
+greater flexibility in designing interactions within the game.
+
+\subsubsection{Architecture}
+
+The sollution to connect the various systems and BehaviorScripts together without
+inducing high coupling is an event system that facilitates communication between
+systems and BehaviorScripts using various types of events. The event system includes
+several pre-defined events, all derived from a parent Event class, capable of
+handling user input and application-level events, such as window resizing.
+Furthermore, a specific event is designated for the collision handler within the
+physics system, which can be triggered when two objects collide. The event system
+also allows developers to create custom events, such as "onPlayerDeath," and assign
+callback functions that execute when the event is triggered.
+
\begin{figure}
- \centering
- \includegraphics[width=\linewidth]{img/event-uml.drawio.png}
- \caption{event system class diagram}
- \label{fig:event-uml}
+ \centering
+ % TODO: export as vector format instead
+ \includegraphics[width=\linewidth]{img/event-uml.drawio.png}
+ \caption{Event system class diagram}
+ \label{fig:event-uml}
\end{figure}
-the event system as seen in \ref{fig:event-uml} includes several parts such as:
+The event system as seen in \cref{fig:event-uml} includes several parts such
+as:\noparbreak
\begin{description}
- \item[eventManager] The manager has the functions to subscribe/trigger/queue/dispatch events. It also stores all callback functions corresponding to specific event.
- The manager is a singleton and can therefor only exist once so all events are stored in one place.
- \item[IEventWrapper] This is a EventWrapper \emph{interface} which is used to store all the different templated eventshandlers in one map in the event manager.
- this wrapper contains the logic to convert the parent class \emph{event} to the correct subclasses. It also contains a variable onSuccessDestroy which can be set to destroy the callback call onces completed.
- This can be used to make a one time only event.
- \item[Event] This is the parent class where all specific event classes are derived from. Each event contains a
- \begin{itemize}
- \item \emph{\codeinline{static std::uint32_t getStaticEventType()}} to set type during compiling.
- \item \emph{\codeinline{virtual std::uint32_t getEventType() const override }} function to manage the type conversion during runtime.
- \end{itemize}
- Other functions can be freely added when creating a custom function.
- When an event is triggered a specific derived class must be used to indicate which event is triggered. A reference to this event is then transfered to all callback functions subscribed.
+ \item[eventManager] The manager has the functions to
+ subscribe/trigger/queue/dispatch events. It also stores all callback functions
+ corresponding to specific event. The manager is a singleton and can therefor only
+ exist once so all events are stored in one place.
+ \item[IEventWrapper] This is a EventWrapper \emph{interface} which is used to store
+ all the different templated eventshandlers in one map in the event manager. this
+ wrapper contains the logic to convert the parent class \emph{event} to the
+ correct subclasses. It also contains a variable onSuccessDestroy which can be set
+ to destroy the callback call onces completed. This can be used to make a one time
+ only event.
+ \item[Event] This is the parent class where all specific event classes are derived
+ from. Each event contains a---
+ \begin{itemize}
+ % TODO: the design document is not a technical reference, so implementation
+ % details shouldn't even be in here. Also, are getter functions used to set
+ % things nowadays?
+ \item \emph{\codeinline{static std::uint32_t getStaticEventType()}} to set type
+ during compiling.
+ \item \emph{\codeinline{virtual std::uint32_t getEventType() const override }}
+ function to manage the type conversion during runtime.
+ \end{itemize}
+ Other functions can be freely added when creating a custom function. When an
+ event is triggered a specific derived class must be used to indicate which event
+ is triggered. A reference to this event is then transfered to all callback
+ functions subscribed.
\end{description}
-The EventManager is a singleton so all all callbacks are stored in one place and it can be called everywhere in the system or game.
-The user can use the EventManager for the following functions:
-\begin{itemize}
- \item \emph{Subscribe:} This subscribes a function pointer or lambda function to a given event. The function can be subscribed either to all event triggers or a specifc ID.
- \item \emph{Trigger:} This triggers a given event and all callbacks correlating to this event are executed immediately.
- \item \emph{Queue event:} This queues an event to be executed at a fixed time during the gameloop.
- \item \emph{Unsubscibe:} This removes the callback function from the event and it will no longer be executed.
-\end{itemize}
-Figure \ref{fig:event-seq} shows that when a specific function is triggered or dispatched using the callback(eventHandler) is executed.
+
+The EventManager is a singleton so all all callbacks are stored in one place and it
+can be called everywhere in the system or game. The user can use the EventManager for
+the following functions:\noparbreak
+\begin{description}
+ \item[Subscribe] This subscribes a function pointer or lambda function to a given
+ event. The function can be subscribed either to all event triggers or a specifc
+ ID.
+ \item[Trigger] This triggers a given event and all callbacks correlating to this
+ event are executed immediately.
+ \item[Queue event] This queues an event to be executed at a fixed time during the
+ gameloop.
+ \item[Unsubscibe] This removes the callback function from the event and it will no
+ longer be executed.
+\end{description}
+
+\Cref{fig:event-seq} shows that when a specific function is triggered or dispatched
+using the callback(eventHandler) is executed.
+
\begin{figure}
\centering
\includepumldiag{img/event-sequence.puml}
\caption{Sequence diagram for event calling}
\label{fig:event-seq}
\end{figure}
+
% \subsection{Physics}
+
\subsection{Rendering}
+
\subsection{Scripting}
The scripting interface was designed around a `target' \gls{api} (described by
@@ -463,7 +654,7 @@ structs, which are used to organize options per system or engine component.
\appendix
-\section{\Glsfmtlongpl{poc}}
+\section{Proof-of-concepts}
The full (documented) source code of these \glspl{poc} is available on GitHub
\autocite{crepe:code-repo}.
@@ -538,5 +729,41 @@ was later converted to a full audio \gls{facade}, which is currently part of the
cr\^epe engine. The \gls{poc} using the audio \gls{facade} is available from the same
repository, under the \codeinline{src/example/audio_internal.cpp} file.
+\subsection{Camera}
+\label{poc:camera}
+
+The camera \gls{poc} \autocite[camera example]{crepe:code-repo} consists of the
+following:\noparbreak
+\begin{itemize}
+ \item An \codeinline{on_key_pressed} function, which listens for key presses and
+ adjusts camera position and zoom based on key inputs.
+ \item A user-defined script class (\codeinline{MyCameraScript}) derived from
+ \codeinline{Script}, implementing only the \codeinline{update()} function. To
+ update the camera movements and zoom.
+ \item A main function that---
+ \begin{itemize}
+ \item Subscribes the \codeinline{on_key_pressed} function to handle
+ \codeinline{KeyPressedEvent} events.
+ \item Creates a \codeinline{GameObject} for the camera and adds
+ \codeinline{Camera} and \codeinline{BehaviorScript} components, with
+ \codeinline{MyCameraScript} attached to manage the camera's transformation.
+ \item Instantiates a background \codeinline{GameObject} with
+ \codeinline{Transform} and \codeinline{Sprite} components, loading an
+ external texture as its background.
+ \end{itemize}
+\end{itemize}
+
+Running this \gls{poc} allows for controlled camera movement and zoom in response to
+key inputs. The \codeinline{MyCameraScript::update} function ensures that these
+transformations are applied each frame, as demonstrated by the output in
+\cref{fig:poc-output-camera}.
+
+\begin{figure}
+ \centering
+ \fitimg{\includegraphics[scale=0.7]{img/poc-camera.pdf}}
+ \caption{Camera \glsfmtshort{poc} output}
+ \label{fig:poc-output-camera}
+\end{figure}
+
\end{document}