On the Bubble

Creating a custom engine for a Monkey Ball-like game

About this project

On the Bubble is an ambitious student project where 12 developers and I worked on creating a Monkey Ball-inspired game. We built the game from scratch using a custom engine, which uses path tracing for stunning visuals and custom physics for precise and responsive gameplay. Additionally, we implemented a user-friendly level editor, allowing players to seamlessly create and share their own levels.

During this project, I primarily focused on implementing engine functionality, including GameObject management, serialization, file IO for both Windows and PS5 using a cross-platform API and much more. All of my big contributions to the project will be listed below.

The game has been released on Steam as an Early Access title. During this phase, we actively gather feedback from our community to improve and refine the game. Our goal is to deliver a fun and polished experience for the full release.

This is a student project made during my 3rd year at Breda University of Applied Sciences.

My contributions to the project

During this project, I mostly worked on developing the engine. My biggest contributions will be listed below:
GameObject management: Implementing the systems required for creating, removing and updating game objects. These GameObjects are stored in the ObjectManager, which updates all objects in the level and manages their lifetime. Game objects are the base class for all objects in the engine that can be used in the game. All game objects can have models, which, when loaded, are properly represented in the renderer as well.
Custom iterators: In order to make looping over all GameObject easy, a custom iterator has been implemented. The iterator is similar in usage to the one used by the Standard Library functions and is compatible with range-based for loops.
Pointer stability:  While developing the GameObject manager, pointer stability was taken into account. GameObjects are stored in a vector using unique pointers. 
Custom serialization/deserialization:  A custom serialization/deserialization system has been implemented. Level saving and loading is used in the game for switching between the levels, as well as saving and loading levels in the editor. I've spent a lot of thought and work into making the serialization/deserialization API as easy to use. The result of this is that only one function is required (per object type) to serialize/deserialize specific variables.
Some more details about the serialization/deserialization system can be seen below.
Saving and loading variables using one function: Variables can easily be marked as serializable using one function call. This function handles both the saving and loading of the data when a level is either saved or loaded from disk. The decision was made to handle both this functionality in one function in order to make it as easy as possible to save and load data. It also turned into a great learning opportunity, as I learned more about template metaprogramming and creating an easy-to-use serializer.
Factory class: When deserializing, objects are created through a factory class. Object types are stored as a string in the save file, which is used to create the correct object type during the deserialization phase. The object factory uses the string to create a new object pointer, which is then stored in the ObjectManager.
Great integration into GameObject systems: The serialization/deserialization system was implemented at the same time as the GameObject management, which means that the two systems work very well together.
FileIO: I implemented the functionality for creating, deleting, reading and writing files on both Windows and PS5.
Cross-platform API: Since Windows and the PS5 use different APIs for manipulating files, two different implementations are required. I implemented the cross-platform API, as well as the different implementations for both platforms. The cross-platform API allows users to use the same functions to manipulate files on both platforms. This was a great learning opportunity, as I learned how to work with the file system on PS5. 
Level files saved to common directory: On Windows, level files are saved to the common Appdata directory. This is especially useful during Windows development, as it allows for easy sharing of level save files between different configurations. 
Level management and loading: I implemented a system for loading and switching between levels. This system also loads assets at the start of the level and unloads unused assets to minimize memory usage. At the start of each level, required models are loaded in parallel using a parallel execution policy.
Automatic unloading of unused assets: When switching between levels, the level system compares the required assets between the two levels and check what assets need to be loaded and which ones can be unloaded. This is done to minimize the memory usage over time.
Multithreaded model loading: Models are loaded in parallel using multiple threads during level loading. This is done using a parallel execution policy. In order to prevent race conditions, lock guards were used.
Undo and Redo functionality for the level editor:   I implemented the undo and redo functionality for the level editor, enabling users to undo and redo actions such as adding, removing, and translating objects. The implementation for this was done using the Command pattern. The decision to implement undo-redo functionality was made after we received feedback from playtesters that implementing such a system would greatly improve the quality and usability of the level editor. Although I had not previously implemented such a sytem, I saw it as a great learning opportunity.
Custom stack: To store the commands, I developed a custom stack data structure. A stack data structure was used for its Last-In-First-Out functionality. This means that the most recent command (the last one to be pushed onto the stack) is the first to be undone, which is exactly what we wanted in an undo operation. It also helps with managing the command history, as a stack data structure allows the system to easily track and manage the sequence of operations by the user, which is essential for an undo-redo system. 
Actions for Adding and Removing entities: T he undo-redo system supports three types of actions: adding objects, removing objects, and translating objects. When a user adds an object to the level, the action can be undone, removing the object, and redone, making the object reappear again in the level. Similarly, when a user removes an object, the action can be undone, making the object reappear in the level, and redone, removing the object again. For translating objects, users can undo changes to an object's position and rotation, reverting to the previous translation, and redo the changes, applying them again.
Leaderboards using Steamworks:  I added support for online leaderboards using the Steamworks API.
Uploading scores: Whenever a user finishes a campaign level, their score is automatically uploaded to the leaderboard specific to that level.
Downloading scores: At the end of each level, the top three scores, along with five leaderboard entries around the player's rank, are downloaded and displayed to the user.
More details about these contributions can be found below.
Launch parameters:  I added support for launch parameters, which are used during debugging, as well as by our automatic CI/CD system. 
Easy to use:   Users can easily check if a launch command is passed into the program by using the Contains function. If the launch command is found, values can be retrieved using the GetInt , GetFloat and GetString functions. These functions return the values belonging to the launch commands (if they can be found). 
Cross-platform:   Launch parameters work on both Windows and the PS5. 
Gameplay trailer:  I created the gameplay trailer, which is featured at the top of the page. The trailer was made using the HitFilm video editing software.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Quick overview

Project Type:  Custom Game Engine
Platform:  Windows (Steam), PS5
Tools:  C++
Role in Team:  Engine Programmer and Lead
Project Duration:  1 year
Release Date:  Q2 2024
Team size:  13
Role in Team:  Engine programmer and Lead