Best basic practices concerning performance and code readability clarity/simplicity?

ex.: entityData.getComponent() seems more cumbersome (but will not fail) than ent.get(SomeComponent.class) that is restricted/limited (and may not have some component), so having good queries is a must. right?

Any other things we should be aware concerning the basics of ZayES usage? so I wont find out later that it would be excellent if I recode my project?

Should the integration with Zay-ES be 100% or only what we intend to save/load? like in we would have a component storing a reference to an initialization object (see below), that would store everything else we do not care on saving on a savegame, what would be a bridge between ES way and old inherited java way (or am I being too imaginative? :))

Another thing, I am storing spatial reference on a component, therefore the entity must be initialized whenever the game is loaded to prepare such reference. Should I be using something else like a spatial Id and bring the spatial from a list, or that is too much?

1 Like

Then your design is broken. The spatial is not a game object.

Basically, all things that are “game object” should be in the ES. Spatials are not game objects.

If you want to think of it this way, imagine that you are showing a 2D and 3D view of your game. To some players your game will look like a 2D isometric style game with sprites and tiles. To some other player, the game will be fully 3D. To some other player, it will be a top-down 2D view with just little icons.

What state would there be in common to all of these views? That’s the game state. That’s what the ES manages. It doesn’t matter if you are saving them or not.

The rest seems to fall out naturally from this, to me.

You use entity.get() in your normal systems because those normal systems are just grabbing the entities they are interested in. If that system is asking for components other than its interest for some rarer use-case, then obviously it goes back to the ES for that (EntityData.getComponent()) because that’s an “out of band” style request.

In general, that’s what makes the code more readable. Your eye sees myEntity.get(…) and your brain automatically knows this is a system watched/managed component. Your eye sees entityData.getComponent(id, …) and knows this is an unmanaged call that you do rarely. The latter case should also be gnawing at you that the closer you are to “Spatial country” the more likely it is that something is wrong.

It may also be helpful to think in terms of client-server usage even if you aren’t networked. myEntity.get(SomeClass) is going to be a local call in immediately available data. EntityData.getComponent(id, SomeClass) is very likely going to be a full round trip TCP request to the server.

If you are already on the server then no worries. If you are in the visualization layer then something may be wrong in the design. It happens but it’s very rare.

Either way, spatials should not be in components. Spatials “do stuff”. Components are 100000000% data only.

2 Likes

so, a “to the point” would be like:

ES stores location and rotation,

the ES GameSystem does the game logic reading the Entities, completely unaware of whatever way it is going to be displayed,

a JME app state, will also read the Entities and will simply position that specific visualization of them in for ex. 3D.

addint to that, an ES PhysicsSystem would take care of collision events preparing the Entities to the GameSystem do more things.

despite cool, do you think I can skip all this learning curve going straight here?:

in a sense that, is it ensuring (to a point) that I will have to put the things in the right place, and that place is clearly recognizable?

1 Like

SiO2 has some nice utilities for doing common ES boiler plate. So it’s worth using. It won’t force you to do the right things if you don’t already know them.

The rest of your post sounds about right. There are a few examples you can look at… I think I’ve linked them in your threads before.

2 Likes

Or the “View System” does that. Systems can access Spatials, you only must not store them as components.
Take a look at SiO2’s EntityContainer for that. I have a class ModelContainer extends EntityContainer<Spatial>, which handles all models.

Does getComponent also break the thread-safety introduced by applyChanges?

Edit: And to avoid a large count of EntitySets when I have “OR” Conditions for the Components.
I don’t know yet if it’s the best solution because buffs are almost static and a giant switch-case could also do, but:
When I have a BuffComponent, the same entity has multiple components constructing the effect, like a IncreaseHealthComponent or an IncreaseRegenerationComponent.

Now I keep one EntitySet of BuffComponents and use getComponent to find out which Components are part of this buff, since the classes of getEntities are AND’ed instead of OR’ed.

2 Likes

Yes and no. getComponent() is thread safe but it’s also bypassing the nice “static view” you get from Entity. Meaning, getComponent() will show new values right away where as Entity.get() only shows you the value at your last applyChanges(). For consistency, this is sometimes nice since if you grab component A then component B… then component A again, you are guaranteed that it is the same A as before. That may not be true with getComponent() in a multithreaded system since some other thread may have changed it in the mean time.

I usually do buff components on separate buff entities. So an IncreaseHealth component would be a component on an entity that points to the entity to which it applies (either in the IncreaseHealth component or some separate component). Then the system that manages the health value for all entities would also have the entity set of IncreateHealth entities and apply those as necessary.

