I've been using the ECS pattern for a while now and, as the complexity of the game increased, I started having issues with the timing of the entity initialisation and destruction code.
I'll use the Physics as the example, but the same principles apply to most other aspects as well.
First a few definitions:
- PhysicsModule - the low level physics system (usually an external library like box2d) - has no idea about ECS
- PhysicsSystem - an ECS system - works as an iterface between the low-level module and the rest of the ECS
- EntityWorld - the object responsible for creating and destroying entities and associating them to Systems
For example, a typical scenario goes like this:
- 1) An Entity gets created from external data (Transform, ShapeData, CollidableData)
- 2) The data has to be registered with the PhysicsModule (using ShapeData and CollidableData)
- 3) Every frame, the PhysicsSystem asks the PhysicsModule for the position of the related object and updates the Transform. Repeat for a while.
- 4) The Entity gets destroyed in another System far a way
- 5) The PhysicsModule needs to be told to remove the associated physics object
The problematic steps are 2) and 5). I can think of two ways of handling this.
Have the PhysicsSystem handle the lifecycle.
Pros:
- the logic is encapsulated in one System
Cons:
- the PhysicsSystem needs to know about the init data (ShapeData, CollidableData) which is useless after the initial registration with the PhysicsModule
- the EntityWorld has to keep track which entities were freshly added or removed from a system to notify it about them
- the destruction of the entity has to be delayed in order for its components to still be accessible in the same frame
- this approach often causes long chains of events (spanning a couple of frames) which are difficult to follow
In order to make this work, the main loop always ends up being a complete mess to make sure particular inits, updates and destroys are done in the correct order.
Have one place for all the init and destruction code.
Pros:
- the init data is not used beyond the initial registration
- the init / destroy code is in one place
- all the cleanup can be done in one frame in the correct order
Cons:
- this essentially becomes the God Object and knows about everything in the game
- the whole thing probably becomes very cluttered with all the possible permutations
- the destruction of the entity has to be delayed in order for its components to still be accessible in the same frame
At the moment my game evolved into the first solution and I'm having quite a few issues so I'm thinking about trying another approach. The second one I mentioned seems a bit better, but it does involve a God Object and from my experience that is a bad way of doing things.
Also, I took a look at various ECS implementations and noticed that some of them have methods to notify systems that entities were added/removed to them and some of them don't - so there's obviously various approaches to this.
My question is - Is there another way of handling Entity Initialisation and Destruction without resorting to either the God Object or the God Loop?