About Real Engine
Introduction
The library is split up in multiple sub libraries. There is RealCore, the base of the library, containing your sound, input,
scene logic, game object and component logic and the transform component, which is in charge of everything position,
rotation and scale wise. Then there is the Real2D and Real3D parts, each in charge of rendering, the 2D engine uses SDL and
a SDL renderer, while the 3D engine uses Vulkan for rendering and SDL for the window. Both have unique components.
Real Core
As mentioned before, RealCore contains everything shared between Real2D and Real3D. It also employs numerous patterns, such as the
component pattern, command pattern, service locator, dirty flag, and more. We will discuss these later. Let's look at some key aspects of RealCore:
The InputManager class handles all input. The user first creates an input map, which they fill with actions. These actions contain
an input type (controller, mouse, or keyboard), the input key, and key state (up, down, or pressed). These parameters are then linked to a custom
command derived from either the GameObjectCommand class or the Command class.
The Locator class currently only contains an audio service. Here, the user can control everything related to audio. When a sound
needs to be loaded, the class pushes an event onto a queue. When the time comes to play the sound, it loads and plays the sound on a
different thread for maximum efficiency.
The GameObject class is the core component. This class can be filled with individual components, either engine-defined or user-defined. There are
two types: the DrawableComponent class, with a render function, and the regular Component class. Game objects can also
be bound to other game objects through a parent-child relationship. They are bound to the scene by default.
Scenes are managed through the SceneManager class, where scenes can be created, loaded, and exited. A specific
input map can also be bound to a scene.
RealCore also includes an Observer and Subject class, a GameTime class, a Logger class, and various other utilities.
Real 2D
Real2D, as the name implies, is a 2D engine that uses SDL to render and create the window. As previously mentioned, it is built upon RealCore.
Its engine class derives from the BaseEngine class located in RealCore. The engine comes with several components, including the ColliderComponent,
which handles collision; TextComponent, which renders text to the screen; SpriteComponent, which renders animated sprites; and
TextureComponent, which renders still textures. The TextComponent also requires the TextureComponent to render its text. Fonts, textures,
and sprites can be loaded through the ResourceManager. The 2D renderer also supports ImGui.
Real 3D
As the name implies, this is a 3D engine. I won't go into too much detail here, as you can find all about it on the following page
here. In short, the engine is a Vulkan abstraction, and the window
is again generated by SDL. It comes with several handy components and its own ContentManager class. This time, the project is created
with CMake.
Patterns Used
You probably already know that this engine consists of multiple patterns. Let's go over the most important ones.
The Observer pattern is used extensively throughout the engine. A small example is in the SceneManager class,
where it notifies all listeners when a scene gets loaded or exited. The subject can pass multiple arguments through its
notify function that notifies the observer.
If you want to learn more about this pattern, you can read about it
here.
Another pattern used is the Command pattern. The engine uses it in combination with input. In RealEngine, there are two variants:
GameObjectCommand, which has a GameObject* parameter, and the regular Command. When the correct combination of input key, type, and state have
been met, the InputManager will call the Execute() function of the command, which will execute the user-defined logic.
If you want to learn more about this pattern, you can read about it
here.
The most important pattern of them all is the Component pattern. This pattern follows the rule of composition over inheritance.
It decouples the game objects significantly. Instead of having each game object derive from a class with some logic, a component can be added through, let's say, GameObject::AddComponent<T>(),
along with some arguments. The component has some virtual functions like update, render, start, kill, and so on. Plus, it has a reference to its owner,
so it can call other components of said owner.
If you want to learn more about this pattern, you can read about it
here.
There are a few more patterns that need to be mentioned, such as
the service locator,
the singleton,
the dirty flag,
the game loop, of course,
and the event queue.
Future Work
I would love to keep working on this project. It has taught me a lot about template programming, smart pointers, and writing cleaner and more manageable code.
Especially in the 3D part, there is much room for improvement. A level editor could also be a future project of mine. Only time will tell.