Am I on the right track regarding architecture?

Hi there

I’m a newcomer to Unreal Engine. I come from an angular / vue / java / k8s background with the occasional dabbling in Unity and its C# flavor.

I’m now doing a tiny (in terms of requirements) game in ue, and after some progress, I have some thoughts and ideas about architecture and wanted to challange that, so here I am.

Since it’s a “simple” one-level game, and since I have no experience, I’ve opted for a blueprint approach with the option to do come cpp if it’s actually necessary. I have no cpp experience at all and iteration speed seems great with BP.

After some initial progress, I noticed a trend of mine to go for an event based architecture, with the occasional direct interface calls. This felt natural to me, as I can keep blueprints and responsibilities separate this way and coupling somewhat low.

For example I have a “CinematicsManager” blueprint that listens to certain event dispatchers disables split screen, plays cutscenes, re-enables split screen and notifies whomever is interested when the cutscene is done.

Since the play through the level can be thought of as a state machine, or a pre-determined series of quests, I’m planning to maintain that state also in a dedicated blueprint that listens to whatever events needed and emits to whomever necessary (e.g. cutscene manager).

And so on.

While this seems somewhat concise and clean for now, from experience I know that such an approach, if done to the extreme, can lead to dev confusion, since it becomes less and less clear which event triggers what and you get event-spaghetti.

So my first question would be what your thoughts and experiences on this are, if I’m on the right track but should keep stuff in mind, or I should opt for something else entirely.

My second question: Since Listeners on Event dispatchers need a reference to that actor, I have now a bunch of empty blueprint actors in the level that are just there, so I can pass in references over the editor where needed. This is somewhat similar to how I did it in Unity, but I wonder if that’s good practice in Unreal too, or if I’m biased here.

The main approach I use is interface/direct calls throughout my gameplay.

For example: Players can’t go without weapons and that is a clear interface call. Players can interact with objects - interface call. Players can enter vehicles - interface call.

Everything internal - direct call. For example calls between components in the same object or between the object and its components. This object is “This Object” because of its components.

I only use events when I need to reverse dependency or I need to create a one-way dependency between interconnected architectural layers.

For example: Actor (Gameplay Layer)->Widget (UI Layer) - The Widget receives a reference to the actor it needs to show info about and subscribes to all needed actor events. Tomorrow I can remove/delete the UI and nuke it out of the game and the rest is still intact.

The same approach I apply to each system I want to be able to remove without affecting the game - managers, quest systems. Non-essential parts that can be removed (on a dedicated server for example) and the game would still play the same.

I never have empty blueprints in the level. Unlike Unity in Unreal there are plenty of objects that are always present on the level - controllers, game state/game mode, player state, even the level can contain code so no need for empty objects really.

P.S.
Blueprints are perfectly fine. I am yet to find system that that is impossible to do with BP. I’ll admit some things are not exposed to BPs, and yes C++ is way more performant, and yes data traversal and math are a painful to look at. But then - no compile time - worth it!

I’d try a GameInstanceSubsystem and implement a simple messaging bus where actors can register / unregister themselves. This way the sender only needs to dispatch an event package and the listeners can handle it without either side knowing about each other.

Thanks. So global scoped systems go in gamemode/state and level scoped into the level BP instead of empty blueprints. that’s the fine that many systems all live in the same blueprint?

Thanks, that sounds interesting. Didnt stumble upon this yet.