…given that Regeneration is related to adjusting the health component then that may also be managed as part of general health.

Alternately, in my general approach, both of those buffs would have been handled by the same IncreaseHealth component. (Depending on what you mean by that.) With one having a longer Decay component (regeneration) and the other being an instant decay (only lives one frame… so does its increase and goes away).

That’s the beauty of the buff entities. You can make them last as long as the buff entity and each can have its own decay. You can also have as many IncreaseHealth at once as you like.

Edit: as a general approach, you want to stop thinking of things in terms of “how do this thing with one entity” and think of ways to do it for all entities matching a certain set of components. If you can restructure your thinking/approach to handle “all of a thing” then you are in line with the more data-oriented approach where an ES really shines.

3 Likes

Sure, but I’d have multiple components on that buff entity (when a buff component is like a “Spell/Aura Id” and has multiple effects).

Another case which might precise that: I have my “Enemy Tags” which can consist of a mix of the following: Health, Energy/Mana and Name.

Since those are already used Components, I just have a component which specifies that this entity should have a tag.
The Problem now is, I’d need three sets: ShowTag and Health, ShowTag and Energy, ShowTag and Name, so I am notified about changes. Or I could have a Set of ShowTag and use getComponent.
This however leads to the problem that I am never notified about a changing Health/Energy.

What I wanted to ask: Is there a good way to have “OR” Conditions for getEntities? Maybe using the ComponentFilter and it’s OrFilter? With a custom “ClassFilter”?

Edit: Especially since I am having an EntityContainer for the Tag System it would be hard to have multiple EntitySets actually

2 Likes

NO. there is no OR for “this component or that component”. It couldn’t possible work. Just don’t do it. And Entity IS its components. Not some random set of maybe this or maybe that or maybe that components. It’s duck but might be a horse or might be a cow. No. Just don’t.

What are “enemy tags”? It’s probably entirely appropriate to have three different entity sets.

Maybe. So what?

1 Like

initially, thinking like classes works concerning cohesion, I thought I should put the most related variables inside a single component, but ES seems to go quite away from that (specifically speaking).

the buff, would be like an “item” where its inventory would be the final entity npc/player.
each effect would be also like an “item” where its inventory would be the buff.

I mean, later on, when you understand you should not be bound to one buff and one effect of that same kind (may be), and believes your game can provide a balanced overpowered experience to players, all that code/logic will be already ready just to be simply further used (even if initially you will only allow one buff ‘of a kind’ per entity, and one effect per buff).

I ended puting a single long on a component, that is the last simulation update time. that helps me avoiding copying all other values of another component it could be at, just to update that single long…

so my “simple” interactive entities, now have about 7 components, and some of them have a single variable.

my fear is overbloating it of components, concerning memory and seek speed (to find/bring components) for a query. Only time may tell I guess.

1 Like

I don’t understand what this long is for. I’ve never needed it. Explain, please.

If a particular system only needs A and B. And another system only needs A and C. You haven’t “saved” anything if you combine B and C because now both systems have copies of crud they don’t really need. It’s counterintuitive but sometimes our “This is more efficient in OOP” tendencies are often exactly backwards/wrong.

That being said, if it’s always the case that you have multiple systems that use A, B, and C and no systems that use B and C separately then they should probably be just one component.

Don’t break your components up based on OOP ideas. Break them up based on what systems need or produce.

3 Likes

The thing is, separate buff entities is actually way EASIER than trying to do it the other way. It simplifies a ton of stuff and frees you from a hundred threading concerns.

2 Likes

It’s the thing floating above their head showing health, energy or the name.
Some enemies might not have a Mana/EnergyComponent since they run without Mana. The Tag System needs to handle that.

Now the regular AND approach would only yield entities which have mana/energy or else they aren’t part of my EntitySet/Triggering updateObject.

Now if I could run my code each frame and use getComponent for things like EnergyComponent, but that sucks considering the benefits of EntitySet.

So as an animal analogy: An animal is feedable but depending on it’s components (MeatEater vs Vegetarian), you have to treat it differently.

Well the question was whether an effect is a seperate entity (as @teique) describes or rather a component on the buff entity. But I guess that is not the problem, it’s just important that it’s not part of the player entity (which would be the oop way).

I don’t know, maybe I also misunderstood getEntities: Is it only triggered when one of the specified components got changed and are those the only ones accessible using entity.get() or not? (if not, my concern would actually be no concern)

1 Like

