aboutsummaryrefslogtreecommitdiff
path: root/design.tex
diff options
context:
space:
mode:
authorLoek Le Blansch <loek@pipeframe.xyz>2024-11-03 00:22:58 +0100
committerLoek Le Blansch <loek@pipeframe.xyz>2024-11-03 00:22:58 +0100
commit07f40f3dc1ef4655844e312ba69be3fbebec51b7 (patch)
tree4ebc5e65290cace95cac5dabe5cfe8f5a5d4a95a /design.tex
parent3007b3677ae6a0752a9d1fb136d6ea84c1b6d555 (diff)
parent0bed01a4e2e820b8974207145cd2eb3430864ad7 (diff)
merge #49
Diffstat (limited to 'design.tex')
-rw-r--r--design.tex179
1 files changed, 178 insertions, 1 deletions
diff --git a/design.tex b/design.tex
index a7ad91e..6bef7dc 100644
--- a/design.tex
+++ b/design.tex
@@ -115,6 +115,26 @@ the main part of the \gls{ecs}. The design of these eight systems in combination
\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:\noparbreak
+\begin{itemize}
+ \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.
+
\subsection{Texture}
% FIXME: our
@@ -236,8 +256,165 @@ following classes:\noparbreak
\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();
+\end{blockcode}
+
+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{fig:gameloop-flow}
+\end{figure}
+
+\begin{figure}
+ \centering
+ \includepumldiag{img/gameloop-class.puml}
+ \caption{Gameloop Flowchart Diagram}
+ \label{fig:gameloop-class}
+\end{figure}
+
+\subsection{Event system}
+
+\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
+ % 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 \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}
+ % 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:\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
@@ -477,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}.