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?
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.
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.
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.
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.
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
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.
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.
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.
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.
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)
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).
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.
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!
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.
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
Which leads us to automatic macros and code generation?
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
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
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âŚ
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.