Advertisement

Game Engine Architecture best practice

Started by March 22, 2024 11:44 AM
3 comments, last by KielanT 9 months ago

Hi,

I am creating a new engine (for fun and experimental projects). I find engine architecture really interesting. In my last engine I had the main App be created as a singleton and I had my Renderer wrapped in a static class so that it could be called globally.

In my new engine I want to find a different approach. I have not created the app as a singleton but I have created my renderer as a singleton. My current problem (Sorry it took this long to get here) is in my app class I have a bool appIsRunning, which I need to set to false inside my window class, the window class is inside the App, I know I could just make app a singleton but I am wondering if there are any better alternatives.

Is bad to have a singleton inside a singleton? (App and renderer)

Is my previous engine approach better?

Are there good examples and different approaches I can use to further my learning and architecture knowledge?

I do have access to the Game Engine Architecture book.

Thanks

None

Just had an idea, would implementing an event system be better?

None

Advertisement

KielanT said:
Is bad to have a singleton inside a singleton? (App and renderer)

It is bad to have a singleton, period. If you are looking for “best practices”, here is the first one: Don't make things singleton. Singleton leads to all kind of design-issues:

You can't control which systems can access what other systems, so naturally everything will end up being coupled to every other thing (having explicit control over what systems can use, by having to make references available, is a very good thing).

Also, you might think that certain things only exist once, but that is not a guarantee. I made the same mistake when designing my (editor) GUI-library. Obviously, I thought, there is only one GUI, so I can make it static. Well, once I added ingame-GUI rendering, using the same library, now I needed two instances of the GUI classes. Weeks down the train, refactoring it, when in reality, it should have always been non-static/singleton.
The same applies to renderer. You can easily have multiple of those. My own renderer is split into many parts, and most of the can be (and are) instantiated and specialized for many different cases. There is one core-renderer class which practically, at the moment, only exist once (the one that wraps the underlying API functionality), but this is also coincidential - when dealing with multi-threaded rendering, or rendering to different Windows, you could easily have more than one of those.

So my advice: Don't be lazy and make everything statically accessible. Think about how systems can communicate, and what systems can access. You also don't have to pass down 10 parameters to every class, for every system you have - you can group modules into “context” objects. For my engine, there is one “BaseContext”, which contains everything. It is mostly given to very top-level APIs for extending the engines core functionality, and is contained of multiplex sub-contexts that group more specialized functionality (like Render, Input, Gui, …). The more levels I go down, the more specialized contexts or objects I pass. And besides, this whole thing is also mostly because I don't have any dependency injection - this would be preferred to even that approach.

@Juliean Thank you this is useful. It has changed my way of thinking and approaching my engine.

None

This topic is closed to new replies.

Advertisement