Is it possible to attach multiple components of the same type to an entity?
SCENARIO 1 (entity with multiple textures)
In modern OpenGL, array textures has taken over the old texture atlases. This "forces" you to use textures of same size.
If you imagine a game like Terraria, a world made up with 16x16 pixel tiles. But there are also plenty of sprites of different sizes. You would need to attach multiple Texture/Sprite/Appearance components to an entity, to make it look bigger. For example a door need an upper and lower part, both with an offset in position.
SCENARIO 2 (entity with multiple shapes)
When doing collision detection, you usually attach Shape/Hitbox components to an entity.
To describe more complex geometry of an entity's body, you need multiple shapes. For example a square and a circle with an offset in position.
These two scenarios would fit perfectly with how systems operate on components, for example a renderer just wants to iterate over the Texture components, not over entities.
I did find some similar problems other programmers had (https://github.com/alecmce/xember/issues/12 and https://github.com/sschmid/Entitas-CSharp/issues/56), but I'm not sure if those were really "component" material.
I've been struggling with this for a week now, trying to find a good solution.
At first I just had a std::vector
In my current solution, for example; A main entity (the door) which has Physics and Sheet component. Plus two "entities" (the upper and lower part of the door) which only has a Texture component each. The sheet component is a std::vector with references to its childrens. The main entity doesnt contain any texture information at all.
The entity count will raise quickly with the current solution.
Is this something that could be added to this framework? Or do you have a better solution to my problem?
Great job on this framework. Also, I would love to put my project in the readme, once its done!
Is it possible to attach multiple components of the same type to an entity?
No. By design. Internal data structures of a registry (namely sparse set) aren't intended for that use. EnTT won't support such a feature any time soon, I'm sorry.
SCENARIO 1 [...] For example a door need an upper and lower part, both with an offset in position.
You can just make a door component that refers to other entities and describe the upper and lower parts through those entities.
Next question on the line: what if not all the doors are multi parts? Define two components, SimpleDoor and MultiPartsDoor and assign the right component to the right entity. A simple door can become a multi parts one (remove a component, assign the other one, creates two entities and that's all). Similarly, when a multi parts door becomes a simple door you can destroy the two children and then change the component assigned to their parent.
SCENARIO 2 [...] For example a square and a circle with an offset in position.
As above, I would do it through children. Put the parent entity in the children and performs collision using the latter ones. Only in case of collision detected you have to walk to the parent and thus you can incur in cache misses. In all the other cases, parents are ignored.
The entity count will raise quickly with the current solution.
Define _raise_. Unless you have some 100k entities so far, it cannot be a problem. A game that uses 10/20/30k entities at runtime isn't a big problem and pretty common.
As a rule of thumb, it's important to avoid cache misses but you cannot avoid them all. Therefore don't point out a pattern of use because it seems it increases cache misses. If you have drops in frame rate, measure and find the real bottleneck. ;-)
Is this something that could be added to this framework? Or do you have a better solution to my problem?
Nothing to add to support multiple components, it doesn't worth it. Problems it pulls in are much more than those it solves from my point of view.
I'm willing to help you if you need. Feel free to contact me whenever you want. ;-)
Thank you so much! I'll be back :)
Great job on this framework. Also, I would love to put my project in the readme, once its done!
Thank you. I hope you are enjoying EnTT.
Let me know when your project is done and we can add it to the readme. Is it online or a private one?
Side note: I'd close the issue if it's fine for you.
There is no chance we can add multi components support to EnTT without rewriting it, so it doesn't worth it to keep the issue open.
Any problem your side?
Currently, its private :)
Close it, but where do I ask questions, if needed? IRC?
Options are:
Continue writing here: a closed issue can still be used to discuss, even though it doesn't end in new features or bug fixing.
Open new issues with proper titles for different questions: they can help future users if you got an answer.
Mail: you find mine in the profile section.
Thank you for asking.
Set aside the fact that you cannot have it in EnTT, if was you I would go for a pure ECS approach and stay away from multiple components on a single entity.
It's _easier_ to some extent for programmers, less machinery in general, but it pulls in a lot of new and more complex problems.
My two cents. Parent-child relationships can easily solve it in a more elegant and consistent way. As long as you define correctly your components, you rarely have to walk to the parents and thus unlikely you'll have problems.
Let's consider for a moment you can add two components of the same type to your door, name it Part.
How would you differentiate between upper and lower in case you need it? A flag? Deducing it from the position? What else?
What if your door can have three parts or only one part in the future? I can already imagine the amount of if it brings in your codebase.
Instead, if you define good components and the right amount of systems, it will be both fast and easy to extend in future (at least in my experience).
Hi, I have a question about "creating a component that uses other entities as children".
How would you model something like a variable cluster grenade, where a single grenade would be able to spawn a variable amount of timed cluster explosions?
The children, aka, the explosions would all have their own single timed effect, etc, but what about the parent?
If I wanted a cluster bomb that could have between five and ten explosions, would I need to create five components for that?
As in, ClusterOfFive, ClusterOfSix [...] ?
Or Something like
ClusterBomb with a std::vector of explosion entities?
But using vectors would make the need of child entities less important, wouldn't it?
I'm new to this, so the analyzation paralysis I have makes it harder to reason even though it feels like this should be an easy thing...lol.
So I'm asking here.
@Lovewyrm is #253 what you're looking for? It seems to me the problem is exactly the same.
All what you need is to create other entities and attach them a component like this to create an implicit list of children:
struct hierarchy {
entt::entity parent;
entt::entity next;
entt::entity prev;
};
Then assign to the parent a component that points to the first child:
struct children {
entt::entity first;
};
Avoid using types that allocate dynamically in your components (eg the std::vector).
I'm writing a post on this topic with an example _made with EnTT_. I'll publish it here when ready. :+1:
Parent-child relationships can easily solve it in a more elegant and consistent way.
Its similar to relational databases. For example, I could do something like this in Postgres:
CREATE TABLE foo (
id SERIAL PRIMARY KEY,
frobs INTEGER[]
);
Eg:
SELECT * FROM foo;
id | frobs
----+-----
0 | {1, 2, 3}
1 | {}
2 | {2, 4}
That is, a foo contains an array of frob's. This would be like adding multiple frob components to a single foo entity.
Alternatively, you could do something like this:
CREATE TABLE foo (
id SERIAL PRIMARY KEY
);
CREATE TABLE frob (
foo_id INTEGER REFERENCES foo (id),
value INTEGER
);
Eg:
SELECT * FROM foo;
id
----
0
1
2
SELECT * FROM frob;
foo_id | value
--------+--------
0 | 1
0 | 2
0 | 3
2 | 2
2 | 4
So, in EnTT, you could think of each entity as a relation/row and each component as a column. Then, instead of having an array of components attached to an entity, you could instead have multiple entities with a "foregin key" to the parent entity.
Just like in SQL, using arrays is more compact and simple, but normalising has its own advantage: you can now iterate through frob separately from foo (the parent entities), which might save you from accessing data which you don't need saving on cache misses, but also its separation of concerns. At the expense of having to walk the tree sometimes.
Anyway, my point is ECS and relational databases have a lot in common and sometimes thinking about your entity/component model in terms of relational data/SQL can be useful. I've heard ECS be described as a subset of relational that is optimised for a particular segment of use cases. I think I agree.
Anyway, my point is ECS and relational databases have a lot in common and sometimes thinking about your entity/component model in terms of relational data/SQL can be useful. I've heard ECS be described as a subset of relational that is optimised for a particular segment of use cases. I think I agree.
I gave a talk about this recently. I don't pretend to know all the implications, but definitely some interesting ideas to explore.
@bbi-yggy Oh, that's cool! Thanks for sharing. I love your slides too :heart:
@bbi-yggy the only suggestion I can give you is that the slides let suppose there is an equivalence between a _join_ and _whatever_ but this isn't the case.
Eg when you want to iterate A and B with archetypes, you find instances in archetype A/B as well as A/B/C or A/B/D and so on, you don't have a _single table_ with all the instances. Similarly with sparse sets where this separation is even clearer.
The parallelism ECS vs SQL is a good one but do not make the mistake of thinking that there is a 1-to-1 equivalence between tables and whatever implementation you decide to use because this isn't the case.
@bbi-yggy the only suggestion I can give you is that the slides let suppose there is an equivalence between a _join_ and _whatever_ but this isn't the case.
Eg when you want to iterate A and B with archetypes, you find instances in archetype A/B as well as A/B/C or A/B/D and so on, you don't have a _single table_ with all the instances. Similarly with sparse sets where this separation is even clearer.The parallelism ECS vs SQL is a good one but do not make the mistake of thinking that there is a 1-to-1 equivalence between tables and whatever implementation you decide to use because this isn't the case.
There is a 1-to-1 _logical_ equivalence between ECS and (a subset of) SQL, but you are absolutely right this may not be mirrored in the implementation. A relational database is a logical abstraction for data manipulation, with a ton of underlying complexity to optimize and scale the implementation. What is a "single table" when you consider paging, sharding, memory-caching, etc? I don't know a lot about how modern relational databases work, but I bet if I learned more it would give me ideas for ECS optimizations.
Regarding my discussion of the join logic, you are right that I make it look like there's a pre-joined table ready to go with just the results of the join. I should include more archetypes in the example, as you suggest. For now I've added a note to the Unity Archetypes slide.
Most helpful comment
Its similar to relational databases. For example, I could do something like this in Postgres:
Eg:
That is, a
foocontains an array offrob's. This would be like adding multiplefrobcomponents to a singlefooentity.Alternatively, you could do something like this:
Eg:
So, in EnTT, you could think of each entity as a relation/row and each component as a column. Then, instead of having an array of components attached to an entity, you could instead have multiple entities with a "foregin key" to the parent entity.
Just like in SQL, using arrays is more compact and simple, but normalising has its own advantage: you can now iterate through
frobseparately fromfoo(the parent entities), which might save you from accessing data which you don't need saving on cache misses, but also its separation of concerns. At the expense of having to walk the tree sometimes.Anyway, my point is ECS and relational databases have a lot in common and sometimes thinking about your entity/component model in terms of relational data/SQL can be useful. I've heard ECS be described as a subset of relational that is optimised for a particular segment of use cases. I think I agree.