Bad practice. Study the visual state from asteroid panic, then it get clear how to deal with spatials or maybe better name them visuals, as it is nothing more like @methusalah already pointed out very clearly. Your visual system do have a hash map <EntityId, Spatial>. Then on applyChanges you have acess to all removed, changed, added entites with what you keep your map up to date. On add instantiate a new spatial of a given model and add it to the node and hash map. On removed remove it from your node and hash map. On changed adjust the postion of your spatial. That’s it.
You really really need to let go of controls and all that OO stuff, as you do not need, you have systems for that. Behaviour? You guess it a system which do manipulate the Position component of your models.
But first don’t think in terms of OO. Don’t hold anything in spatials (this I had to learn the hard way, I suppose everybody need to learn this the hard way, before that you do not see the benefit not doing it).
public class EnergyBurstOnHPDepleted implements EntityComponent{}
This is used on the LifeCheckingAppState. If the Component “hitpoint” has value <=0 then the Entity gets removed, but this flag tells that the Entity should not just disappear, but also spawn a graphic effect.
The life system should not worry about the onDecayEffect. Because life system only worry about lifed entities and can’t handle all the effect, event, or behavior that may exist on decay.
Those are independant systems.
Maybe the life system could give the entity a Deceased component, before entity is removed?
Cool! How about this, then:
After that an entity has deceased, it needs to be processed by the DeathGraphicalSystem for showing the effect, and also by the ScoreSystem to increase the player score.
To avoid race condition where a Entity is removed before it gets processed by all systems, each system that is listening for the “deceased” flag then adds a new “boolean flag” like: GraphicalProcessed, ScoreProcessed etc. (which means that the system has processed the Entity)
Then finally a EntityDisposer system looks for entities with all these flags and removes them?
I’ve ran through that problems some time ago. The fact that a componen stores data it should not care about is bad. Entity system is strong because things are as much disconnected as possible.
If you have to come back to your decease component and add inside it more and more data each time you add a behavior is bad practice.
Your deceased component is only to flag the entity deceased. A DeceasedCleanerSystem will remove that entity at some point. Maybe the end of the tick? maybe 1 second? that up to you to choose. System that want to react to the deceased component will have to be called before that event.
Maybe just a matter of ordering your systems in the pipeline.
This needs to be stated. Sometimes, it’s still important to know what order your systems run in… or to have a fixed order in some cases. It’s always possible to design around this but the added complexity is generally not warranted.
Edit: in other words, it’s ok to have one or two systems that you know always run at the beginning of a ‘step’ and one or two that always run at the end. It avoids these ‘join’ type of components.
statemanager.attachAll(new LifeState(),
new GraphicalState(),
new ScoreState(),
new DestroyEntityState()
);
Then I’m guarranteed that the Entity will be processed by the states on this order?
And what if these states are stopped/resumed in bulk, for example when I go to the menu?
Hm in this case I would say that A needs to process before B is logic not data.
So an entity decayed event from the decaysystem to consume would be a acceptable solution.
Aka keep data in entities not logical dependencies.
Yes, but sometimes knowing the order can prevent these ‘purely conflation’ components from propagating. Yes, it’s a more correct design but often needlessly tedious.
I’m planning to test John Carmack’s suggestion to make Entity Data imutable, enqueuing the asked changes from systems, but appling them effectively only at the end of the tick.
how about that: add a decay comp to get ride of it. add new entity with an effect componnent, a position and a decay of 2 seconds. now your effect last 2 seconds and vanish. the main entity you want remove is removed and replaced by effect component.
I solved my destroied invaders that way. works as expected. hope my proposal is clear more or less.
It is also fun to see the progress, how initial problems most of us had changed to slightly different approaches. Like the explicit stuff about making sure to only have data inside the es, not logic via crude workarounds
I enjoy all those ES threads in this forum. I always learn something new which shows me over and over again the beauty of this approach. I’m very new to ES but it was love in the fist sight actually. I never was a OO speciallist my background is more plain C
A wiki would be greate but no clue how to contribute content to jme wiki (if it will be a jme wiki). I also would like to make / see some “beginners” page where you could just copy past and try out.
Or maybe some kind of ready to use components and systems? like the decay stuff? I need that one always any way. there are others I need always.
I admit that my vision is biased by the entity editor I’m working on. It imposes some rules, like being able to edit components using standard controls, or serialize them in JSon. This make it a little strict maybe.