I have to create a hierarchy based on last activation time, so I store such time at a single component.

my hierarchy also considers parents and childs, but that is handled by another component, and the activation time also modifies the sort order of the nested childs within that parent/child hierarchy/tree.

mmm… that may make things more simple indeed.

any good/simple way to “update” only a single variable of components? that difficulty is the main reason I am overbloating it with components…

so, when creating a new component, copy of the currently one being worked on, I do like this:

new CompKindA(compCurrent, null, 100, null);

so, that constructor will call a private copy() that will clone all the compCurrent values into the new “this” one initially. Further on, the 2nd parameter “null” was to be a Boolean, the 4th one was to be a Float, and both will be skipped, because that constructor expects only true or false or floating for these parameters, so such copied fields from compCurrent will remain unchanged.

that helps me avoiding creating loads of constructors for each specific case, but prevents me from using nulls (unless I actually do accept them to be set as null on such constructor, and then I will not be able to skip, so I guess that may confuse me later because I am using a workaround).

1 Like

Two things:
A) You can do a full copy and then modify those values after the constructor. That however introduces setters which you shouldn’t have for your component, mh.

B) On the other hand I think having more than 5 values for a component means you are about to structure your components wrong since they should be the smallest possible core thing.
It leans towards the aggregation you’d have in OOP things.

1 Like

I could use set(){...;return this;} if I conditioned it with a boolean lock as being the last thing set, just to dynamically prevent wrong usages, but that would still be flow dependent. would make things a lot easier tho, and would require me to not forget using the lock, or to add a check ensuring it is locked.

another fancy option is that I could use an Object… array, and pass an enum (as field Id) and a value, like:
new CompKindA(compCurrent, EField.Time, 948736476, EField.Name, "Abc", ...)
I would be adding minimal logic to the component, what I think is ok.
EDIT: the “problem” here may be: what will be required to be set toguether, could have to be documented…

On the other hand, I can convert 5 components into 1, and will result in 6 fields on it :), but not using the above, I would still have to create many constructors, mainly to set single fields, and always passing the current to copy from.
For some reason I dont like loads of constructors, they look messy, but seems the only option if we want to avoid the before mentioned options.

EDIT: I dont know yet if I will try the Enum one, just to avoid having to remember to lock it, and the checks etc… and the plethora of constructors.

if someone else has other tips concerning this, I would like to hear too! :slight_smile:

1 Like

The Enum thing is also quite verbose and adds just another class (or enum) per constructor. Not so good.
Though I partially like the idea.
Another good way is at least to break the constructor call into multiple lines, mhh.
A more native way would be adding multiple constructors for each possible combination of Fields.

I guess it’s better to just live with those constructors and keep in mind to keep components simple. Sometimes you could also go with a “lookup table”, mh.

1 Like

the enum thing would allow me to actually have only a single contructor for every possible possibility, like in:
new CompKindA(CompKindA compCurrent, Object... aobj){...
the “problem” is maintaining two names (the field variable and its related enum), whenever I think it should be called differently. Well, I can always write a sed script to automate that anyway.
EDIT: Another big problem is, there is no type check, will exception only dinamically

that is what scare everything possible it can out of me :scream:

this could be interesting, could you exemplify?

1 Like

Which leads us to automatic macros and code generation? :smiley:
like new CompKindA(myField=true, otherField=null);

I guess it’s not what you expected, it’s just the regular:

CompKindA newComp = new CompKindA(
   oldComp.field1,
   oldComp.field2,
   oldComp.field3
);

It’s more of an optical trick, however it’s no real problem to have such constructors, it’s also only an optical problem, if we are honest :wink:

And it might be annoying to write, but you could even copy&paste there. That way you atleast think about the parameters of the new component, so you don’t forget some field which could happen in your enum approach

2 Likes

mmm, this sounds quite cool hehe, but would break on the IDE right?

I actually meant somethign simple like
at field declaration bMyField; //#syncFieldFrom bMyField (I prepend b on booleans)
EDIT: after the comment, if not matching the field var name, would trigger the external update.
at enum bMyField, //#syncFieldTo
EDIT: the full code refactoring would be matching like EField.bMyField and case bMyField:

put it on a loop and see the automatic sync while I am editing on eclipse, I am almost coding just to see how fun it is… :slight_smile:
EDIT: not needed, it is easy to maintain as long we refactor at the constructor like
case bMyField: this.bMyField=(Boolean)objValue;break;
I wont forget to sync even in a hurry.

1 Like

Here is an example of how I usually handle updating one element of an immutable component:

2 Likes