So, EntityManager.CreateArchetype() returns an EntityArchetype.
EntityManager.CreateEntity() can take an EntityArchetype argument. Because of the nature of ECS, one can assume that CreateEntity() will often be called from Systems.
So my question is: How should a System get access to the EntityArchetype they need to pass into CreateEntity()?
How do you personally solve this? Are you storing your EntityArchetypes in a collection somewhere, which can be accessed by Systems when they need an archetype variable?
Please share your approach if youād like, and thanks!
What if you need that archetype in another system? Did you never want to make a database of them?
Yeah, but then you have to pass in that long list of components every time. Thatās like building a gameobject up from scratch in the before days, instead of using prefabs.
Maybe Iām thinking about this wrong- is that what youāve been doing every time you create an entity (passing in a set of component types)?
I believe I understand why you think this, and I respect it. Would you mind going into more detail about why you consider that bad design?
Am I correct to assume youād prefer the following model: instead of multiple systems creating the same entity type, those systems would add a component tag to an entity. That tag would then be picked up by a later system, which would actually create the entity in question, and remove the tag.
@tertle is most likely refer to Single Responsibility Principle.
For which is expected, there is only one place in whole program, that creates entity with given archetype.
In the past (and in other ECS engines) Iāve seen that āone placeā be Utility functions. Those could take the form of a factory, or just be explicit, individual functions to create each entity type. Multiple systems could call these Utility functions as needed to create a new entity.
Iāve never heard of the single responsibility principle being interpreted to mean that only one system should ever āhave a needā to create a given entity type. Iām very interested in the idea, and how tertle may have worked it into his system order.
Thereās a real-world case Iām curios to see how it handles, involving a need to spawn multiple entities at once which work together to function as one contextual āthingā in the project.
I hope none of this is coming off as argumentative or debating, as Iām genuinely curious of your design here.
Iām a bit busy and Iāll write a bit more later, but pretty much Iāve found a lot of issues arise with the deferred nature of EntityCommandBuffer if you create and destroy entities or components from different systems.
These issues often pop up at a later, unexpected time when you add a new system and the order of your systems change, so Iāve found a lot of pain can be avoided by just not doing it.
I had this same question here and it was tertle that helped me out as well lol
What ive been doing is just creating a static class with a bunch of ComponentType[ ] that can be used in CreateEntity(). ECS will try to find that archetype if it already exists and provide it to you. You dont want to store EntityArchetypes as they are specific to each EntityManager. Its better to just always refer back to the array of ComponentTypes and let the EM do the heavy lifting on CreateManager.
That looks great. Two questions, if you have time:
This looks like you might be accessing static data from inside Jobs. While there is no explicit check against this, Unity has stated in multiple places that they strongly advise against doing it.
Iāve been therefore avoiding it, even if cases where it seemed logically fine (like reading static readonly data). Hard to imagine that causing race conditions, but Iām just trying to follow Unityās guidelines- maybe they know something I donāt.
ā¦Iām realizing I may be taking this more strictly than others. There are even cases in the Unity sample projects where they follow this same pattern (though those also make heavy use of [Inject], so itās hard to know how closely they match the current direction). Are you just not concerned about it?
How many Entity Managers do you find yourself typically using in a project?
So you wouldnt do something like CreateEntity(ECSArchetypeComponents.SomeListOfStaticComponents) inside a job function. Instead when you create the job you pass in the required data you need like so.
public struct CreateSomeEntityJob : IJob
{
public EntityArchetype MyJobArchetype;
[ReadOnly] public EntityCommandBuffer ecb;
public void Execute()
{
for (int i = 0; i < 100; i++)
{
ecb.CreateEntity(MyJobArchetype);
}
}
}
So you dont want to use static data INSIDE of the jobs but rather pass copies of that data to the job when you construct it.
There should be on EntityManager per World. So how ever many worlds you have is however many EMās you should have. If you are doing mainly main thread work using the EM is fine but for anything job related you should really use EntityComandBuffers. Or alternatively Tertle has some solutions that reduce the use of EM and ECB.
Also just to renote, I usually override the OnCreateManager method in the component systems and I use it like such
If another system wants that archetype they can simply use EntityManager.CreateArchetype(ECSArcheTypes.SomeArchetypeComponentList) and the EM will give back the same archetype
This is just a solution ive found that works for me seeing how my game im refactoring is pretty small. So having 20-30 componentType[ ] isnt that big of a deal for me. Maybe the factory route is better for your solution or maybe something else.
And if a Job canāt know ahead of time which type it might spawn, I suppose you could just pass in a lookup table in the form of a Native collection. (Please let me know if you donāt like this pattern).
I mean it really depends on what your use case is but that would work for this case. Not sure what the āstandardā is for this type of stuff tho if thats specifically what you are looking for.