Building a Game Engine - 2 | Organization
Structure
src/
├ main.cpp
├ game/
│ └ game.cpp
├ engine/
│ ├ window.cpp
│ ├ renderer.cpp
│ ├ errors.cpp
│ └ graphics/
│ ├ shader.cpp
│ ├ texture.cpp
│ ├ index_buffer.cpp
│ ├ vertex_buffer.cpp
│ └ vertex_buffer_layout.cpp
└ vendor/
├ glm/
├ imgui/
└ stb_image/
I immediately wanted to organize the code I already had from my crude implementation made earlier.
This involved moving the shader
, texture
, index_buffer
, vertex_buffer
, vertex_buffer_layout
, and
renderer
files into a dedicated engine/
folder. I then further put these files, aside from renderer
into a subsequent graphics/
folder.
Then I moved some of the window initialization and operational stuff into a new window
file within
engine/
and the OpenGL error checking from renderer
to a separate error
file.
Finally, I created a game/
folder which will contain the source code for the game. For now, I put
some placeholder game
files which provide some very basic functionality.
Abstraction
int main(void) {
Window::init("Test");
auto& window = Window::get_instance();
Renderer::init();
auto& render = Renderer::get_instance();
Game::init();
auto& game = Game::get_instance();
while (!window.should_close()) {
window.poll_events();
game.update();
renderer.render();
window.swap_buffers();
}
Game::shutdown();
Renderer::shutdown();
Window::shutdown();
return 0;
}
This is what the main function now looks like. Under the context of this project, I feel like the main function should only really initialize major components, make them run, and handle shutdown. Now this current implementation doesn’t strictly follow this as it’s also responsible for the main update and render loop but this may change in the future.
Another note to make is how I implemented the window, renderer, and game objects. First is the fact that they’re objects in the first place. I wanted to ensure that only one instance of a window, renderer, and game could be made and any attempt to do so multiple times would fail.
The current approach involves defining classes for these three components but removing the constructors
and destructors and using static calls like ::init()
to create the global static objects and handle
other tasks. So essentially singletons. These objects are defined in each of the components primary
translation unit to keep them from being globally accessible.
As shown by the main function, I’m calling a ::get_instance()
function that returns a reference to the
global static object. This allows me to use them more like objects than like a bunch of static function
calls. Through some experimentation, there are some potential annoyances that mainly revolve around the
redundancy of using a class for these representations and trying to figure out the implementation details
so I’m gonna experiment around with this abstraction.
Next
Probably figuring out how I’m gonna handle rendering. Preferably in a way that allows for parallelism. We’ll see ig.