ECS and Screens

I’m working on a game with multiple stages or “screens.” Currently a screen manager handles the menus and game screens and the MonoGame.Extended.Entities ECS is being created in the first game screen. The game will change screens a limited number of times in sequential order: 1, 2, 3, 4, 5, 6, and then back to 1. (Note: I’m not using MonoGame.Extended.Screens, I’m using an XNA game state management project by Microsoft)

I’ve realized I have two options: Either 1) recreate an ECS inside each screen (but there’s probably no way to differentiate between the ECS/Systems/Components of previous screens)
or 2) Just have a single gameplay screen with one ECS and write logic in the systems and components to handle creating different “screen” entities based on what gameplay is supposed to be happening. Because after all an ECS is just data+logic, right?

I’m thinking option 2 makes much more sense. Any advice? Thanks!

(Using an ECS and screen manager is the obvious choice for avoiding hard to write and maintain spaghetti code and it has already made it light years easier to plan out a game, so I know there’s probably an easy answer here that I just have to find, probably by just trying to code it.)

Option 1 makes more sense IMO and IME.

(but there’s probably no way to differentiate between the ECS/Systems/Components of previous screens)

Then the ECS you’re using is trash or you’re overestimating the costs of setup/storage for your ECS.

An ECS isn’t everything, it’s just one part of a bigger picture. Making it more than that turns into a hammer-nail problem.

I would really like to use the first option if possible. I’m using the MonoGame.Extended.Entities ECS. Do you know how to differentiate them? Because currently two different ECS instantiated in two different screen classes end up scanning, detecting, and processing the same systems. I must be missing something.

Hi there, I’m trying to do the same thing in my project. I’m currently passing entity manager as a parameter when initializing screen, don’t have another solution yet. :pensive:

Sorry to rise my own question in this topic, but it seems to be connected:

I’m having issue with LoadContent of DrawableGameComponent (Screen): it is sad, that LoadContent is called on main.Initialize(), rather than main.LoadContent(), for that reason I cannot figure out how to use spriteBatch properly, so I’ve set it static (( Doesn’t look very nice though. Any ideas how to use single spriteBatch?

I’ve read about passing it as parameter, but it is what can be called ‘spaghetti’, passing spriteBatch through every instance of Screen or Entity (((
Passing it through ServiceContainer, I need to initialize screens in main.LoadContent().

Don’t use the Scan of EntityComponentSystem - instead manually construct everything (or do your own more limited/directed scan, ie. only scan types in a target namespace/etc).

I have stopped using components completely, in favor of multiple lists of objects. I have a single SpriteBatch.Begin() and End().
There is no issue with passing SpriteBatch around, It is a simple pointer on the stack. (only an extra 32/64 bits) per call. Not Spaghetti.The CPU to GPU benefits(single transfer v multiple transfers) far outweigh the alternatives. I only use multiple draw calls when order or transparency are involved.

Is it bad for performance to use ServiceContainer?

There is a strange thing happening, that ScreenGameComponent is initiating before main game initiation, at the same time EntityComponentSystem is initiating after main game, though both of them inherit DrawableGameComponent & initialize method looks pretty much the same. So it is not possible to access spriteBatch properly through ServiceContainer, because it is null each time.

Would you recommend to create my implementation to change scenes/screens of game (using list probably)?


I just wanted to let you know that I’m currently rewriting the ECS in MonoGame.Extended. The current version has a lot of shortcomings (as you’ve discovered).

We’re getting rid of Scan method completely. It causes more problems than it solves. We’re making it easier to inject dependencies into your systems (because they are just plain old classes). We’re removing the limitations around components (because they can also be just plain old classes). There’s also lots of performance and API improvements.

If you want to follow along with development I’ll be posting about it on my patreon page fairly often.

1 Like