engineer-thesis-WUT/Thesis/Thesis.tex

2536 lines
116 KiB
TeX
Raw Normal View History

\documentclass[a4paper,11pt,twoside]{report}
% From specification:
% kroj bezszeryfowy rozmiar 11
% Druk dwustronny A4
2022-08-22 13:26:35 +02:00
% Pod rozdzialy do trzech poziomow -> domyslnie zalatwione przez latexa
% Rozdzialy poziomu I od nowej strony -> domyslnie przez latexa
% Wyliczenia -> tylko kropka lub myslnik -> tylko kropka domylsnie przez latexa
2023-08-28 22:27:07 +02:00
\usepackage{dirtree}
\usepackage{ulem}
2022-08-17 19:22:26 +02:00
\usepackage{fontspec}
2022-08-18 20:09:21 +02:00
\usepackage{anyfontsize}
\usepackage{graphicx}
2023-08-31 15:34:05 +02:00
\usepackage{subcaption}
2022-08-18 20:09:21 +02:00
\usepackage{geometry}
\usepackage{leading}
2022-08-23 14:19:26 +02:00
\usepackage[nottoc]{tocbibind}
\usepackage{titleps}
\usepackage{float}
% From specification:
% Tytuł tabeli
% Umieszczony nad tabelą (manually by setting caption above table)
% Justowany do lewej -> raggedright
% Czcionka bezszeryfowa rozmiar 9 -> footnotesize (see: https://www.sascha-frank.com/latex-font-size.html)
% Podpis rysunku -> pod rysunkiem (manually by setting caption below table)
% Źródło rysunku/tabeli -> Pod rysunkiem lub tabelą (manually by setting caption below table)
2022-08-22 13:26:35 +02:00
% Przypis dolny -> numeracja ciagla w calej pracy, kroj bezszeryfowy analogiczy jak w tekscie, rozmiar 9
\usepackage[font=footnotesize, justification=raggedright]{caption}
\usepackage{svg}
2022-08-22 13:26:35 +02:00
% Kroj pisma tytulow glownych rozdzialow
% pogrubiony bezszeryfowy -> wyzej
% tytul 1 poziomu 14
% tytul 2 poziomu 13
% tytul 3 poziomu 12
\usepackage{sectsty}
2023-08-29 14:29:46 +02:00
\usepackage{tikz}
\usetikzlibrary{shapes.geometric, arrows, positioning}
\tikzstyle{startstop} = [rectangle, rounded corners, minimum width=3cm, minimum height=1cm,text centered, draw=black, fill=red!30]
\tikzstyle{io} = [trapezium, trapezium left angle=70, trapezium right angle=110, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=blue!30]
\tikzstyle{process} = [rectangle, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=orange!30]
\tikzstyle{decision} = [diamond, minimum width=3cm, minimum height=1cm, text centered, draw=black, fill=green!30]
\tikzstyle{arrow} = [thick,->,>=stealth]
2022-08-24 16:58:20 +02:00
2022-08-22 13:26:35 +02:00
\chapterfont{\fontsize{14}{14}\selectfont}
\sectionfont{\fontsize{13}{13}\selectfont}
\subsectionfont{\fontsize{12}{12}\selectfont}
% From specification:
% Numeracja tabel i rysunków:
% Ciagła w całej pracy <-----
% Kolejna w rozdziałach
\usepackage{chngcntr}
2023-08-28 22:27:07 +02:00
\usepackage{tabularx}
\counterwithout{figure}{chapter}
\counterwithout{table}{chapter}
% From specification:
% Odwołania do źródeł
% Styl numeracyjny wg normy PW
% OR Styl Harwardzki <-----
% Bibliografia w układzie alfabetycznych wg nazwisk autorów (has to be ensured manually)
\usepackage{natbib}
2022-08-24 16:58:20 +02:00
\usepackage{hyperref}
\hypersetup{
colorlinks=true,
linkcolor=blue,
filecolor=magenta,
urlcolor=cyan,
pdftitle={Overleaf Example},
pdfpagemode=FullScreen,
}
\bibliographystyle{agsm}
% From specification:
% Numeracja stron:
% U dolu
% Po zewnetrznej stronie
% Odbicie lustrzane na stronach parzystych i nie parzystych
\renewpagestyle{plain}{%
\sethead{}{}{}
\setfoot[\thepage][][]{}{}{\thepage}
}%
\pagestyle{plain}
% From specification:
% kroj bezszeryfowy rozmiar 11
\renewcommand{\familydefault}{\sfdefault}
% From specification:
% Akapit wciecie 0.5 cm <-----
% OR bez wciecia z odstepem 4 przed akapitem
\setlength{\parindent}{0.5cm}
% From specification:
% Marginesy:
% wewnetrzny - 30 mm
% Zewnetrzny - 20 mm
% Gorny/dolny - 25 mm
2022-08-18 20:09:21 +02:00
\geometry{
inner=30mm,
2022-08-18 20:09:21 +02:00
outer=20mm,
2022-08-20 18:14:52 +02:00
top=25mm,
bottom=25mm,
2022-08-18 20:09:21 +02:00
}
\graphicspath{ {./images/} }
\newenvironment{centereq}[1][0.90]
{%
\trivlist
\centering
\setlength{\leftskip}{\dimexpr(\columnwidth-#1\columnwidth)/2\relax plus 1em}%
\setlength{\rightskip}{\leftskip}%
\item\relax
}
{\endtrivlist}
2023-08-30 00:54:33 +02:00
\usepackage{listings}
\usepackage{xcolor}
\lstdefinestyle{C++Style}{
language=C++,
basicstyle=\footnotesize\ttfamily,
keywordstyle=\color{blue},
commentstyle=\color{gray},
stringstyle=\color{red},
numbers=left,
numberstyle=\tiny,
frame=single,
keepspaces=true,
showspaces=false,
showtabs=false,
tabsize=2,
breaklines=true,
breakatwhitespace=true
}
\lstdefinestyle{mystyle}{
backgroundcolor=\color{gray!10},
basicstyle=\ttfamily\footnotesize,
breakatwhitespace=false,
breaklines=true,
captionpos=b,
keepspaces=true,
numbers=left,
numbersep=5pt,
showspaces=false,
showstringspaces=false,
showtabs=false,
tabsize=2,
language=Python,
morekeywords={os, re},
}
% for blank page after title
\usepackage{afterpage}
\newcommand\blankpage{%
\null
\thispagestyle{empty}%
\addtocounter{page}{-1}%
\newpage}
2022-08-18 20:09:21 +02:00
\newfontfamily{\adagio}{Adagio_Slab}
\newfontfamily{\adagioLight}{Adagio Slab Light}
\newfontfamily{\helveticaLight}{HelveticaLTStd-Light}
\newfontfamily{\helvetica}{Helvetica}
2022-08-22 13:43:33 +02:00
\newcommand{\tytul}{
2023-08-28 22:27:07 +02:00
Tworzenie aplikacji wieloplatformowych na przykładzie silnika gier z gatunku "match 3"
2022-08-22 13:43:33 +02:00
}
\newcommand{\tytulEng}{
2023-08-28 22:27:07 +02:00
Creating multiplatform applications with creation of match three game engine as an example
2022-08-22 13:43:33 +02:00
}
2022-08-17 19:22:26 +02:00
\begin{document}
\begin{titlepage}
2022-08-20 18:14:52 +02:00
\begin{minipage}{0.9\textwidth}%
2022-08-17 19:22:26 +02:00
\begin{center}
2023-03-05 18:14:33 +01:00
{\fontsize{24}{24}\adagio Warsaw University of Technology }
2022-08-18 20:09:21 +02:00
\end{center}
\begin{center}
2023-03-05 18:14:33 +01:00
{\fontsize{12}{12}\adagio \addfontfeature{LetterSpace=41.0} FACULTY OF ELECTRONICS AND INFORMATION TECHNOLOGY}
2022-08-18 20:09:21 +02:00
\end{center}
\end{minipage}
\begin{minipage}{0.1\textwidth}%
\includegraphics[width=25mm, height=25mm]{logo.jpg}%
\end{minipage}
2022-08-20 18:14:52 +02:00
\\[100pt]
2022-08-18 20:09:21 +02:00
\begin{center}
2023-03-05 18:14:33 +01:00
{\fontsize{43}{43}\adagioLight Bachelor's diploma thesis}
2022-08-20 18:14:52 +02:00
\\[24pt]
2023-03-05 18:14:33 +01:00
{\fontsize{12}{12}\helveticaLight in the field of study Computer Science}
2023-03-05 18:14:33 +01:00
{\fontsize{12}{12}\helveticaLight and specialization Computer Systems and Networks \\[50pt]}
2022-08-20 18:14:52 +02:00
2023-09-04 00:58:22 +02:00
{\fontsize{14}{14}\helvetica \tytulEng \\[50pt]}
2023-09-04 00:58:22 +02:00
{\fontsize{12}{12}\helveticaLight thesis number in the Faculty thesis register 103B-ISA-IN/307585/1202985 \\[12pt]}
2022-08-20 18:05:52 +02:00
2023-09-04 00:58:22 +02:00
{\fontsize{21}{21}\helvetica Krzysztof Stefan Rudnicki \\[12pt]}
2022-08-20 18:05:52 +02:00
2023-09-04 00:58:22 +02:00
{\fontsize{12}{12}\helveticaLight student record book number 307585 \\[24pt]}
2022-08-20 18:05:52 +02:00
2023-09-04 00:58:22 +02:00
{\fontsize{12}{12}\helveticaLight thesis supervisor }
2022-08-20 18:05:52 +02:00
{\fontsize{12}{12}\helvetica dr hab. inż. Tomasz Martyn \\[12pt]}
2022-08-20 18:05:52 +02:00
{\fontsize{12}{12}\helveticaLight konsultacje }
2022-08-20 18:05:52 +02:00
2023-09-04 00:58:22 +02:00
{\fontsize{12}{12}\helvetica Tomasz Martyn \\[40pt]}
2022-08-20 18:05:52 +02:00
2023-09-04 00:58:22 +02:00
{\fontsize{12}{12}\helveticaLight WARSAW 2023}
2022-08-20 18:05:52 +02:00
\end{center}
\afterpage{\null\newpage}
2022-08-17 19:22:26 +02:00
\end{titlepage}
2022-08-18 20:09:21 +02:00
2022-08-22 13:43:33 +02:00
2022-08-22 13:43:33 +02:00
\subsubsection{Streszczenie pracy}
{\fontsize{12}{12}
\tytul \\
Rynek systemów operacyjnych na PC jest podzielony na trzech głównych graczy, tworzy to zapotrzebowanie na silniki do gier, które są wszechstronne i działają tak samo, niezależnie od platformy. Niniejsza praca inżynierska przedstawia projekt i implementację nowego silnika do gier opracowanego z myślą o grach typu "dopasuj 3", gatunku który jest zarówno popularny, jak i stosunkowo łatwy do wdrożenia, mimo to nadal nie ma wyspecjalizowanego silnika open-source pod gry "dopasuj 3". Silnik został zbudowany w oparciu o bibliotekę graficzną OpenGL i system zarządzania oknami glfw, zapewniając zaawansowane możliwości graficzne przy jednoczesnym zachowaniu kompatybilności między platformami. Silnikowi przyświecają dwa cele: prostota obsługi dla deweloperów i solidna wydajność. Architektura skupia się na wykorzystaniu dobrych praktyk, nowoczesnego kodu C++ i sprawieniu że czytanie kodu silnika będzie łatwe i zrozumiałe dla developerów. W rezultacie twórcy gier mogą skupić się na tworzeniu gier typu "dopasuj 3" bez konieczności nauki programowania, umożliwiając artystom bez zaplecza technicznego, którzy chcą stworzyć wyjątkowe doświadczenie. Niniejsza praca opisuje motywacje, tło, dokumentację i przypadki użycia na trzech głównych platformach: Linux, Windows i MacOS. Silnik demonstruje użyteczność, możliwość dostosowania do różnych platform i zapewnia narzędzia niezbędne do tworzenia prostych gier typu "dopasuj 3". Niniejsza praca stara się wypełnić lukę w wyspecjalizowanych silnikach gier wideo open-source.
2023-08-28 22:27:07 +02:00
\{Multiplatformowość,
Gry,
Silniki do gier,
Gry "dopasuj 3"
OpenGL,
GLFW,
Grafika,
Design,
Prostota,
Linux,
Windows,
MacOS,
C++,
Dobre praktyki kodowania\}
2022-08-22 13:43:33 +02:00
}
\newpage
\subsubsection{Thesis abstract}
\fontsize{12}{12}{\tytulEng \\
2023-08-28 22:27:07 +02:00
With three major operating systems on PC, there exists a need for game engines that are versatile and platform-agnostic. This thesis introduces the design and implementation of a new game engine developed with match-three games in mind, which is a game genre that is both popular and relatively easy to implement, despite this there is still no specialized open-source match three game engine. The engine is built upon the foundations of the OpenGL graphics library and the glfw windowing system, ensuring advanced graphics capabilities while retaining platform compatibility. There are two goals for the engine: simplicity of use for developers, and robustness in performance. The architecture focuses on using good practices, modern C++ code and making the code developer friendly. As a result, game developers can focus on crafting match-three games without need to learn programming, empowering artists without technical background who want to create an unique experience. This work provides motivation, background, documentation and use-case across three major platforms: Linux, Windows, and MacOS. The engine demonstrates usability, adaptability to different platforms, and provides the tools necessary for creation of simple match-three games. This thesis is trying to fill the gap of specialized open-source video game engines.
\{Multiplatform,
Gaming,
Game engines,
Match-three games,
OpenGL,
GLFW,
Graphics,
Platform-agnostic,
Design,
Robustness,
Simplicity,
Linux,
Windows,
MacOS,
C++,
Good coding practices\}
2022-08-22 13:43:33 +02:00
}
2022-08-23 14:19:26 +02:00
\tableofcontents
\chapter{ Introduction }
2023-08-08 22:05:55 +02:00
\section{Background and Motivation}
Among us, computer science students, video games were—and still are—one of the driving forces pushing us into the field of IT. Video games allow people with technical background to express their artistic side and create visually stunning projects. In particular "Match Three" games, characterized by their intuitive mechanics and satisfying gameplay, have attracted millions of players around the globe. They offer statisfying experience of aligning three or more similar game pieces, often resulting in gratyfying chain reactions. This lead to success of titles like "Candy Crush Saga" and "Bejeweled", staple titles for both mobile and desktop market.
\begin{centering}
\begin{figure}[htp]
\includegraphics[scale=0.5]{allgates}
\caption{Minecraft redstone offers introduciton to logical gates \cite{redstoneGates}}
\end{figure}
\end{centering}
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
Match three games are from technological point of view relatively easy to make, despite that there is no dedicated open-source game engine designed just for them. This engineering thesis aims to fill this void, to give back to the world of game developers and open-source projects.
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
Another motivation is a chance to learn one of the most popular graphical API - OpenGL, It is a graphical API which proved useful again and again with video game engines, rendering engines or for desktop applications.
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
\section{Scope of the Thesis}
Game development is a broad spectrum, This section aims to define to what extent the game engine will be developed
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
\subsection{Game Engine Focus: Match Three Genre}
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
While game engines can be created for multiple game genres, this thesis focuses on Match Three genre. This decision comes from its ease of implementation, combined with relatively high popularity and applicability on all platforms. We will focus on core logic, rendering techniques, and controls focused on Match Three games.
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
\subsection{Multiplatform Development}
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
Another important part of the thesis is multiplatform game development. We will focus on three major desktop operating systems: Windows, Mac, and GNU/Linux. The challenges associated with creating an uniform gaming experience across these platforms, taking into consideration differences in architecture, functionality and graphics.
2023-08-08 22:05:55 +02:00
\subsection{Tool and Library Integration}
2023-08-12 01:21:08 +02:00
This thesis will make biggest use of OpenGL API together with libraries: GLFW, GLAD, FreeType, stb\_image, and ft2build. In order used for platform-independed creation of windows, context and handling inputs, loader for OpenGL, library for rendering text, library for loading images and library for building free type sources. Later in the thesis we will dvelfe deeper into those libraries
2023-08-08 22:05:55 +02:00
\subsection{Theoretical and Practical Exploration}
2023-08-12 01:21:08 +02:00
Main portion of this thesis is practical implementation, still we are going to explore theoretical concepts crucial for game engine development.
2023-08-08 22:05:55 +02:00
\subsection{Limitations}
2023-08-12 01:21:08 +02:00
Since the engine aims to be simple and robust, it will not contain every possible feature or optimization like in commercial-grade game engines. The primary intent is to create a solid structure for which further advancements can be made.
In conclusion, this thesis goal is to provide an understanding of multiplatform Match Three game engine development. By setting managable boundaries, it aims to dive deep into specific challenges, tools, and solutions, providing valuable insights for aspiring engine developers. Next sections will further describe the objectives, methodologies, and findings of this exploration into the world of game development.
2023-08-08 22:05:55 +02:00
\section{Objectives of the Thesis}
2023-08-12 01:21:08 +02:00
Clear objectives allow for accomplishments that can be measured. Therefore it is important to define goals that underpin this thesis. In this section, we describe the primary goals of this thesis.
2023-08-08 22:05:55 +02:00
\subsection{Design of a Cross-Platform Core Architecture}
2023-08-12 01:21:08 +02:00
The foremost objective is to design a core multiplatform engine architecture. This demands a good understanding of the operating systems differences, from their system calls to their graphics pipelines. The engine should be modular and scalable, in order to make sure that the core mechanics and logic can be implemented across Windows, Mac, and GNU/Linux platforms.
2023-08-08 22:05:55 +02:00
\subsection{Effective Integration of Libraries}
2023-08-12 01:21:08 +02:00
With numerous libraries at our disposal, an important goal is to combine them into the engine in a cohesive manner. We will make use of GLFW for window management, GLAD for OpenGL function pointers, FreeType and ft2build for text rendering, and stb\_image for image handling. In addition to integrating them into an engine, these libraries must operate in such a way that they complement each other to improve the engine's overall performance and capability.
2023-08-08 22:05:55 +02:00
\subsection{Development of Core Match Three Mechanics}
2023-08-12 01:21:08 +02:00
Architecture and libraries used form the skeleton, the Match Three mechanics are the most important part of the engine. The aim is to create algorithms and techniques to take care of typical Match Three functionalities from matching detection to gravity-induced piece drops and chain reactions.
2023-08-08 22:05:55 +02:00
\subsection{Providing a Blueprint for Future Development}
2023-08-12 01:21:08 +02:00
While the first objective is the engine's development, a broader goal is to expand upon created engine. By addressing challenges and sharing solutions, this thesis hopes to offer an example for engine developers. Whether they wish to enhance this engine or create new game engines. This thesis tries to improve their understanding of the topic
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
\section{Match Three Games and Engines}
The world of video games is vast and varied, Offering anything from massive multiplayer role playing games to small mobile puzzles. Match Three games offer players a blend of strategy, pattern recognition, and instant gratification. To better understand the significance of our task in creating a multiplatform Match Three game engine, it's important to trace how the genre evolved, understanding its roots, its development, and its appeal.
2023-08-08 22:05:55 +02:00
\subsection{Origins and Early Forerunners}
2023-08-12 01:21:08 +02:00
Match Three games owe their existence to the broader genre of tile-matching video games. The earliest entrants in this category were games like "Tetris" in the 1980s, where players manipulated falling blocks to create complete lines. "Tetris" kickstarted games focused on spatial reasoning and pattern recognition.
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
Expandin on this formula, 1980s and 1990s saw games like "Columns" and "Dr. Mario". These games introduced the mechanic of matching three or more identical items, but they were still using the falling-block paradigm. The true prototype of modern Match Three mechanics can be credited to "Shariki," a 1994 game where players swapped adjacent pieces to form chains of three or more identical items.
2023-08-08 22:05:55 +02:00
\subsection{Mainstream Adoption and Innovations}
2023-08-12 01:21:08 +02:00
In 2001 game titled "Bejeweled" came out. Simplifying and refining the mechanics of "Shariki", "Bejeweled" was the first mainstream success of Match Three genre. It provided intuitive gameplay, visually appealing graphics and set the benchmark for games that followed.
2023-08-08 22:05:55 +02:00
\begin{figure}[htp]
\centering
\includegraphics[scale=0.50]{images/bejeweld.jpg}
\caption{Bejeweled gameplay \cite{bejeweledGameplay} }
\label{}
\end{figure}
2023-08-12 01:21:08 +02:00
The success of "Bejeweled" lead to several innovation. Developers experimented with various twists on the core mechanics. Games introduced power-ups, barriers, objectives, and narrative elements. "Candy Crush Saga", released in 2012, integrated a level-based progression system, increasing the genre's complexity and depth.
2023-08-08 22:05:55 +02:00
\subsection{Technological Influences and Platform Diversification}
2023-08-12 01:21:08 +02:00
The evolution of Match Three games is interlocked with technological improvements in the gaming industry. Initially developed to PCs and consoles, the rise of mobile devices opened a new opportunities for the genre. The touch interface of smartphones and tablets proved to be an ideal medium for the drag-and-swap mechanics of Match Three games.
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
At the same time, browser-based games, using technologies like Flash, allowed players to engage with Match Three puzzles without heavy downloads or installations. As technology progressed, the need for engines that worked on multiple platforms mobile, browser, consoles and desktop became apparent.
2023-08-08 22:05:55 +02:00
\subsection{Enduring Appeal and Contemporary Significance}
2023-08-12 01:21:08 +02:00
Despite multiple competing genres, Match Three games remain popular. Their success can be attributed to their 'easy to learn, hard to master' trait. The games offer immediate rewards the satisfaction of creating a match, beauty of pieces disappearing, and the strategic depth of planning several moves ahead. Additionally, the modular nature of their design allows for easy adaptation, whether it's incorporating a narrative, integrating with popular cultures, or tailoring to specific demographics.
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
In conclusion, the history of Match Three games is a proof to their adaptability and universal charm. They established themselves as one of the most recognizable genres in mobile and desktop gaming, they continue to gather players. This perspective marks significance of engines tailored to Match Three games specificaly.
2023-08-08 22:05:55 +02:00
\section{Overview of Multiplatform Game Development}
2023-08-12 01:21:08 +02:00
Game developres try to reach wider audiences by ensuring that their creations are accessible across a variety of operating systems. Multiplatform game development aims to deliver the same experience to different user bases. This section describes challenges and methodologies connected with multiplatform game development.
2023-08-08 22:05:55 +02:00
2023-08-09 19:34:51 +02:00
\subsection{The Need for Multiplatform Development}
2023-08-08 22:05:55 +02:00
There are three main operating systems, Windows, Mac, and GNU/Linux which together are responsible for over 90\% of desktop market share \cite{marketShareChart}, the potential to reach a bigger audience increases when a game is made available across all of these platforms.
\begin{figure}[H]
\centering
\includegraphics[scale=0.50]{chart.png}
\caption{Desktop OS market share worldwide \cite{marketShareChart}}
\label{}
\end{figure}
2023-08-08 22:05:55 +02:00
2023-08-09 19:34:51 +02:00
\subsection{Challenges in Multiplatform Development}
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
Idea of developing once and deploying everywhere comes with its set of challenges:
\begin{itemize}
\item Hardware Disparity: Different platforms might have varying hardware specifications, which can influence the game's performance.
\item OS Specific Limitations: Each operating system operates under its own rules, from system calls to user interface.
\item Toolchain Variability: Development tools and libraries might have platform-specific versions or may not be available for all platforms.
\end{itemize}
2023-08-08 22:05:55 +02:00
2023-08-09 19:34:51 +02:00
\subsection{Tools and Libraries for Cross-Platform Development}
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
In order to face multiplatform development challenges, we use a set of tools and libraries. Libraries like OpenGL offer an unified graphics rendering solution, while GLFW enforces consistent window management and input handling. stb\_image, and ft2build are other libraries that offer consistent behavior across platforms for handling images and font rendering.
2023-08-08 22:05:55 +02:00
2023-08-09 19:34:51 +02:00
\subsection{Strategies for Effective Multiplatform Development}
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
\begin{itemize}
\item Modular Design: By dividing the game engine into distinct modules, developers can isolate platform-specific code, ensuring that core logic remains unchanged by platform dependencies.
\item Continuous Integration and Testing: Automated testing across platforms can identify inconsistencies, ensuring that the game offers an uniform experience.
\item Community Engagement: Using the community that uses the game engine across multiple platforms offers developers insights into existing bugs and potential optimizations
\end{itemize}
2023-08-08 22:05:55 +02:00
2023-08-09 19:34:51 +02:00
\subsection{Future Trajectory of Multiplatform Development}
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
With the cloud gaming on the rise, ressurection of web-based games, and increasingly powerful mobile devices, multiplatform development's scope is constantly expanding. There will be newer platforms and more varied devices to handle. The goal will remain the same: ensuring that games offer a consistent, engaging, and seamless experience, independent of the platform.
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
Multiplatform game development requires technological knowledge and good design. By understanding its challenges and methodologies, developers are better equipped to face-on multiple platforms of modern gaming. This foundation will become crucial later into the development of our multiplatform Match Three game engine.
2023-08-08 22:05:55 +02:00
\section{Existing Game Engines and Their Limitations}
2023-08-12 01:21:08 +02:00
The gaming industry has seen rise of various game engines, each offering a unique set of tools and functionalities for different needs. While these engines have facilitated the creation of iconic games, they also come with certain limitations, especially concerning specific genres or platforms. This section will describe prominent game engines and analyze their shortcomings, providing a reference for our multiplatform Match Three game engine.
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
\subsection{Unity Game Engine}
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
Unity is one of the most popular game engines available today. It's known for its versatility, supporting a wide range of platforms, from PCs to consoles to mobile devices.
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
\begin{itemize}
\item Strengths: Plenty of community resources, a vast asset store, and an intuitive interface make Unity a popular choice among both beginners and professional developers.
\item Limitations: Unity's all-purpose nature might introduce unnecessary load for simpler games, like Match Three titles, potentially impacting performance.
\end{itemize}
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
\subsection{Unreal Engine}
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
Epic Games' Unreal Engine stands out for its impressive graphical capabilities, often employed in AAA game titles.
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
Strengths:
\begin{itemize}
\item Blueprints: Blueprint visual scripting system allows for easier game development especialy for non-technical users
\item Graphics: Unreal Engine offers top-tier rendering capabilities, which makes it ideal for creating visually stunning games.
\end{itemize}
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
Limitations:
\begin{itemize}
\item Learning Curve: Its advanced features can be overwhelming for beginners.
\item Simpler Genres: As with Unity, for a simple game like Match Three game, the engine might be too sophisticated, leading to longer load times and increased resource consumption compared to custom solution.
\end{itemize}
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
\subsection{Godot}
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
Godot is the biggest multipurpose game engine that is also free and open-source.
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
Strengths:
\begin{itemize}
\item No licensing: Godot is free to use
\item Open: Godot source code can be accessed and modified by anyone
\item Community: As with many open source projects community offers huge support for potential developers
\end{itemize}
2023-08-08 22:05:55 +02:00
Limitations:
2023-08-12 01:21:08 +02:00
\begin{itemize}
\item Limited professional presence: While unity and unreal dominate professional market, Godot is a less popular alternative
\item Scalability: Godot game engine is not famous for building big game projects
\end{itemize}
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
\subsection{RPG Maker and Ren'Py}
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
RPG Maker and Ren'Py are examples of game engines focusing on one genre of games.
RPG Maker focues on top-down rpg games, while ren'py aims to ease the process of making visual novel games. Both of those engines were used with commercial and critical success, with creation of games like "To The Moon" and "Doki Doki Literature Club". Their limitations are both their strenght and weaknesses, allowing to speedup development process but blocking the developer for leaving the area of interest for those engines.
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
\subsection{Limitations}
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
While each game engine has its unique strengths and weaknesses, some common limitations come apparent when considering the development of a specialized game like a Match Three title, those engines either do not allow for match three development (RPG Maker or Ren'Py) or deliver match three titles with too much technological bloat (Unity/Unreal/Godot)
While existing game engines offer a lot of tools and capabilities, there exists a space for specialized engines made for specific genres. Recognizing the limitations of mainstream engines explains development of our multiplatform Match Three game engine, which tries to fix these gaps while providing an easy development.
2023-08-08 22:05:55 +02:00
\chapter{Basics of Game Engine Design}
2023-08-09 19:44:00 +02:00
\section{Core Components of Game Engines}
2023-08-08 22:05:55 +02:00
Game engines serve as the backbone for game development, providing a selection of tools and features that simplify the process of creating a game from scratch. At the heart of every game engine lie its core components, which define its capabilities, flexibility, and performance. This section explains those elements that we are going to implement in our engine.
\begin{figure}[htp]
\centering
\includegraphics[scale=0.50]{images/gameEngineComponents.drawio.pdf}
\caption{Components used in our game engine}
\label{}
\end{figure}
2023-08-08 22:05:55 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Rendering Engine}
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
The rendering engine is responsible for all visual aspects within a game. It takes the game's data including textures and shaders and converts them into pixels on the screen.
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
\begin{itemize}
\item Role: Ensures that all visual elements, from static backgrounds to animations, are displayed with clarity, smoothness, and consistency.
\item Key Features: Supports various rendering techniques such as ray tracing, rasterization, and shadow mapping to enhance visual quality.
\end{itemize}
2023-08-08 22:05:55 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Input Handling}
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
Games are interactive by nature, and this interaction is delivered by the engine's input handling system.
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
\begin{itemize}
\item Role: Processes user inputs from various sources, like a keyboard, mouse, gamepad, or touch screen. Translates these inputs into in-game actions or commands.
\item Key Features: Detects multiple simultaneous key presses, supports touch gestures, and allows for input remapping.
\end{itemize}
2023-08-08 22:05:55 +02:00
2023-08-12 01:21:08 +02:00
\subsection{Transformations}
In order for object in game to move, game engine must handle its position on screen, this is a job of transformation system
\begin{itemize}
\item Role: Move objects based on user input, delete, add and modify existing coordinates
\item Key Features: Matrices and vectors calculation
\end{itemize}
2023-08-08 22:05:55 +02:00
2023-08-13 22:25:22 +02:00
Each component of game engine plays a different role, in combination they ensure that the game runs smoothly, offers an enjoyable experience, and responds to user interactions. These core parts form the foundation upon which our multiplatform Match Three game engine will be built and updated.
2023-08-08 22:05:55 +02:00
\section{The Role of OpenGL in Game Development}
2023-08-13 22:25:22 +02:00
Game engines need graphics libraries, those libraries provide the necessary tools to bring visual elements to the screen. Among these libraries, OpenGL (Open Graphics Library) has established itself as one of the most popular choices for graphics rendering. This section explores the role of OpenGL in game development, focusing on library functionalities and how they can be used.
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Introduction to OpenGL}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
OpenGL is a cross-language, cross-platform application programming interface (API) designed for rendering vector graphics. Initially developed by Silicon Graphics in the 1990s, it is now taken care by the non-profit technology organization, the Khronos Group. It is platform-agnostic which makes experience consistent across different platforms.
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Rendering Mechanism}
2023-08-09 19:34:51 +02:00
At its core, OpenGL is about rendering. It provides developers with the tools needed to draw complex 3D and 2D graphics.
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Role: OpenGL communicates directly with a system's GPU (Graphics Processing Unit) and translates the game's data into visual elements displayed on screen.
\item Key Features: Supports techniques such as texture mapping, anti-aliasing, and shader programming.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Shader Programming}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
Shaders allow for creating stunning visuals programatticaly, and OpenGL provides extensive support for shader programming.
\begin{itemize}
\item Role: Shaders allow developers to program the GPU directly, which gives massive control over how individual pixels or vertices are processed.
\item Key Features: OpenGL's GLSL (OpenGL Shading Language) lets developers create custom shaders, enabling dynamic lighting, shadows, and other advanced visual effects.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Extensibility}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
One of OpenGL's strengths lies in its extensible design, allowing to include advancements in hardware and software.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Role: As hardware evolves, new extensions can be added to OpenGL without changing the entire API. This makes OpenGL relevant, independent of technological improvements.
\item Key Features: These extensions can be used to utilize latest graphics hardware capabilities, making games look and perform their best.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Cross-Platform Development}
2023-08-09 19:34:51 +02:00
\begin{figure}[htp]
\centering
\includegraphics[scale=0.70]{images/openglWikipedia.png}
\caption{Connection between Linux and OpenGL-based games \cite{openGLWikipedia}}
\label{}
\end{figure}
2023-08-13 22:25:22 +02:00
Gamers are spread across Windows, Mac, GNU/Linux, and other platforms, OpenGL's platform-independent allows for creating games for all platforms.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Role: OpenGL ensures that games look consistent across different platforms, easing the process of multiplatform game development.
\item Key Features: It abstracts underlying platform-specific differences, allowing developers to focus on creating the game without need to adapt to platform-specific constraints.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Integration with Other Libraries and Tools}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
OpenGL is compatible with many libraries and development tools.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Role: Enhances OpenGL capabilities by working with libraries like GLFW for window management, GLAD for handling extensions, and more.
\item Key Features: Provides an unified development environment, where various tools and libraries work together under OpenGL, again simplifying the process of game development.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
In summary, OpenGL combines software and hardware, enabling developers to create experiences with enough precision and speed. Understanding impact of OpenGL will make explaining our own game engine inner workings much easier.
2023-08-08 22:05:55 +02:00
\section{Multiplatform Considerations}
2023-08-13 22:25:22 +02:00
In order to reach as wide an audience as possible, developers try to develop a game for multiple platforms mostly Windows, Mac, and GNU/Linux. Creating multiple platforms game engine is filled with challenges and considerations. This section explores difficulties of multiplatform game development, describing what developers must be conscious of when targeting multiple operating systems.
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Platform-Specific Hardware and Software}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
Every platform has its unique hardware and software configurations, which influence a game's performance and appearance.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Role: Ensuring the game runs smoothly across different hardware setups, from different GPU architectures to memory configurations.
\item Key Features: Developers need tools to abstract these hardware-software differences, allowing the game engine to react dynamically based on the platform.
\end{itemize}
2023-08-08 22:05:55 +02:00
2023-08-09 19:44:00 +02:00
\subsection{User Input Variations}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
Different platforms often have different input methods, from touchscreens to gamepads to keyboard-mouse setups.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Role: Making sure that the game responds accurately to various input methods.
\item Key Features: Input handling system that can detect and adapt to different input devices.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Graphical Rendering Nuances}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
There are platform-specific nuances in how graphics are presented.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Role: Making engine work under different display resolutions, aspect ratios, and screen sizes.
\item Key Features: Dynamic resolution scaling and responsive UI layouts to ensure the game looks similar across platforms.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{File System and Data Management}
2023-08-09 19:34:51 +02:00
\begin{figure}[htp]
\centering
\includegraphics[scale=0.5]{images/windowsLinuxSlash.jpg}
\caption{Separating folders with backslash and forward slash is one of many differneces between Windows and Linux systems \cite{windowsLinuxSlash} }
\label{}
\end{figure}
2023-08-13 22:25:22 +02:00
File systems varies between Windows, Mac, and GNU/Linux, influencing how game data is stored, retrieved, and updated.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Role: Managing game saves, configurations, and other data across platforms.
\item Key Features: Data management system that behaves the same for platform-specific directory structures and access permissions.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-08 22:05:55 +02:00
\chapter{Toolchain and Libraries Overview}
\section{Introduction to GLFW}
2023-08-13 22:25:22 +02:00
In the arena of game development, libraries related to window management and input handling play crucial role. GLFW offers an interface for developers to create interactive applications. This section offers an introduction to GLFW, explaining into its origins, functionalities, and relevance in game development.
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Historical Context}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
GLFW, which stands for Graphics Library Framework, was a response to the need for an open-source library that simplifies the challenges of window management and input handling, especially for OpenGL applications. Initially developed to provide a more straightforward alternative to existing solutions, GLFW has grown in popularity due to its simplicity, efficiency, and cross-platform capabilities.
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{GLFW's Core Competencies}
2023-08-09 19:34:51 +02:00
GLFW serves as a bridge betFween the game's logic and the operating system, handling tasks that are crucial for interactive applications.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Window Management: GLFW's manages window creation, querying, and manipulation. It allows developers to focus on their game logic rather than handling platform-specific windowing.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Input Handling: GLFW provides a system to capture and process user inputs. It forms for keyboard strokes, mouse movements, or even joystick inputs, GLFW makes sure that user interactions are detected and communicated to the application efficiently.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Context Management: Especially relevant for OpenGL applications, GLFW helps create contexts, manage profiles, and handle extensions, for easier development experience.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Integration with OpenGL}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
While GLFW is platform-agnostic and can support multiple rendering systems, its mostly used with OpenGL.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Role: It functions as the companion to OpenGL, offering an environment where OpenGL can work more efficiently by addressing system-specific challenges that are outside OpenGL's specification.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Key Features: Context creation for OpenGL.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Cross-Platform Capabilities}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
GLFW's is able to work across Windows, Mac, and GNU/Linux.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Role: GLFW is a consistent interface for developers, regardless of the target platform. This ensures uniformity in window creation, input handling, and other functionalities across different operating systems.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Key Features: An architecture that ensures platform-specific norms while offering a consistent API for developers.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Community and Support}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
Being open-source, GLFW benefits from a huge community that continually refines, optimizes, and extends the library.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Role: Ensures GLFW remains up-to-date, addreses challenges and evolves with the needs of developers.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Key Features: Tutorials and forums, assisting both new and trained developers in using GLFW
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
GLFW proves useful to many game developers, especially those using OpenGL. Its ability to handle window management, input processing, and other tasks ensures that developers can focus on crafting game mechanics and narratives.
2023-08-08 22:05:55 +02:00
\section{Role of GLAD in OpenGL Loading}
2023-08-13 22:25:22 +02:00
GLAD is a robust and flexible loader-generator designed for OpenGL. It ensures the dynamic loading of OpenGL functions based on the specific version and extensions a developer chooses. GLAD was developed to automate handling OpenGL extensions.
2023-08-09 19:34:51 +02:00
2023-08-28 22:27:07 +02:00
\begin{figure}[htp]
\centering
\includegraphics[scale=0.50]{images/gladSite.png}
\caption{Glad website allowing for different configurations of OpenGL \cite{gladSite}}
\label{}
\end{figure}
2023-08-09 19:44:00 +02:00
\subsection{The Need for Loading OpenGL Extensions}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
OpenGL's is an extensible API. With changes in hardware, new functionalities are introduced through extensions without changing the core API. This creates new challenges on their own.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Role: Extensions allow developers to use the latest graphics capabilities, which are not always part of the core OpenGL library.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Key Features: Handling these extensions requires dynamic loading at runtime, so that the game can access and utilize these advanced functionalities.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{GLAD's Functionality in Extension Loading}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
GLAD simplifies working with OpenGL extensions through its automated approach.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Role: Provided with the OpenGL version and extensions, GLAD generates C/C++ code to load these extensions dynamically at runtime. This removes the need to manually address each extension, reducing errors and inefficiencies.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Key Features: GLAD supports multiple languages and specifications. It is also up-to-date with the latest OpenGL specifications, making it compatible with newest graphics capabilities.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Integration with GLFW and OpenGL}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
GLAD interacts with both OpenGL and GLFW, creating an unified development environment. Once GLFW creates the OpenGL context, GLAD is utilized to load the necessary functions. This collaboration ensures that GLFW handles the platform-specific instructions, while GLAD focuses on OpenGL's extensibility.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\section{Handling text and images with FreeType, ft2build and stb\_image}
2023-08-09 19:44:00 +02:00
\subsection{Introduction to FreeType}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
FreeType is an open-source software font engine, It offers ability to render text onto bitmaps and other font-related functionalities.
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Key Capabilities of FreeType}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Font Parsing and Loading: Before rendering, fonts need to be parsed and loaded. FreeType supports many font formats, ensuring broad compatibility.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Glyph Rendering: FreeType is good at converting individual glyphs into bitmaps, handling anti-aliasing and hinting to create clear, sharp text rendering.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Font Metrics and Kerning: Rendering text isn't just about individual glyphs. The spacing between them (kerning) and their metrics are crucial for readability and aesthetics, and FreeType is able to deliver this functionality.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-28 22:27:07 +02:00
\begin{figure}[htp]
\centering
\includegraphics[scale=0.50]{images/freetypeInspect.png}
\caption{ftinspect showcasing capabilities of FreeType library \cite{freeTypeSite}}
\label{}
\end{figure}
2023-08-09 19:44:00 +02:00
\subsection{Understanding ft2build}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
ft2build serves as an essential interface, allowing for the inclusion and deployment of FreeType headers in development projects. ft2build was created to ease the integration process of FreeType 2.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\subsection{Introduction to stb\_image}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
While FreeType takes charge of fonts, stb\_image is a solution for image loading and decoding, popular for its simplicity and compactness. It is part of the stb collection of single-file libraries.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\subsection{Key Capabilities of stb\_image}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Image Loading: It is capable of handling popular formats like JPEG, PNG, BMP, and more, this way developers can incorporate multiple types of graphical assets into their game
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Image Decoding: stb\_image decodes images into a format that can be directly used with OpenGL or other rendering systems.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Simplicity and Efficiency: stb\_image has minimalistic design. With just a single header file, developers can use its capabilities without employing complex dependencies or configurations.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
Specialized tools like FreeType and stb\_image elecate the visual experience of games with text rendering and images inclusion into game engine
2023-08-09 19:34:51 +02:00
\chapter{Design and Architecture of the Match Three Engine}
2023-08-09 19:34:51 +02:00
\section{Game Loop and State Management}
2023-08-13 22:25:22 +02:00
In the heart of every video game lies the game loop. This cycle dictates the game's pacing, ensuring that events, updates, and rendering processes all appear in a correct order. Game loop functions together with state management, which ensures the game behaves consistently in response to player actions and internal events. This section will focus on both the game loop and state management and how they influence our multiplatform Match Three game engine.
2023-08-09 19:34:51 +02:00
2023-08-28 22:27:07 +02:00
\begin{figure}[htp]
\centering
\includegraphics[scale=0.50]{images/gameLoop}
\caption{Game loop flowchart representation}
\label{}
\end{figure}
2023-08-09 19:44:00 +02:00
\subsection{The Anatomy of a Game Loop}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
The game loop is a repetitive process that continues for the lifespan of the game session. It tries to:
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Poll Input: Gather and process player inputs.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Update Game State: Based on the inputs and game rules, modify game entities and overall state.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Render: Draw the current state of the game onto the screen.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Sleep (Optional): Introduce a short delay, if necessary, to control the loop's frequency and match the target framerate.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Importance of State Management}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
As games grow complex, they may contain numerous states, including:
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Menu Screens: Where players can start, configure settings, or view credits.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Gameplay Modes: Different modes or levels of gameplay, each with its unique rules and environments.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Pause/Resume States: Allowing players to stop the game and later resume it.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Endgame Scenarios: Winning, losing, or drawing conditions.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
State management ensures the game recognizes and responds appropriately to these states.
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Interlinking Game Loop and State Management}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
Game Loop and State Management must work together:
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item State-Driven Rendering: What the game displays during each loop iteration depends on its current state. For instance, the game may render a main menu, gameplay screen, or a 'game over' message based on its active state.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item State Transitions: Player inputs or internal events can trigger state changes. The game loop continually checks for such triggers and initiates the necessary transitions.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Challenges and Considerations}
2023-08-13 22:25:22 +02:00
Managing a game loop and states is filled with challenges:
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Performance: The game loop must run efficiently to maintain smooth gameplay, especially crucial for real-time games where fast decisions matter.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item State Persistence: Some states may require data persistence, like saving a game, which requires storing and retriving game data.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Synchronization: Ensuring that state transitions and game loop iterations are in sync is essential to avoid unexpected behaviors.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Role in the Multiplatform Match Three Game Engine}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
For our game engine, the game loop and state management fullfill following functions:
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Cross-Platform Consistency: The game's behavior, pacing, and responses should be consistent across Windows, Mac, and GNU/Linux platforms.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Match-Three Logic: The game engine will manage states specific to match-three mechanics, like checking for matches, handling cascades, and introducing new game pieces.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
In summary, game loop maintains the rhythm of the game, while state management ensures logic in the game's behavior.
2023-08-09 19:34:51 +02:00
\section{Asset Management and Rendering}
2023-08-13 22:25:22 +02:00
Game development consists of art and logic, where visual assets behave based on game code. Ensuring these assets are well-organized, efficiently loaded, and rendered is vital for any gaming experience. This section explores asset management and rendering.
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{What are Game Assets?}
2023-08-09 19:34:51 +02:00
2023-08-28 22:27:07 +02:00
\begin{figure}[htp]
\centering
\includegraphics[scale=1.00]{images/gemMatchThree.png}
\caption{Exemplary assets for match three tiles \cite{assetsMatchThree} }
\label{}
\end{figure}
2023-08-09 19:34:51 +02:00
In the context of game development, assets refer to:
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Graphics: These include textures, sprites, animations, and UI elements.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Data: Configurations, level designs, scripts, and other data structures that define gameplay mechanics.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Rendering: Bringing Assets to Life}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
Once assets are organized and loaded, rendering puts them onto the screen:
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Displaying Graphics: Textures and sprites are mapped onto game entities.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Shaders \& Effects: Advanced graphical effects, such as lighting, shadows, and particle effects, are layered on to assets to elevate visuals.
\end{itemize}
2023-08-09 19:44:00 +02:00
\subsection{Cross-Platform Considerations in Asset Management}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
Given our engine's multiplatform nature, certain challenges arise:
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Format Compatibility: Not all asset formats are supported uniformly across platforms. Ensuring assets are in universally compatible formats and using libraries like stb\_image that unify asset formats among different operating systems is crucial.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Optimization: Different platforms may have varying memory capacities and processing power. Assets might need to be optimized, resized, or compressed to respond to those limitations.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Role in the Multiplatform Match Three Game Engine}
2023-08-13 22:25:22 +02:00
Our game engines being multiplatform complicates assets rendering:
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Uniformity Across Platforms: Visual experience should remain consistent across Windows, Mac, and GNU/Linux.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Match-Three Specifics: Given the genre, the engine must effectively manage assets like gems, power-ups, grid structures, and cascade animations and then render them in a visually pleasing way.
\end{itemize}
2023-08-09 19:34:51 +02:00
\section{Event Handling and User Input}
2023-08-13 22:25:22 +02:00
Main trait of video game is interactivity. Game must have the ability to capture, interpret, and respond to user input, whether it is the click of a mouse, the press of a keyboard key, or the swipe on a touchscreen. Managing those interactions is called event handling. In this section we will describe event handling and user input, and their role in our game engine.
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Understanding User Input and Events}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
Every action by the user generates an event. This event contains specific data, such as:
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Type of Input: Whether it's a key press, mouse movement, click, or touch.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Coordinates: In case of mouse or touch, the precise location of the interaction.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Duration: The length of time an input is maintained, like a long press.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Event Polling vs. Event Callbacks}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
There are two primary ways to handle these events:
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Event Polling: The game loop consistently checks (or "polls") for user inputs at fixed intervals, processing any detected events.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Event Callbacks: The system is set up to notify (or "call back") the game engine immediately when an event occurs.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Role in the Multiplatform Match Three Game Engine}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
Our game engine should provide following features connected with user input:
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Intuitive Matching: Selecting and swaping game pieces should be easy and convenient, with the engine accurately capturing and responding to these interactions.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Feedback Loop: Upon receiving an input, the game engine must also provide immediate feedback, such as highlighting a selected piece, initiating a combo move or playing animation.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
Event handling and user input are ways for players to communicate with the game. It is crucial to make them intuitive and smooth.
2023-08-09 19:34:51 +02:00
\chapter{Cross-Platform Development Challenges and Solutions}
\section{Operating System Variabilities}
2023-08-13 22:25:22 +02:00
Operating systems (OS) are a middle ground between human interaction and hardware functionality. With Windows, Mac, and GNU/Linux operating systems as the most popular desktop environments, a multiplatform game engine must work under each of them. This section describes differences between these operating systems and how our engine can handle them.
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Core Architectural Differences}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
Some of the distinctive features of OS architecture are:
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Kernel Design: Windows uses a hybrid kernel, while Linux is a monolithic kernel, MacOS is based around Unix XNU kernel.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item File Systems: Windows primarily offers NTFS, MacOS stores files using APFS, and GNU/Linux has multiple options like ext4, Btrfs, and many, many more.
2023-08-28 22:27:07 +02:00
\begin{figure}[htp]
\centering
\includegraphics[scale=0.75]{images/fileSystems}
\caption{Windows file system consists of drives, which contain folders which contain subfolders and files, in Linux everything is a file}
\label{}
\end{figure}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item APIs \& System Calls: Each OS provides developers with its own set of APIs and system calls, changing how software communicates with the system.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Graphical User Interface (GUI) Divergence}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
Differences in GUI of each OS:
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Window Management: Windows uses a floating window system, MacOS has its unique mission control, and Linux distributions can use anything from floating, fixed to no graphical interface at all.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Input Methodologies: Multi-touch gestures work different under MacOS than under Windows. Linux, depending on its distribution and desktop environment, may have a the same or different approach altogether.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\subsection{Driver Support}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
Certain hardware, sometimes crucial to game engine like graphics card or keyboad, might be optimized for one OS over the others, or might not be supported entirely.
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Middleware \& Third-party Libraries}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
The accessibility, performance, and support of middleware and third-party libraries can differ, while some libraries are universally compatible, others might be OS-specific, another problem might be with the update cycle, the frequency of libraries updates can vary, impacting game engine compatibility and performance.
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Implications for the Multiplatform Match Three Game Engine}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
Operating system variances impact directly on our game engine:
\begin{itemize}
\item Performance Optimizations: Depending on the OS, certain code paths might be more efficient. The engine must be adaptable.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Consistent Gameplay Experience: Players on all platforms should have a similar gameplay experience.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Updates \& Maintenance: As OSs changes, the game engine must be ready for regular updates to ensure compatibility.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
Multitude of operating systems poses challenges for game engine developers. By understanding these differences, developers can make sure that the game functions across different platforms.
2023-08-09 19:34:51 +02:00
\section{Addressing Hardware and Driver Differences}
2023-08-13 22:25:22 +02:00
Hardware and its associated drivers act as the final execution devices for any game engine. When creating a game engine, developer must keep in mind a variety of hardware configurations and their driver implementations. This section focuses on understanding these differences and how we can challenge them.
2023-08-09 19:44:00 +02:00
\subsection{A Landscape of Diverse Hardware}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
Across all platforms, multiple hardware components exists:
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Processors: Mostly Intels and AMD's x86 architecture (32 and 64 bits), together with ever more popular ARM processors
\item Graphics Cards: NVIDIA, AMD, and Intel dominate the market, each with their architectures and feature sets.
\item Memory Configurations: RAM specifications, speeds, and type of storage devices (SSDs and HDDs) can influence performance.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Input Devices: Various keyboards, mice, touchpads, touchscreens, and game controllers, each have unique specs and capabilities.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Drivers: The Link to Hardware}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
Drivers allow an operating system to interact with hardware:
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Proprietary vs. Open-Source: While NVIDIA provides proprietary drivers, AMD and Intel often offer open-source alternatives for Linux. There are also community driven, universal, open-source drivers.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Update Frequencies: Hardware vendors release driver updates at different intervals, each update possibly affects game performance and compatibility.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Feature Support: New hardware features may be enabled in driver updates.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Challenges Posed to Game Engines}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\begin{itemize}
\item Optimization Issues: What's optimized for one graphics card might not be for another.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Feature Inconsistencies: Some hardware may support specific graphical features, while others might not.
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\item Input Latency Variations: Different input devices and their drivers can lead to varied response times and incosistent responses.
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
\subsection{Abstraction Layers in Match Three Game Engine}
2023-08-09 19:34:51 +02:00
2023-08-13 22:25:22 +02:00
To address these challenges, our engine adopts abstraction layers: by utilizing existing libraries and solutions (OpenGL, GLAD and GLFW), our game engine is ready for easier adjustments for specific hardware.
2023-08-09 19:34:51 +02:00
\chapter{Implementation Details}
2023-09-06 18:16:40 +02:00
\section{Requirements}
\subsection{Functional Requirements (FR)}
\begin{enumerate}
\item \textbf{Game Initialization and Setup (FR1)}:
\begin{itemize}
\item The engine shall initialize a game board with a predetermined square size (e.g., 8x8).
\item The game board shall be populated randomly with different colored pieces.
\item The initial game board should not have any matches (three or more of the same colored pieces in a row or column).
\end{itemize}
\item \textbf{User Interactivity (FR2)}:
\begin{itemize}
\item Players shall be able to select a piece.
\item Players shall be able to swap the selected piece with an adjacent piece (up, down, left, or right) to form a match.
\end{itemize}
\item \textbf{Matching Logic (FR3)}:
\begin{itemize}
\item When three or more pieces of the same color align vertically or horizontally, they shall be recognized as a match.
\item Matched pieces shall be removed from the board.
\end{itemize}
\item \textbf{Board Update (FR4)}:
\begin{itemize}
\item After pieces are matched and removed, new pieces shall drop down to fill the vacant spaces.
\item The board shall continuously check for matches after each update.
\end{itemize}
\item \textbf{Scoring System (FR5)}:
\begin{itemize}
\item Players shall earn points for each match made.
\item Bonus points shall be awarded for matches greater than three pieces.
\end{itemize}
\item \textbf{Game Over Logic (FR6)}:
\begin{itemize}
\item The game shall end when no moves are left.
\end{itemize}
\item \textbf{Pause and Resume (FR7)}:
\begin{itemize}
\item Players shall be able to pause and resume the game.
\end{itemize}
\item \textbf{Game Difficulty Levels (FR8)}:
\begin{itemize}
\item Make the game more difficult or easy by giving player more or less turns to play
\end{itemize}
\end{enumerate}
\subsection{Non-functional Requirements (NFR)}
\begin{enumerate}
\item \textbf{Performance (NFR1)}:
\begin{itemize}
\item The game engine shall ensure smooth animations without any lag.
\item Match detection should occur within milliseconds to ensure real-time response.
\end{itemize}
\item \textbf{Usability (NFR2)}:
\begin{itemize}
\item The game interface shall be intuitive.
\end{itemize}
\item \textbf{Portability (NFR3)}:
\begin{itemize}
\item The game engine should be platform-independent, allowing for easy deployment across different operating systems using C++ and OpenGL.
\end{itemize}
\item \textbf{Maintainability (NFR4)}:
\begin{itemize}
\item The code shall be well-structured, modular, and commented, allowing for easy updates and maintenance.
\item Utilize design patterns where applicable for cleaner and more understandable code.
\end{itemize}
\item \textbf{Reliability (NFR5)}:
\begin{itemize}
\item The engine shall be robust enough to handle unexpected inputs without crashing.
\item Memory leaks should be minimized, and efficient memory management practices should be followed.
\end{itemize}
\item \textbf{Scalability (NFR6)}:
\begin{itemize}
\item The game engine shall support additional features or levels in the future without requiring a complete overhaul.
\end{itemize}
\item \textbf{Documentation (NFR7)}:
\begin{itemize}
\item A comprehensive documentation detailing the architecture, algorithms, and functionalities should be provided. (For example in this thesis)
\end{itemize}
\end{enumerate}
2023-08-09 19:34:51 +02:00
\section{Core Engine Implementation}
2023-08-13 22:25:22 +02:00
For our Match Three game engine, we aimed to create a simple core, capable of ensuring basic gameplay and small codebase allowing developers to extend or modify the engine's capabilities as needed. This section describes the implementation of the Match Three game engine.
2023-08-09 19:34:51 +02:00
\subsection{Foundational Principles}
\begin{itemize}
\item Platform Independence: Core engine functionalities independent of any specific platform, allowing for easy porting across Windows, MacOS, and GNU/Linux.
2023-08-09 19:34:51 +02:00
2023-08-30 00:54:33 +02:00
\item Simplicity: There are no more than 1500 lines of code in the entire engine
\item Good coding style: When writing code, popular coding styles of cpplint and clang-tidy were used
\item Good coding principles: when writing code, clang-tidy was extensively used to highlight potential errors and eliminate bad practices
\end{itemize}
2023-08-09 19:34:51 +02:00
\section{Integration of Libraries and Tools}
In this section we will explain rationality for choosing libraries and tools for our engine and how they were implemented
\subsection{ Choice of graphic renderning API }
There are 3 main APIs for graphical rendering
\begin{itemize}
\item DirectX
\item OpenGL
\item Vulkan
\end{itemize}
DirectX developed by Microsoft focues on Windows operating systems and
Microsoft line of consoles Xbox, it is deemed as being harder with more
low level programming and requiring better understanding of how underlying
mechanisms work but in turn offers functionalities and better performance.
It does not have free license. \\
OpenGL is developed by Khronos Group and offers good compatibility,
especially if using OpenGL ES subset which works on Windows, Linux,
Mac OS, Android, iOS and all major consoles.
It is widely recognized as easiest of APIs and most popular choice
for writing first game engine. On the other hand it lacks some of
more advanced features which have to be written manually.
It uses open source license similar to BSD
\\
Vulkan is also developed by Khronos Group and as such is deemed as a
spiritual successor of OpenGL with focus on using modern C++ features and
fixing issues created by OpenGL 30 years old development time.
Out of these three it is recognized as the hardest one as
it is both complicated and newest. Similarly as OpenGL
it uses open source license, namely Apache License 2.0.
\\
\begin{table}[H]
\centering
\caption{Comparison of Graphics APIs}
\begin{tabularx}{\textwidth}{|l|X|X|X|X|}
\hline
& \textbf{Developer} & \textbf{Platform Focus} & \textbf{Complexity} & \textbf{License} \\
\hline
\textbf{DirectX} & Microsoft & Windows, Xbox & Harder, requires understanding of underlying mechanisms & Non-free \\
\hline
\textbf{OpenGL} & Khronos Group & Windows, Linux, Mac OS, Android, iOS, major consoles (especially with OpenGL ES) & Easiest, lacks some advanced features & Open source (similar to BSD) \\
\hline
\textbf{Vulkan} & Khronos Group & Modern platforms, successor to OpenGL & Hardest, newest & Open source (Apache License 2.0) \\
\hline
\end{tabularx}
\end{table}
Considering all of those characteristics I decided to go with OpenGL API,
specifically OpenGL ES subset with its focus on compatibility as
making a multiplatform application is one of the focues of this thesis.
I decided that since this will be my first attempt at game engine development
I need something that is relatively easy and has a lot of resources online.
I would most likely not use advanced features of Vulkan and DirectX and
therefore finish my thesis before approaching problems where OpenGL
does not deliver more complicated architecture.
From my own private preferences I also prefer software with
open source license.
\subsection{Choice of OpenGL Library}
There are 4 basic OpenGL libraries that I considered:
\begin{itemize}
\item freeGLUT
\item SDL
\item SFML
\item GLFW
\end{itemize}
freeGLUT was created as opensource alternative to GLUT,
is considered to be the worst out of all 4,
written in archaic way, using C or very old C++,
which in turn results in unexpected "buggy" behaviour,
it is also not really popular with lack of online guides \\
SDL - Simple DirectMedia Layer has big userbase,
it is not designed to by used as a standalone
library and requires additional libraries to do networking
or to create more complex applications. \\
SFML is the library with most features out of all 4,
it supports networking, audio and has system features by
default. It uses modern object oriented C++.
Main problem with SFML is that it is not very popular API,
therefore troubleshooting problems with SFML is quite hard and
it has only few use guides online \\
GLFW is an library that is both the most popular and with fewest features by default.
It forces users to use additional libraries for networking,
sound, physic calculations and so on but in turn is also
quite small and flexible. It has biggest community and a
lot of guides, like one hosted at
\href{learnopengl.com}{learnopengl.com} or one created by
programming youtuber Cherno \\
I decided to use GLFW library. I wanted something that is
relatively easy to troubleshoot and has abundance of
learning materials online.
\subsection{GLAD and OpenGL Extension Handling}
GLAD enabled the dynamic loading of OpenGL functions, this way engine can use the latest OpenGL features.
\subsection{Text and Image Rendering with FreeType, stb\_image, and ft2build}
FreeType and stb\_image were choosen for their simplicity and popularity
\begin{itemize}
\item Font Rendering: With FreeType and ft2build, the engine can render text, crucial for messages, scores, and menus.
\item Image Loading: stb\_image simplifies the task of loading and processing various image formats, from PNGs and JPGs to more complex formats, making asset integration much easier.
\end{itemize}
2023-08-09 19:44:00 +02:00
\subsection{Core Modules}
2023-08-09 19:34:51 +02:00
The engine's architecture is segmented into modules:
2023-08-09 19:34:51 +02:00
\begin{itemize}
\item Game object: (game\_object.cpp) Defines base class for game objects used by the engine, this class is later used to define tiles
2023-08-09 19:34:51 +02:00
\item Main Game class: (game.cpp) This class combines all of the other modules and runs the game loop
2023-08-09 19:34:51 +02:00
\item Game Level: (game\_level.cpp) Loads and saves game levels.
2023-08-09 19:34:51 +02:00
2023-09-05 01:56:34 +02:00
\item Particle Generator: (particle\_generator.cpp) Generates particle effects for tilesz
\item Resource Manager: (resource\_manager.cpp) Handles assets and shaders files
\item Shader: (shader.cpp) calculates shaders and applies their effects
\item Sprite Renderer: (sprite\_renderer.cpp) Renders sprites from images
\item Text Renderer: (text\_renderer.cpp) Renders text
\item Texture Renderer: (texture.cpp) Renders textures
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-30 00:54:33 +02:00
\subsection{Main function}
\begin{figure}[H]
2023-08-29 14:29:46 +02:00
\centering
\begin{tikzpicture}[node distance=2cm]
\useasboundingbox (-5,0) rectangle (5, -17); % Set a custom bounding box
\node (start) [startstop] {Enter main function};
\node (pro1) [process, below of=start] {Initialize GLFW};
\draw [arrow] (start) -- (pro1);
\node (pro2) [process, below of=pro1] {Initialize window};
\draw [arrow] (pro1) -- (pro2);
\node (pro3) [process, below of=pro2] {Load OpenGL};
\draw [arrow] (pro2) -- (pro3);
\node (pro4) [process, below of=pro3] {Initialize game};
\draw [arrow] (pro3) -- (pro4);
\node (pro5) [process, below of=pro4] {Main Loop};
\draw [arrow] (pro4) -- (pro5);
\node (dec1) [decision, below of=pro5] {Closed?};
\draw [arrow] (pro5) -- (dec1);
% Arrow from 'Closed?' decision node to 'Main Loop' node
\draw [arrow] (dec1.east) -- ++(2,0) |- node[anchor=south] {no} (pro5);
\node (pro6) [process, below of=dec1] {Free resources};
\draw [arrow] (dec1) -- node[anchor=east] {yes} (pro6);
\node (close) [startstop, below of=pro6] {Close};
\draw [arrow] (pro6) -- (close);
\end{tikzpicture}
\caption{Main function logic}
\label{fig:main_function_logic}
\end{figure}
\paragraph{GLFW initialization}
2023-08-30 00:54:33 +02:00
Very first operation of our engine is to initliaze GLFW context, window and openGL, we set version of glfw to 3.3, resizable window and the profile depending on whether the engine got initialized on MacOS, or Linux/Windows, we set the windows width and height based on values from constants file
\subsubsection{Main Loop}
\begin{figure}[H]
\centering
\begin{tikzpicture}[node distance=2cm]
\useasboundingbox (-5,0) rectangle (5, -11); % Set a custom bounding box
\node (start) [startstop] {Enter main loop};
\node (pro2) [process, below of=start] {Process input};
\draw [arrow] (start) -- (pro2);
\node (pro3) [process, below of=pro2] {Update game state};
\draw [arrow] (pro2) -- (pro3);
\node (pro4) [process, below of=pro3] {Render};
\draw [arrow] (pro3) -- (pro4);
\node (dec1) [decision, below of=pro4] {Closed?};
\draw [arrow] (pro4) -- (dec1);
% Arrow from 'Closed?' decision node to 'Main Loop' node
\draw [arrow] (dec1.east) -- ++(2,0) |- node[anchor=south] {no} (start);
\node (close) [startstop, below of=dec1] {Close};
\draw [arrow] (dec1) -- node[anchor=east] {yes} (close);
\end{tikzpicture}
\caption{Main loop}
\label{fig:main_function_logic}
\end{figure}
\paragraph{Process inputs}
Reacts to user inputs and sets up game state based on them, for example which tile was chosen by user
\paragraph{Update game state}
Changes game level, removes blocks if applicable, drops new blocks and checks for win/lose conditions
\paragraph{Render}
Based on changes from previous steps draws actual game window.
2023-08-29 14:29:46 +02:00
2023-08-09 19:34:51 +02:00
\subsection{Constants file}
Game parameters, from graphics settings to gameplay variables, are stored in constants.cpp file, which can be modified, to apply the changes the engine must be compiled again.
2023-08-09 19:34:51 +02:00
2023-08-30 00:54:33 +02:00
\subsection*{Game Constants}
\textbf{constants} namespace: Used for constants that are used over the project, for example colors, colors are hold in open gl vector of 3 values (for RGB colors)
\begin{lstlisting}[style=C++Style]
namespace constants {
constexpr glm::vec3 LIGHT_BLUE = glm::vec3(0.2F, 0.6F, 1.0F);
...
}
\end{lstlisting}
\newpage
\textbf{text} namespace: Parameters concerning text display positions on screen.
\begin{lstlisting}[style=C++Style]
struct Point {
float x;
float y;
};
namespace text {
constexpr Point LIVES_POSITION = {5.0F, 5.0F};
...
}
\end{lstlisting}
\textbf{textures} namespace: Provides paths to texture files and their respective identifiers, in this examples gems are named as: "g" for gems, number of gem and then color of gem
\begin{lstlisting}[style=C++Style]
struct TextureInfo {
const char* path;
const char* name;
};
namespace textures {
static constexpr TextureInfo textures[] = {
{"resources/textures/background.jpg", "background"},
{"resources/textures/g1black.png", "block_black"},
{"resources/textures/g2blue.png", "block_blue"},
{"resources/textures/g3green.png", "block_green"},
{"resources/textures/g4purple.png", "block_purple"}
};
}
\end{lstlisting}
2023-08-31 15:34:05 +02:00
\section{Game class}
Game class defined in game.h and game.cpp is the main and biggest class in the project, it brings together all other classes and functionalities of the engine.
\subsubsection{Includes}
\begin{lstlisting}[style=C++Style]
#include "./constants.hpp"
#include "./filesystem.h"
#include "./game_level.h"
#include "./game_object.h"
#include "./resource_manager.h"
#include "./sprite_renderer.h"
#include "./text_renderer.h"
\end{lstlisting}
\paragraph{Constructor}
Constructor initializes game window size, empties clicked keys, sets game state to game menu, sets initial level map and retrieves max turns from constants file
\begin{lstlisting}[style=C++Style]
Game::Game(ScreenDimensions screen)
: State(GAME_MENU),
Keys(),
KeysProcessed(),
Width(screen.width),
Height(screen.height),
Level(0),
MaxTurns(constants::MAX_TURNS),
Turns(0)
{}
\end{lstlisting}
\subsection{Game initialization}
\begin{figure}[H]
\centering
\begin{tikzpicture}[node distance=2cm]
\useasboundingbox (-5,0) rectangle (5, -11); % Set a custom bounding box
\node (start) [startstop] {Init game};
\node (pro2) [process, below of=start] {Configure Shaders};
\draw [arrow] (start) -- (pro2);
\node (pro3) [process, below of=pro2] {Load Textures};
\draw [arrow] (pro2) -- (pro3);
\node (pro4) [process, below of=pro3] {Render Controls};
\draw [arrow] (pro3) -- (pro4);
\node (pro5) [process, below of=pro4] {Load Levels};
\draw [arrow] (pro4) -- (pro5);
\node (close) [startstop, below of=pro5] {Finish};
\draw [arrow] (pro5) -- (close);
\end{tikzpicture}
\caption{Initialization logic}
\label{fig:main_function_logic}
\end{figure}
We will describe each step below
\paragraph{Shaders}
Two shaders are used throughout the project, one for rendering sprites (gem tiles) and one for generating post processes (for example shaking the map when tiles get matched) \\
More on the shaders usage later when we will be discussing postProcessor and Shader clasess
\begin{lstlisting}[style=C++Style]
void Game::loadShaders() {
ResourceManager::LoadShader("sprite.vs", "sprite.fs", "sprite");
ResourceManager::LoadShader("post_processing.vs", "post_processing.fs", "postprocessing");
}
\end{lstlisting}
\paragraph{Textures}
Textures names are first defined in the constans file, then the game object invokes resource manager to go through texture paths and load them
\begin{lstlisting}[style=C++Style]
void Game::loadTextures() {
const auto *begin = std::begin(textures::textures);
const auto *end = std::end(textures::textures);
for (auto it = begin; it != end; ++it) {
ResourceManager::LoadTexture(FileSystem::getPath(it->path).c_str(),
it->name);
}
}
\end{lstlisting}
\paragraph{Setting controls}
After loading sprite renderers, postprocesses and text, we set instances of classes using loaded resources.
\begin{lstlisting}[style=C++Style]
void Game::renderSpecificControls() {
// set render-specific controls
Renderer =
std::make_unique<SpriteRenderer>(ResourceManager::GetShader("sprite"));
Effects = std::make_unique<PostProcessor>(
ResourceManager::GetShader("postprocessing"), this->Width, this->Height);
Text =
std::make_unique<TextRenderer>(TextRenderer(this->Width, this->Height));
Text->Load(FileSystem::getPath("resources/fonts/OCRAEXT.TTF"), text::OCRAEXT_FONT_SIZE);
}
\end{lstlisting}
\paragraph{Levels}
Levels are loaded automatically from the levels folder, game assumes that every file with extension ".lvl" is a level file and adds it to an array of levels
\begin{lstlisting}[style=C++Style]
void Game::loadLevels() {
const std::string path = "../../resources/levels/";
for (const auto& entry : std::filesystem::directory_iterator(path)) {
if (entry.is_regular_file() && entry.path().extension() == ".lvl") {
GameLevel level;
level.Load(entry.path().c_str(), this->Width, this->Height);
this->Levels.push_back(level);
}
}
this->Level = 0;
}
\end{lstlisting}
\subsection{Game update}
\begin{figure}[H]
\centering
\begin{tikzpicture}[node distance=2cm]
\useasboundingbox (-5,0) rectangle (5, -13); % Set a custom bounding box
\node (start) [startstop] {Update};
\node (pro2) [process, below of=start] {Update Tiles};
\draw [arrow] (start) -- (pro2);
\node (dec1) [decision, below of=pro2, yshift=-1cm] {Points reached?};
\draw [arrow] (pro2) -- (dec1);
\node (stopLost) [startstop, left of=dec1, xshift=-2cm] {Game Won};
\draw [arrow] (dec1) -- node[anchor=north] {yes} (stopLost);
\node (dec2) [decision, below of=pro4, yshift=-1cm] {Turns exceeded?};
\draw [arrow] (dec1) -- node[anchor=west]{no} (dec2);
% Arrow from 'Closed?' decision node to 'Main Loop' node
\draw [arrow] (dec2.east) -- ++(2,0) |- node[anchor=south] {no} (start);
\node (stopWon) [startstop, below of=dec2, yshift=-1cm] {Game Lost};
\draw [arrow] (dec2) -- node[anchor=west]{yes} (stopWon);
\end{tikzpicture}
\caption{Game updates logic}
\label{fig:main_function_logic}
\end{figure}
Game is ended either when the player exceeds maximum move limit (game lost) or when points limit is reached (game won), otherwise the game continues, notice how first we check for win condition then for loss condition, this makes the gameplay a little bit more satisfying and fair.
\subsection{Controls}
Game allows to move through the grid to highlight a tile, then after clicking "enter" a tile is selected, then by using arrows or WSAD keys user can highlight the tile that will be swapped when again "enter" gets clicked
\begin{figure}[H]
\centering
\begin{tikzpicture}[node distance=2cm]
\useasboundingbox (-5,0) rectangle (5, -7); % Set a custom bounding box
\node (start) [startstop] {Highight tile (WSAD or arrow keys)};
\node (pro2) [process, below of=start] {Select tile (ENTER)};
\draw [arrow] (start) -- (pro2);
\node (pro3) [process, below of=pro2] {Highlight tile to swap (WSAD or arrow keys)};
\draw [arrow] (pro2) -- (pro3);
\node (stop) [startstop, below of=pro3] {Swap tile (ENTER)};
\draw [arrow] (pro3) -- (stop);
\end{tikzpicture}
\caption{User controls}
\label{fig:main_function_logic}
\end{figure}
All of input processing is taken care by game class, and then relied to game level class.
\begin{lstlisting}[style=C++Style]
void Game::handleActiveGame() {
if (this->State == GAME_ACTIVE) {
this->moveLeft();
this->moveRight();
this->moveUp();
this->moveDown();
this->selectPiece();
this->unselectPiece();
}
}
\end{lstlisting}
\begin{figure}[htp]
\centering
\begin{subfigure}[b]{0.45\textwidth}
\centering
\includegraphics[scale=0.45]{images/controlsSelect.png}
\caption{View of highlighted tile}
\label{fig:highlighted_tile}
\end{subfigure}
\hfill
\begin{subfigure}[b]{0.45\textwidth}
\centering
\includegraphics[scale=0.45]{images/controlsSelectGreen.png}
\caption{View of selected tile}
\label{fig:selected_tile}
\end{subfigure}
\caption{Tile selection views}
\label{fig:tile_selection}
\end{figure}
\begin{figure}[H]
\centering
\begin{subfigure}[b]{0.45\textwidth}
\includegraphics[scale=0.45]{images/controlsSwapLeft.png}
\caption{Left tile is set to be swapped when enter key will be hit}
\label{fig:swap_left}
\end{subfigure}
\hfill
\begin{subfigure}[b]{0.45\textwidth}
\includegraphics[scale=0.45]{images/controlsSwapRight.png}
\caption{Right tile is set to be swapped when enter key will be hit}
\label{fig:swap_right}
\end{subfigure}
\vspace{10pt}
\begin{subfigure}[b]{0.45\textwidth}
\includegraphics[scale=0.45]{images/controlsSwapUp.png}
\caption{Upper tile is set to be swapped when enter key will be hit}
\label{fig:swap_up}
\end{subfigure}
\hfill
\begin{subfigure}[b]{0.45\textwidth}
\includegraphics[scale=0.45]{images/controlsSwapDown.png}
\caption{Down tile is set to be swapped when enter key will be hit}
\label{fig:swap_down}
\end{subfigure}
\caption{Tile swap controls}
\label{fig:tile_swaps}
\end{figure}
\subsection{Rendering}
2023-08-31 19:36:05 +02:00
As mentioned in main loop, the game runs a render method every frame.
\begin{figure}[H]
\centering
\begin{tikzpicture}[node distance=2cm]
\useasboundingbox (-5,0) rectangle (5, -9); % Set a custom bounding box
\node (start) [startstop] {Render};
\node (dec1) [decision, below of=start] {State};
\draw [arrow] (start) -- (dec1);
\node (pro1) [process, below of=dec1, xshift=2cm] {Render win view};
\draw [arrow] (dec1) -- node[anchor=west] {Game won} (pro1);
\node (pro2) [process, below of=dec1, xshift=-2cm] {Render menu view};
\draw [arrow] (dec1) -- node[anchor=east] {Menu} (pro2);
\node (stop) [startstop, below of=dec1, yshift=-4cm] {Render main view};
\draw [arrow] (dec1) -- node[anchor=east] {Active} (stop);
\draw [arrow] (pro1) -- (stop);
\draw [arrow] (pro2) -- (stop);
\end{tikzpicture}
\caption{Rendering logic}
\label{fig:main_function_logic}
\end{figure}
\paragraph{Rendering text}
Rendering menu and win view consists of giving a text class correct coordinates and what text should be displayed
\begin{lstlisting}[style=C++Style]
From constants.hpp file:
namespace text {
...
constexpr float WON_X_POSITION = 320.0F;
constexpr float WON_Y_OFFSET = -20.0F;
constexpr float WON_ESCAPE_X_POSITION = 130.0F;
...
}
From game.cpp file:
void Game::renderWin() const {
if (this->State == GAME_WIN) {
const float screenMiddleYCoordinate =
static_cast<float>(this->Height) / 2.0F;
Text->RenderText("You WON!", {text::WON_X_POSITION,
screenMiddleYCoordinate + text::WON_Y_OFFSET}, 1.0F,
glm::vec3(0.0F, 1.0F, 0.0F));
Text->RenderText("Press ENTER to retry or ESC to quit",
{text::WON_ESCAPE_X_POSITION, screenMiddleYCoordinate}, 1.0F,
glm::vec3(1.0F, 1.0F, 0.0F));
}
}
\end{lstlisting}
\newpage
\paragraph{Rendering main view}
Rendering main view consists of rendering map and then applying postprocesses and text represending number of turns
\begin{lstlisting}[style=C++Style]
void Game::renderMain() {
if (this->State == GAME_ACTIVE || this->State == GAME_MENU ||
this->State == GAME_WIN) {
// begin rendering to postprocessing framebuffer
Effects->BeginRender();
this->renderDraw();
// end rendering to postprocessing framebuffer
Effects->EndRender();
// render postprocessing quad
const auto time = static_cast<float>(glfwGetTime());
Effects->Render(time);
// render turns (don't include in postprocessing)
this->renderTurns();
}
}
\end{lstlisting}
2023-08-31 15:34:05 +02:00
2023-08-31 19:36:05 +02:00
\section{Game level class}
2023-09-04 00:58:22 +02:00
Game level class takes a 2D array of game objects instances (tiles), receives inputs from game class and reacts to them, it handles removing, swaping, adding new tiles on a map and checking for sequences of tiles. It also loads the level file and translates it to in game object
\paragraph{Reading file}
Game level class goes through each line of level file. \\
It loads each row to a vector of unsigned int as the level file contains rows of numbers representing tile type
\begin{figure}
\begin{lstlisting}
4 2 3 2 4 3 3 1 3 3
1 1 2 1 1 2 1 3 1 1
4 1 4 3 3 4 4 3 2 3
4 3 3 4 3 3 2 1 2 1
3 2 3 1 4 4 3 2 4 2
4 2 1 3 3 2 2 3 1 1
4 3 2 1 2 2 3 3 4 4
1 4 3 2 1 4 3 2 1 4
3 4 3 3 4 4 1 2 3 1
2 3 2 2 1 2 3 3 4 2
\end{lstlisting}
\caption{Exemplary level file}
\end{figure}
\paragraph{Level initialization}
Initializing level takes the loaded vector of ids and creates game objects based on the window dimensions (so that the tiles fill the window evenly), textures are based on the tile id,
we assume that all levels are square so the width and height of the window is always the same.
\newpage1
\begin{lstlisting}[style=C++Style]
void GameLevel::handleTile(std::vector<std::vector<unsigned int>> tileData,
unsigned int x_coordinate, unsigned int y_coordinate,
float unit_width, float unit_height) {
const unsigned int tileNumber = tileData[y_coordinate][x_coordinate];
glm::vec3 color = this->assignColor(static_cast<int>(tileNumber));
// Directly use the constructor arguments for GameObject with emplace_back
this->Bricks.emplace_back(tileNumber,
glm::vec2(unit_width * static_cast<float>(x_coordinate), unit_height * static_cast<float>(y_coordinate)),
glm::vec2(unit_width, unit_height),
ResourceManager::GetTexture(idTextureMap[tileNumber]),
color
);
}
void GameLevel::init(std::vector<std::vector<unsigned int>> tileData, unsigned int levelWidth, unsigned int levelHeight)
{
// calculate dimensions
unsigned int height = tileData.size();
unsigned int width = tileData[0].size(); // note we can index vector at [0] since this function is only called if height > 0
float unit_width = static_cast<float>(levelWidth) / static_cast<float>(width);
// initialize level tiles based on tileData
for (unsigned int y_coordinate = 0; y_coordinate < height; ++y_coordinate)
{
for (unsigned int x_coordinate = 0; x_coordinate < width; ++x_coordinate)
{
this->handleTile(tileData, x_coordinate, y_coordinate, unit_width, unit_width);
}
}
}
\end{lstlisting}
2
\subsection{Highlighting, selecting and swapping tiles}
There are four steps in order for the tile to be swapped, logic of fulfilling this conditions is handled in game level class
\paragraph{Highlighting tile}
First the tile must be highlighted, game level makes sure that only one tile is highlighted by keeping the index of highlighted tile and changing it whenever user inputs a change
\paragraph{Selecting tile}
Then the tile must be selected, again game level has a special parameter just to keep track of which tile is selected
\begin{lstlisting}[style=C++Style]
void GameLevel::selectPiece() {
this->Bricks.at(selectedTile).Selected = true;
...
}
void GameLevel::unselectPiece() {
this->Bricks.at(selectedTile).Selected = false;
this->unswapAll();
}
\end{lstlisting}
\paragraph{Which tile will be swapped}
Then the user must choose which tile will be swapped, game level does not keep special parameter for that, it just automatically deselects all tiles in the selected tile neighboorhood if user choose any other tile
\begin{lstlisting}[style=C++Style]
void GameLevel::moveRight()
{
if(!this->Bricks.at(selectedTile).Selected) {
this->Bricks.at(selectedTile).Highlighted = false;
this->selectedTile++;
if(static_cast<size_t>(this->selectedTile) > this->Bricks.size()) {
this->selectedTile--;
}
this->Bricks.at(selectedTile).Highlighted = true;
return;
}
this->swapRight();
}
\end{lstlisting}
\paragraph{Confirming swap}
At the end user must confirm the swap, then the swap is checked if it creates the pattern of at least 3 tiles
\begin{lstlisting}[style=C++Style]
void GameLevel::confirmSwap()
{
const bool canSwap = this->checkSwap();
if(this->swappableTile != -1 && canSwap) {
this->Bricks.at(selectedTile).Selected = false;
this->Bricks.at(selectedTile).Highlighted = false;
this->unswapAll();
const GameObject temp = this->Bricks[this->swappableTile];
this->Bricks[this->swappableTile].Position = this->Bricks[this->selectedTile].Position;
this->Bricks[this->selectedTile].Position = temp.Position;
std::swap(this->Bricks[this->swappableTile], this->Bricks[this->selectedTile]);
this->selectedTile = 0;
this -> swappableTile = -1;
}
}
void GameLevel::selectPiece() {
this->Bricks.at(selectedTile).Selected = true;
if(this->Bricks.at(selectedTile).Selected) {
this->confirmSwap();
}
}
\end{lstlisting}
\subsection{Matching logic}
When 3, 4 or 5 tiles get match in a row or column, matching function removes those tiles, fills the empty space with blocks from above and fills the final empty space with randomly generated tiles
\paragraph{Finding matches}
To simplify finding matches first game objects tiles is transformed into vector of ids, then this vector is converted into vectors of columns and rows and finaly those vectors are checked for matches
\begin{figure}[H]
\centering
\begin{tikzpicture}[node distance=2cm]
\useasboundingbox (-5,0) rectangle (5, -9); % Set a custom bounding box
2023-09-04 01:15:49 +02:00
\node (start) [startstop] {Finding matches logic};
2023-09-04 00:58:22 +02:00
\node (pro1) [process, below of=start] {Convert to ids vector};
\draw [arrow] (start) -- (pro1);
\node (pro2) [process, below of=pro1] {Convert to rows and columns ids vectors};
\draw [arrow] (pro1) -- (pro2);
\node (pro3) [process, below of=pro2] {Find matches};
\draw [arrow] (pro2) -- (pro3);
\node (stop) [startstop, below of=pro3] {Return matches};
\draw [arrow] (pro3) -- (stop);
\end{tikzpicture}
\caption{Finding matches logic}
\label{fig:findingMatches}
\end{figure}
2023-09-04 02:46:48 +02:00
\newpage
\subsection{Processing matches}
2023-09-04 00:58:22 +02:00
\paragraph{Removing blocks}
After finding matches, blocks where matches appear are set to be replaced by replacing their tile ids with -1
\paragraph{Replacing blocks}
After setting tiles to be replaced, algorithm goes through blocks with ids equal to -1, checks if there are any blocks above, if yes it replaces the block from above with block from below, if there is no block above, it generates one randomly
2023-09-04 02:46:48 +02:00
\begin{figure}[H]
2023-09-04 00:58:22 +02:00
\centering
2023-09-04 01:15:49 +02:00
\includegraphics{images/processLogicMatches.pdf}
\caption{Logic for processing matches}
2023-09-04 00:58:22 +02:00
\end{figure}
2023-08-31 15:34:05 +02:00
2023-09-04 02:46:48 +02:00
\subsection{Game objects}
Game object class holds informations about tiles, its position, textures and statuses
\paragraph{Tile draw}
Based on a status of tile it can be drawn in 4 ways:
\begin{enumerate}
\item No status at all, it is drawn without any color overlayed on it
\item Highlighted, it is drawn with red overlay
\item Selected, it is drawn with green overlay
\item ToSwap, it is drawn with orange overlay
\end{enumerate}
\begin{lstlisting}[style=C++Style]
void GameObject::Draw(SpriteRenderer &renderer)
{
if(ToSwap) {
glm::vec3 color = hexToVec3("#f97316");
renderer.DrawSprite(this->Sprite, this->Position, this->Size, this->Rotation, color);
return;
}
if(!Highlighted) {
glm::vec3 empty(1.0f, 1.0f, 1.0f);
renderer.DrawSprite(this->Sprite, this->Position, this->Size, this->Rotation, empty);
return;
renderer.DrawSprite(this->Sprite, this->Position, this->Size, this->Rotation, this->Color);
return;
}
if(!Selected) {
glm::vec3 red(1.0f, 0.0f, 0.0f);
renderer.DrawSprite(this->Sprite, this->Position, this->Size, this->Rotation, red);
return;
}
glm::vec3 green(0.0f, 1.0f, 0.0f);
renderer.DrawSprite(this->Sprite, this->Position, this->Size, this->Rotation, green);
}
\end{lstlisting}
Engine uses two helpful methods to easily translate color hex to glm::vec3 color
\begin{lstlisting}[style=C++Style]
glm::vec3 hexToVec3(const std::string& hex) {
if (hex.size() != 6 && hex.size() != 7) {
throw std::invalid_argument("Invalid hex string length.");
}
size_t offset = hex[0] == '#' ? 1 : 0;
int r = std::stoi(hex.substr(offset, 2), nullptr, 16);
int g = std::stoi(hex.substr(offset + 2, 2), nullptr, 16);
int b = std::stoi(hex.substr(offset + 4, 2), nullptr, 16);
return glm::vec3(r / 255.0f, g / 255.0f, b / 255.0f);
}
glm::vec3 vectorToVec3(const std::vector<int>& vec) {
if (vec.size() != 3) {
throw std::invalid_argument("Vector must have exactly 3 elements.");
}
return glm::vec3(vec[0] / 255.0f, vec[1] / 255.0f, vec[2] / 255.0f);
}
\end{lstlisting}
\begin{figure}[htp]
\centering
\includegraphics[scale=0.75]{images/statesGameObject.pdf}
\caption{Game object states}
\end{figure}
\subsection{Text Renderer}
Text renderer class loads the library and single characters of font used to render text, applies text shaders, sets the text at the position requested by engine and removes text after it is not used \\
We also use a shader for text, we will describe the class and shader in this section
\paragraph{initialization}
When text render class is initialized, it loads the correct shader and sets it up to work
\subsubsection{Loading font}
When initializing text render objects, we provide a ttf file from resources/fonts folder. Text render object calls free type library to load a font
\paragraph{Initializing loading}
First we clear any characters that were loaded previously, initialize freeType library and check if it was correctly loaded
\begin{lstlisting}[style=C++Style]
void TextRenderer::Load(const std::string &font, unsigned int fontSize)
{
// first clear the previously loaded Characters
this->Characters.clear();
// then initialize and load the FreeType library
FT_Library freeTypeLibrary;
// all functions return a value different than 0 whenever an error occurred
if (FT_Init_FreeType(&freeTypeLibrary)) {
std::cout << "ERROR::FREETYPE: Could not init FreeType Library" << std::endl;
}
...
\end{lstlisting}
2023-09-04 14:12:27 +02:00
\newpage
\paragraph{Actual loading and configuration}
We load the font using freeType, after checking if it was loaded correctly we set size of a single character, disable byte-alignment in order for the text to be rendered correctly, preload first 128 [ASCII] characters and since we already loaded everything we wanted we destroy FreeType library
\begin{lstlisting}[style=C++Style]
void TextRenderer::Load(const std::string &font, unsigned int fontSize)
{
...
FT_Face face = this -> loadFontAsFace(freeTypeLibrary, font);
// set size to load glyphs as
FT_Set_Pixel_Sizes(face, 0, fontSize);
// disable byte-alignment restriction
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
face = this -> preloadCharacters(face);
this -> destroyFreeType(face, freeTypeLibrary);
}
\end{lstlisting}
\begin{figure}[htp]
\centering
\begin{tikzpicture}[node distance=1.5cm]
\useasboundingbox (-5,0) rectangle (5, -13cm); % Set a custom bounding box
\node (start) [startstop] {Load font};
\node (pro1) [process, below of=start] {Clear previous characters};
\draw [arrow] (start) -- (pro1);
\node (pro2) [process, below of=pro1] {Initialize FreeType library};
\draw [arrow] (pro1) -- (pro2);
\node (pro3) [process, below of=pro2] {Load font};
\draw [arrow] (pro2) -- (pro3);
\node (pro4) [process, below of=pro3] {Set letter pixel size};
\draw [arrow] (pro3) -- (pro4);
\node (pro5) [process, below of=pro4] {Disable byte allignment};
\draw [arrow] (pro4) -- (pro5);
\node (pro6) [process, below of=pro5] {Preload ASCII characters};
\draw [arrow] (pro5) -- (pro6);
\node (pro7) [process, below of=pro6] {Destroy FreeType};
\draw [arrow] (pro6) -- (pro7);
\node (stop) [startstop, below of=pro7] {Finish loading};
\draw [arrow] (pro7) -- (stop);
\end{tikzpicture}
\caption{Loading font logic}
2023-09-04 14:12:27 +02:00
\label{fig:loadingFont}
\end{figure}
2023-09-05 00:01:18 +02:00
\subsubsection{Loading characters}
2023-09-04 14:12:27 +02:00
In order to preload ASCII characters we use a method loadCharacter from TextRenderer, it uses FreeType library to load character, then generates textures for a character (it needs to allign a texture to character), sets options for texture and adds the character object to characters array
\begin{figure}[htp]
\centering
\begin{tikzpicture}[node distance=1.5cm]
2023-09-05 00:01:18 +02:00
\useasboundingbox (-5,0) rectangle (5, -10cm); % Set a custom bounding box
2023-09-04 14:12:27 +02:00
\node (start) [startstop] {Load character};
\node (pro1) [process, below of=start] {Load character using FreeType};
\draw [arrow] (start) -- (pro1);
\node (pro2) [process, below of=pro1] {Generate Texture};
\draw [arrow] (pro1) -- (pro2);
2023-09-04 14:12:27 +02:00
\node (pro3) [process, below of=pro2] {Setup texture options};
\draw [arrow] (pro2) -- (pro3);
\node (pro4) [process, below of=pro3] {Create character instance};
\draw [arrow] (pro3) -- (pro4);
\node (pro5) [process, below of=pro4] {Push character to characters array};
\draw [arrow] (pro4) -- (pro5);
\node (stop) [startstop, below of=pro5] {Finish loading};
\draw [arrow] (pro5) -- (stop);
\end{tikzpicture}
\caption{Loading single character logic}
\label{fig:loadingCharacter}
\end{figure}
2023-09-04 02:46:48 +02:00
2023-09-05 00:01:18 +02:00
\newpage
\paragraph{Texture options}
\begin{itemize}
\item The first two lines set the wrapping mode of the texture in the S and T directions (usually the x and y axes) to \texttt{GL\_CLAMP\_TO\_EDGE}. This means if the texture coordinates go beyond [0,1], the texture will not repeat but instead clamp to the edge values.
\item The next two lines set the minification and magnification filter to \texttt{GL\_LINEAR}. This means when the texture is scaled down or up, it will use linear interpolation between the texture coordinates, resulting in a smoother texture appearance.
\end{itemize}
\begin{lstlisting}[style=C++Style]
void TextRenderer::setTextureOptions() const {
// set texture options
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
\end{lstlisting}
\newpage
\subsubsection{Rendering text}
We are given text as a C++ string and a position, method is supposed to automatically render text so that it fits in a position that was provided \\
We achieve that by iterating through each character of a string and putting it next to each other at a gap equal to a previous character width and height
\begin{figure}[htp]
\centering
\includegraphics[scale=1.00]{images/glyph_offset.png}
\caption{Glyph metrics from learnopengl}
\label{}
\end{figure}
Calculating x and y positions of each character \\
$x_{pos}$ and $y_{pos}$ is the final x/y position of character \\
$x_{start}$ and $y_{start}$ is the position inputed to the method render text \\
$x_{bearing}$ and $y_{bearing}$ is a parameter shown in image above \\
$s$ is scale \\
We calculate final bearing of $y_{pos}$ by subtracting bearing of "H" character from the bearing of actual character, we do it this way because "y" bearing of "H" character is highest \\
\[
x_{pos} = x_{start} + x_{bearing} * s
\]
\[
y_{pos} = y_{start} + (H_{bearing} - y_{bearing}) * s
\]
2023-09-05 01:56:34 +02:00
\subsection{Resource Manager}
Resource manager class loads textures and shaders from files.
\paragraph{Loading textures}
After giving a name of texture to a method it is loaded (converted to raw byte data) using stb image library, we receive texture width, height and number of channels and later use it to generate texture using texture class. At the end we free image data
\begin{lstlisting}[style=C++Style]
// RGB for Red Green Blue, RGBA for alpha channel
GLenum getTextureFormat(int nrChannels) {
switch (nrChannels) {
case 1: return GL_RED;
case 3: return GL_RGB;
case 4: return GL_RGBA;
default:
throw std::runtime_error("Unsupported number of channels in the image.");
}
}
Texture2D ResourceManager::loadTextureFromFile(const char *file)
{
// create texture object
Texture2D texture;
// load image
int width;
int height;
int nrChannels;
unsigned char* data = stbi_load(file, &width, &height, &nrChannels, 0);
GLenum format = getTextureFormat(nrChannels);
texture.Internal_Format = format;
texture.Image_Format = format;
// now generate texture
texture.Generate(width, height, data);
// and finally free image data
stbi_image_free(data);
return texture;
}
\end{lstlisting}
\subsubsection{Loading shaders}
In order to load shaders we load up to three different source codes for vertex, fragment and geometry shaders and compile them in shader class.
\paragraph{Shader types}
\begin{itemize}
\item \textbf{Vertex Shader:} This is the first stage in the graphics pipeline that processes each vertex and is responsible for transforming vertex positions from object space (local coordinates) to clip space. Additionally, it can manipulate vertex attributes such as colors, normals, and texture coordinates.
\item \textbf{Fragment Shader:} Often referred to as a pixel shader, this stage operates on each fragment (potential pixel) generated by rasterization. It determines the final color of the pixels on the screen. Fragment shaders can apply textures, compute lighting, and handle other surface details.
\item \textbf{Geometry Shader:} This is an optional shader stage that sits between the vertex and fragment shaders. It can generate new graphics primitives (like points, lines, and triangles) from input primitives. It offers more flexibility in processing than the vertex shader but can be computationally intensive.
\end{itemize}
\subsection{Shader class}
Shader object compiles shader from shader string code and sets its input parameters
\subsubsection{Compiling shader}
When compiling shader we provide shader source code, create shader from shader type (vertex, fragment or geometry), compile it, attach to program and link program so that it can be used by engine, at the end we remove the shader code as it is already in our engine in order to free resources.
\begin{lstlisting}[style=C++Style]
unsigned int Shader::compileShader(const char *shaderSource, const std::string& type, const GLenum shaderType) {
unsigned int shaderPointer = 0;
if(shaderSource != nullptr) {
shaderPointer = glCreateShader(shaderType);
glShaderSource(shaderPointer, 1, &shaderSource, nullptr);
glCompileShader(shaderPointer);
checkCompileErrors(shaderPointer, type);
}
return shaderPointer;
}
void Shader::Compile(const char* vertexSource, const char* fragmentSource, const char* geometrySource)
{
unsigned int sVertex = this->compileShader(vertexSource, "VERTEX", GL_VERTEX_SHADER);
// shader program
this->ID = glCreateProgram();
glAttachShader(this->ID, sVertex);
...
glLinkProgram(this->ID);
checkCompileErrors(this->ID, "PROGRAM");
// delete the shaders as they're linked into our program now and no longer necessary
glDeleteShader(sVertex);
...
}
\end{lstlisting}
\begin{figure}[htp]
\centering
\begin{tikzpicture}[node distance=1.5cm]
\useasboundingbox (-5,0) rectangle (5, -13cm); % Set a custom bounding box
\node (start) [startstop] {Processing shader};
\node (pro1) [process, below of=start] {Create shader};
\draw [arrow] (start) -- (pro1);
\node (pro2) [process, below of=pro1] {Get shader source};
\draw [arrow] (pro1) -- (pro2);
\node (pro3) [process, below of=pro2] {Compile shader};
\draw [arrow] (pro2) -- (pro3);
\node (pro4) [process, below of=pro3] {Create shader program};
\draw [arrow] (pro3) -- (pro4);
\node (pro5) [process, below of=pro4] {Attach shader to program};
\draw [arrow] (pro4) -- (pro5);
\node (pro6) [process, below of=pro5] {Link program to engine};
\draw [arrow] (pro5) -- (pro6);
\node (pro7) [process, below of=pro6] {Delete shaders};
\draw [arrow] (pro6) -- (pro7);
\node (stop) [startstop, below of=pro7] {Finish processing};
\draw [arrow] (pro7) -- (stop);
\end{tikzpicture}
\caption{Processing shader}
\label{fig:processShader}
\end{figure}
2023-08-30 00:54:33 +02:00
\subsection{Dependency Management}
There are several libraries: OpenGL, GLFW, stb\_image and freetype being integrated into engine, they are simply included at the top of any files that need them.
\chapter{Practical Use of Engine}
In the previous chapters, we explained on the architecture, design, and construction of our match-three game engine This chapter focuses on practical application of this engine by illustrating the creation of a functional match-three game from scratch.
\section{Initial Setup and Configuration}
Before we start creating the game, We need to set up the development environment to utilize our game engine's capabilities fully. Using a modern IDE (Integrated Development Environment) like Visual Studio or Code::Blocks can ease the process.
\paragraph{Importing the engine} Initiate a new C++ project and import our game engine's header and source files. Ensure that the necessary libraries related to OpenGL are linked.
\paragraph{Configuration of OpenGL} Validate that the OpenGL version compatible with our engine is installed. This often involves setting up GLEW (OpenGL Extension Wrangler Library) or similar middleware.
\subsection{Choosing assets}
Choosing assets is the most important part of our match three engine design \\
We are going to use site \href{https://opengameart.org/}{https://opengameart.org/} which offers free game assets with permissive license, wcansFilterede are going to search for assets with the most permisible CC0 license which is an equivalent to public license
\begin{figure}[H]
\centering
\includegraphics[scale=1.00]{images/openGameArt.png}
\caption{Searching for 2D art on OpenGameArt}
\label{}
\end{figure}
\begin{figure}[H]
\centering
\includegraphics[scale=1.00]{images/OGASearch.png}
\caption{Searching for CC0 licensed assets}
\label{}
\end{figure}
\paragraph{Filtering non tiles assets}
Our first step is to filter all assets that refer to graphics that cannot be used as tiles, for example UI elements, icons or buttons
\subsubsection{Filtering tile assets}
We end up with 4 assets to choose from, based on 2 parameters we filtered 3 of them
\paragraph{Using mechanics not available in engine}
First we filter asset pack that uses dynamic falling mechanic which is not present in our engine
\begin{figure}[htp]
\centering
\includegraphics[scale=0.4]{images/cans.png}
\caption{Cans have different sprite depending on if they are falling or not, we do not have such mechanic in our engine \cite{cansFiltered}}
\label{}
\end{figure}
\paragraph{Too much details}
Two more tile assets use too much details inside the tiles, this would require our game to react to those details to make sure that the gameplay experience is compatible with the tiles look.
\begin{figure}[htp]
\centering
\begin{minipage}{0.45\textwidth}
\centering
\includegraphics[scale=0.50]{images/tooMuchDetailsOne.png}
\caption{First assets with too much details inside the detail \cite{tooMuchOne}}
\label{fig:tooMuchDetailsOne}
\end{minipage}\hfill
\begin{minipage}{0.45\textwidth}
\centering
\includegraphics[scale=1.00]{images/tooMuchDetailsTwo.png}
\caption{Second assets with too much details inside the detail \cite{tooMuchTwo}}
\label{fig:tooMuchDetailsTwo}
\end{minipage}
\end{figure}
\paragraph{Chosen assets}
Finally we settled on these tiles, they look simple, work well with our shaders and engine gameplay and offer high quality non-pixelated files
\begin{figure}[htp]
\centering
\includegraphics[scale=1.00]{images/gemMatchThree.png}
\caption{Chosen assets \cite{assetsMatchThree}}
\label{}
\end{figure}
\subsection{Loading assets}
In order to use our assets in the game engine we need to define their names in the engine code and put the files into correct folder
\paragraph{Setting files}
All non-code files used in our engine are stored in resources older \\
Textures in particular are stored in "textures" folder \\
That is where we unpack our tiles, files in the unzipped folder are named with a pattern: "Gem Type[number] [color].png" \\
In order to simplify importing assets name we created a short python script that renames all tiles to "g[number][color].png"
\begin{lstlisting}[style=mystyle][caption=Python code for renaming files]
import os
import re
def rename_files_in_directory(directory_path):
# List all files in the directory
for filename in os.listdir(directory_path):
# Match filenames using regex
match = re.match(r"Gem Type(\d+) (\w+)\.png", filename)
if match:
number = match.group(1)
color = match.group(2).lower() # Convert to lowercase
new_filename = f"g{number}{color}.png"
# Rename files
os.rename(
os.path.join(directory_path, filename),
os.path.join(directory_path, new_filename)
)
# Call the function with the path to your directory
rename_files_in_directory("./")
\end{lstlisting}
\paragraph{Setting tiles names in constants file}
After choosing tiles we are going to use we modify constants.hpp file, namespace textures and add our tiles tot textures array
\begin{lstlisting}[style=C++Style]
namespace textures {
static constexpr TextureInfo textures[] = {
{"resources/textures/background.jpg", "background"},
{"resources/textures/g1black.png", "block_black"},
{"resources/textures/g2blue.png", "block_blue"},
{"resources/textures/g3green.png", "block_green"},
{"resources/textures/g4purple.png", "block_purple"}
};
}
\end{lstlisting}
2023-08-08 22:05:55 +02:00
\section{Game Concept and Design}
2023-08-09 19:34:51 +02:00
\subsection{Game Concept}
A game concept encapsulates the core idea or essence of a game. It's the core vision that drives the entire game development process, giving direction to the gameplay and user experience. In match-three games, the primary concept is to align three or more similar game elements in a row or column to achieve points.
\paragraph{Our concept}
In order to benchmark our game engine we are going to focus on simplicity and rudimentary features of match-three games. We are going to implement a game that while offers only elementary features can still be called a match-three game and can be won or lost
\subsection{Game Design}
Game design describes how a game should be structured and played. It's the process of deciding game rules, creating levels, setting challenges, and determining how players interact with the game. While the game concept is the overarching idea, game design provides the detailed blueprint. In match-three games factors such as how new elements are introduced, the complexity of levels, the scoring system and win/fail condistions are all vital components of the design.
\subsubsection{Our design}
\paragraph{Scoring system}
Let's devise a scoring system for a match-three game with increasing difficulty levels. We will also differentiate the scores based on matching 3, 4, or 5 tiles. \\
First, let's determine the scores for each matching set:
\begin{enumerate}
\item Match 3 tiles = 10 points
\item Match 4 tiles = 20 points
\item Match 5 tiles = 40 points
\end{enumerate}
When devising the point system for matching sets in the game, there are several considerations we kept in mind:
\newpage
\paragraph{Progressive Increase}
We wanted the points to represent a clear progression, making matches of larger sets more valuable, incentivizing players to aim for them. \\
3-tile matches are the baseline, so they were assigned a modest 10 points. \\
4-tile matches are rarer and more difficult to create than 3-tile matches, so they're assigned 20 points, doubling the value from the 3-tile matches. \\
5-tile matches are even rarer, so they were given a point value that's a bit more than the sum of 3-tile and 4-tile matches, settling at 40 points. \\
\paragraph{Simple numbers}
Using round numbers like 10, 20, and 35 makes it easy for players to quickly understand and calculate their scores. Complexity can deter casual gamers, and match-three games are typically aimed at a wide audience, including those who may prefer simpler mechanics.
2023-08-09 19:34:51 +02:00
\paragraph{Winning}
Given these scores, let's decide the target scores for each difficulty level. We'll set these target scores based on an estimated number of matches a player might make in a given game, we will create Easy, Normal and Hard levels
\begin{itemize}
\item Easy Level:
\begin{itemize}
\item Target: 400 points
\item This might involve roughly 40 matches 3 tiles, or a combination of fewer 4 and 5 tile matches. This offers the player plenty of room for errors and learning the game mechanics.
\end{itemize}
\item Normal Level:
\begin{itemize}
\item Target: 600 points
\item For this target, the player might need to make 60 matches of 3 tiles, which will not be possible since we set up the limit of matches to 40 or a combination of fewer 4 and 5 tile matches, which will force the player to use bigger matches. This requires the player to make more strategic matches and utilize power-ups or special moves (if any).
\end{itemize}
\item Hard Level:
\begin{itemize}
\item Target: 800 points
\item Achieving this score might involve 80 matches of 3 tiles, or a combination of fewer 4 and 5 tile matches. With our limit of matches set up to 40 will force the player to keep the average matching to at least 20 points per match. This level is challenging and will likely require the player to plan moves carefully and maximize opportunities to match 4 or 5 tiles for higher scores.
\end{itemize}
\end{itemize}
\paragraph{Losing}
The game is lost whenever player reaches 40 turns, this forces the player to act under limited moveset and ensures that the game offers a challenge \\
Number 40 was chosen based on the similar choice in professional match-three games, it is the same number used for matching 5 tiles, it offers gameplay that is not too short neither too long and it is a "nice" number, even, round and with many divisors
\newpage
\paragraph{Setting up values in constants file}
In order to implement this design in our game engine we need to again modify constants.hpp file in following way:
\begin{lstlisting}[style=C++Style]
struct DifficultySettings {
const std::string name;
const int points;
const int limit;
const std::vector<int> matchScores;
DifficultySettings(const std::string& n, int p, int l, const std::vector<int>& scores)
: name(n), points(p), limit(l), matchScores(scores) {}
};
namespace difficulty {
std::vector<DifficultySettings> settings = {
DifficultySettings("easy", 400, 40, {10, 20, 40}),
DifficultySettings("normal", 600, 40, {10, 20, 40}),
DifficultySettings("hard", 80, 40, {10, 20, 40})
};
}
\end{lstlisting}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Core Mechanics and Gameplay}
2023-08-09 19:34:51 +02:00
Game utilizes full functionality of our engine, player needs to match three or more gems, chaining matches or achieving higher combos grants the player higher score
2023-08-09 19:34:51 +02:00
\paragraph{Generating levels}
We used python script to first generate levels user can choose from in order to simplify our work so we do not need to create the levels on our own \\
Later in a course of our game the game engine handles generating new random blocks when old ones are replaced
2023-08-09 19:44:00 +02:00
\subsection{User Interface and User Experience}
The Heads-Up Display is minimalistic, showcasing only essential elements, score and moves left.
2023-08-09 19:34:51 +02:00
\paragraph{Choosing level and difficulty}
User can choose both level and difficulty on the menu screen using WSAD keys
2023-08-09 19:34:51 +02:00
\begin{figure}[htp]
\centering
2023-08-09 19:34:51 +02:00
\begin{minipage}{0.32\textwidth}
\centering
\includegraphics[scale=0.40]{images/easy.png}
\caption{UI when choosing easy level}
\label{fig:easy}
\end{minipage}
\hfill
\begin{minipage}{0.32\textwidth}
\centering
\includegraphics[scale=0.40]{images/normal.png}
\caption{UI when choosing normal level} % Adjusted the caption
\label{fig:normal}
\end{minipage}
\hfill
\begin{minipage}{0.32\textwidth}
\centering
\includegraphics[scale=0.40]{images/hard.png}
\caption{UI when choosing hard level} % Adjusted the caption
\label{fig:hard}
\end{minipage}
2023-08-09 19:34:51 +02:00
\end{figure}
2023-08-09 19:34:51 +02:00
\begin{figure}[H]
\centering
\includegraphics[scale=1.00]{images/scoreMoves.png}
\caption{Score and moves left text}
\label{}
\end{figure}
2023-08-09 19:34:51 +02:00
\begin{figure}[H]
\centering
\includegraphics[scale=1.00]{images/redMoves.png}
\caption{Score and moves left text, when there are less than 10 moves left}
\label{}
\end{figure}
\paragraph{Losing and winning}
Whenever player loses (reaches max number of turns) or wins (reaches target points), game stops, clears the level and displays a message
\begin{figure}[htp]
\centering
\includegraphics[scale=0.50]{images/losing.png}
\caption{Game message when lost}
\label{}
\end{figure}
2023-08-09 19:34:51 +02:00
\begin{figure}[htp]
\centering
\includegraphics[scale=0.50]{images/win.png}
\caption{Game message when won}
\label{}
\end{figure}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Advantages of a Custom-built Engine}
2023-08-09 19:34:51 +02:00
\begin{itemize}
\item Optimized Performance: Tailored specifically for a Match Three game, the engine could be highly optimized for this genre, reducing unnecessary overheads. Using OpenGL and plain C++ also added to engine speed
2023-08-09 19:34:51 +02:00
\item Direct Control: Having complete control over engine we could introduce, modify, or remove features as needed.
\end{itemize}
2023-08-09 19:34:51 +02:00
We were able to create a game using our engine, which means that the goal of this entire thesis was reached.
2023-08-09 19:34:51 +02:00
2023-08-08 22:05:55 +02:00
\chapter{Future Work and Enhancements}
\section{Potential Extensions to the Engine}
While we were able to produce a game using our engine, it still has a potential to grow more and introduce many new features.
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Enhanced Graphics and Physics}
2023-08-09 19:34:51 +02:00
Enhancing the visual and interactive experience:
2023-08-09 19:34:51 +02:00
\begin{itemize}
\item Ray Tracing: Using ray tracing can provide more realistic lighting, shadows, and reflections, increasing visual depth with little cost to an engine user.
2023-08-09 19:34:51 +02:00
\item Advanced Particle Systems: Enhancing particle effects can create more immersive environments, from weather effects to more dynamic game elements.
2023-08-09 19:34:51 +02:00
\item Physics Enhancements: More advanced physics simulations can improve feel to game interactions, from simple collisions to complex motion dynamics.
\end{itemize}
2023-08-08 22:05:55 +02:00
\subsection{Adaptive Difficulty}
Machine learning can analyze player performance and adjust game difficulty in real-time, ensuring a balanced challenge.
2023-08-09 19:34:51 +02:00
\subsection{Real-time Multiplayer}
Adding capabilities for online multiplayer modes can increase engagement, replayability and competetivnes.
2023-08-09 19:34:51 +02:00
\subsection{More platforms}
Engine could be adapted to work under mobile systems (Android and IOs) and consoles (Xbox, PlayStation and Switch)
2023-08-09 19:34:51 +02:00
As can be seen there are still a lot of features that can be added to our engine to make it even more useful
2023-08-09 19:34:51 +02:00
2023-08-08 22:05:55 +02:00
\chapter{Conclusion}
\section{Summary of Achievements}
In this section we will look back at our project and describe our achievments.
\subsection{Multiplatform Support}
2023-08-09 19:34:51 +02:00
\begin{itemize}
\item OS Versality: We successfully developed a game engine that operates across Windows, Mac, and GNU/Linux platforms, addressing the title of this thesis.
2023-08-09 19:34:51 +02:00
\item Addressed Platform-specific Challenges: Overcame technical challenges associated with different operating systems, ensuring a consistent user experience.
\end{itemize}
2023-08-09 19:34:51 +02:00
\subsection{Library Integrations}
We managed to itegrate libraries such as GLFW, glad, freetype, stb\_image, and ft2build, all within one game engine
2023-08-09 19:34:51 +02:00
\begin{itemize}
\item GLFW/glad: easying the process of using OpenGL
\item freetype/ft2build: allowing for rendering text within game
\item stb\_image: for ease of importing image assets into game engine
\end{itemize}
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Robust Game Mechanics}
2023-08-09 19:34:51 +02:00
\begin{itemize}
\item Match Three Logic: Core match three logic was implemented, matching 3 or more tiles, chain reactions and limited moves
2023-08-09 19:34:51 +02:00
\item Event Management: The game responds successfuly to user interactions
\end{itemize}
2023-08-09 19:34:51 +02:00
\subsection{Practical usage}
We managed to create a fully functional match-three game, using only our game engine and royalty free assets.
2023-08-09 19:34:51 +02:00
\subsection{Contributions to the Field of Game Development}
Our engine allows aspiring game developers to create their own match three games, and engine developers to learn from it and expand it.
2023-08-09 19:34:51 +02:00
In conclusion, we managed to accomplish all of the goals we set for this thesis, our engine successfuly produces a game for all three operating systems we were aiming for.
2023-08-09 19:34:51 +02:00
2023-08-08 22:05:55 +02:00
\section{Reflection on the Development Process}
Creating this game engine was a long process, it took almost a year to bring it to the state it is now in, during this time several reflections came about.
2023-08-09 19:34:51 +02:00
2023-08-09 19:44:00 +02:00
\subsection{Embracing the Multiplatform Challenge}
In order to overcome differences for different operating system, a lot of time was put into choosing correct graphical api and libraries that could work on Windows, GNU/Linux and MacOS. This proved crucial when later developing the engine as this issue did not came back and I could focus on creating the engine itself.
2023-08-09 19:34:51 +02:00
\subsection{Library Integrations}
Using multiple different libraries and integrating them with our game engine was a challenge, thanks to existing solutions like learnopengl repository which already overcame those difficulties and KDevelop easy approach to external libraries it was possible to implement all of libraries within our game engine.
2023-08-08 22:05:55 +02:00
\subsection{Time management}
2023-08-28 22:27:07 +02:00
Lastly, probably the biggest challenge was managing time for this thesis. Finishing it required a lot of determination, setting barriers and working every day to ensure that the thesis is finished on time. Thankfully past experiences helped in guiding through this task that could be compared to colossus.
2023-08-08 22:05:55 +02:00
2022-08-23 14:19:26 +02:00
\bibliography{references}
2022-08-23 14:19:26 +02:00
2022-08-16 19:29:30 +02:00
\end{document}