This is one of my favorite projects.
In my second year of DAE, I learned how to create a component-based 2D game engine. The engine was implemented using various programming patterns based on Game Programming Patterns by Robert Nystrom.
Much of the attention was spent on following the Core Guidelines of modern C++, such as using C++ concepts and using smart pointers to assist you in using RAII.
You can find some of the used patterns/systems below.
GameObjects can be added to a scene and have a parent/child hierarchy (uses Dirty Flag pattern for when the positon changes).
The GameObjects can receive 1 instance of every type of component. This is convenient when trying to acquire a certain component. All you need is the type.
Components should only handle their one task and nothing more. Following this creates a clear and readable structure.
In my InputManager, I use an exceptional case of std::shared_ptr for following reasons:
The InputManager and the Controllers own commands and I often want the same command bound to keyboard AND Controller. A std::shared_ptr establishes ownership of the Command to both. This is important because say a controller get disconnected, the keyboard should still own the Command.
As a little experiment, I have specific containers for commands that execute when the input type changes from keyboard to controller and vice versa. This is very convenient for when you want to change UI based on the current input type.
You can see the result on the right.
I created my own Box Collison component. It keeps track of all the current active CollisionComponents. You can call CheckCollision(), returning the GameObject which it collided with. Additional info about which side is colliding is stored in a byte as flags. This is handy when checking for walls and platforms. The component requires a CollisionTag that the user of the engine can decide on their own.
For Audio, I use the Service Locator Pattern. It makes sure that you can swap an audio service according to your choice. In the engine, the standerd implemented audio service uses the SDLMixer features. I also use a Log-decorator in Debug mode to log every call that gets made to the AudioService. Decoraters are wrapped around the chosen implementation to provide additional behaviour.
Observer Pattern
Data Locality
Dirty Flag
Singleton
(Game Loop)
(Update Method)