R-Type
Introduction
R-Type is a C++ game project involving Game Engine and Advanced networking concepts. The project was developed in a team of 5 people. The game is a 2D side-scrolling shoot-em-up game. The player controls a spaceship and must fight against enemies and bosses. The player can also play with other players in a cooperative mode. The game is based on the original R-Type game released in 1987.
The main goal of the project was to develop a game engine based on an ECS architecture in order to be able to easily add new features to the game. The game engine was developed using the SFML library. Thanks to the modularity of the engine, we were able to support multiple graphic libraries (SFML, SDL, Vulkan, etc.) and multiple operating systems (Windows, Linux, MacOS).
The focusing track of the project was the networking part. The goal was to develop a server that could handle multiple games at the same time with custom a custom architecture and robustness. The server was developed using the Boost.Asio library.
Architecture
Game Engine
The game engine is based on an ECS architecture. The engine is composed of 3 main parts:
- The Core part is the core of the engine. It contains the main classes of the engine such as the
Engine
class, theScene
class, theEntity
class, theComponent
class, etc. - The Systems part contains the different systems of the engine. A system is a class that is responsible for updating the components of a specific type. For example, the
SpriteSystem
is responsible for updating theSpriteComponent
of each entity. - The Components part contains the different components of the engine. A component is a class that contains data and is attached to an entity. For example, the
SpriteComponent
contains the sprite of an entity. - The Scenes part contains the different scenes of the engine. A scene is a class that contains entities and systems. For example, the
GameScene
contains the entities and systems of the game. - The Graphics part contains the different graphic libraries of the engine. A graphic library is a class that is responsible for rendering the entities of a scene. For example, the
SFMLGraphics
is responsible for rendering the entities of a scene using the SFML library.
Server
To handle multiple games at the same time we thought about 2 different architectures:
- The Client-Hosted architecture is the architecture where a client can host a game and other clients can join the game. The host is responsible for the game logic and the clients are responsible for the rendering. This architecture is the easiest to implement, so it is not robust because if the host leaves the game, the server closes. See figure below.
- The Server-Hosted architecture is the architecture where a main server hosted somewhere is responsible for provisioning games lobby and games servers. This architecture is more robust because if a game server crashes, the main server can restart it, no one must be connected to the game server for it to work and we can add more game servers if needed. See figure below.
We decided to implement the Server-Hosted architecture because it is more robust and it is more interesting to implement. Also we implemented a large panel of features:
- The server can handle multiple games at the same time.
- The server can handle multiple players in a game.
- The server uses a custom packet protocol to communicate with the clients.
- The server communicates with the clients using TCP and UDP.
- Packets are compressed using LZ4 to reduce the bandwidth.
- Packets are serialized and follow a Little Endian byte order.
CI/CD
We used GitHub Actions to lint the code and build the project (for each supported platforms) on each pull request and merge to the main
branch.
This workflow is composed of 3 jobs:
- The Lint job is responsible for linting the code using clang-tidy.
- The Build job is responsible for building the project using CMake and Ninja for each supported platforms (Windows, Linux).
- The Create Release job is responsible for creating a release on GitHub containing the build artifacts (binaries, libraries, etc.).
- The Mirror job is responsible for mirroring the repository to Epitech's Organization.