Hello there,
I was wondering whether there is a way to get a view to iterate on all components deriving from a common interface ? Or if it would of interest for people to have it.
At some point I was looking for something like this:
registry.view< Interface >() that would return a view on all pools of components fulfilling the condition std::is_base_of
Thanks !
Components are intended to be simple POD structs with no inheritance or virtual functions. Using an interface class isn't really what this library is intended for.
Pools are accessed by type IDs so it's not possible to get the type of a pool. You can only get a pool that you know the type of. This would make it impossible to check std::is_base_of. This is similar to std::any. You can get the object stored in a std::any if you know it's type, but you can't get the type of the stored object. I didn't write the registry so I could be wrong.
This might have been possible using the old compile-time registry because all of the component types are known at compile time.
@Kerndog73 It looks like you wrote EnTT indeed!! ;-)
This might have been possible using the old compile-time registry because all of the component types are known at compile time.
Uhu, that annoying compile-time registry that was even slower than the runtime one? :-D
Did you prefer it? Honestly I'm much comfortable with the current implementation.
@FabienPean I'm sorry, this isn't possible. The registry doesn't know about the types of the pools it contains. It relies heavily on type erasure techniques and we cannot get a pool because _its original type T was derived from B_.
Moreover, view for multiple components return entities that have all those components and not entities that have one of the components. In other terms:
registry.view< Interface >() that would return a view on all pools of components fulfilling the condition std::is_base_of
::value == true
I'm not even sure what you would expect in this case.
That being said, @Kerndog73 pointed out an interesting thing. When it comes to working with ECS in general, you shouldn't put _logic_ in your components. This is more or less how Unity works and the most criticized aspect of their engine.
A slightly related thing I was thinking about is having inheritance in the sense that the data is compatible, eg, if I have A and B, where B is a superset of A (for simplicity of memory compatibility, lets assume that B is A with some extra data appended, so that a pointer to B could be cast to A but not the other way around — my actual use can assume this, at least).
The “issue” is that if I have a view that looks at A, it should also see the B’s.
The way I can accomplish this right now is to simply split A and B into two components, which might be the right thing to do anyway, but then instead of creating a view over B, I now need to make the view over A, B instead, which limits the options of view types I can use. There may not be a better way to solve this without sacrificing something elsewhere, so its fine if this is the necessary approach, but I’m wondering if there’s a better way?
@danielytics If I got what you mean, I think the problem is exactly the same: the registry doesn't know about the types it contains. So, when you ask for As and only for As, there is no chance to know that somewhere there exists a pool that contains some superset of A like B.
I confirm you that the _ECS way_ of doing this is to split B in two components, A and _what is not in A_, then iterate them as needed.
If you have any idea about how to implement what you are suggesting, feel free to contact me and we can try to analyze it together to see if it works. No idea my side unfortunately. It's pretty much (let me say) _out of the ECS path_ and it sounds like something we cannot easily implement in an ECS, it was EnTT or not.
Yes, I assumed that the registry would have no idea about this, I was more wondering if there’s a better approach other than what I mentioned to achieve this. I only asked because it was something I was thinking about and seemed sort-of related to this thread :)
I’ll think on it more and see. I need to actually start doing it in real code to determine if its a useful use case or not first, no point wasting energy on something that isn’t generally useful or has only niche use cases.
Thanks for your detailed response!
Hi all, thanks a lot for the elaborated replies. It seems that I did not quite grasp the entire concept of ECS... Need to check my use case again and see further.Then, I close the thread, and if I ever come up with a specific example, I will be back :)
You're welcome.
This isn't the first time someone comes up with questions about how to use an ECS in general and EnTT in particular.
Probably it's worth it creating a sort of Q/A repo for this, so as to help future readers.
Anyone interested in it?
@skypjack I've been thinking about what I said above some more and I've come to the conclusion that such a feature isn't needed because its really not a runtime thing -- at runtime, systems shouldn't know that this data is part of some kind of hierarchy, instead the systems should only know about the minimum thing they need to execute. Therefore, having them as separate components is absolutely the correct thing to do.
The hierarchical nature would exist in the tooling/editor, not in the code (or, if it does, only when the entity is given the components, possibly implemented using a prototype).
@danielytics It makes sense. Thank you for spending your time on this. Really appreciated.
Most helpful comment
You're welcome.
This isn't the first time someone comes up with questions about how to use an ECS in general and EnTT in particular.
Probably it's worth it creating a sort of Q/A repo for this, so as to help future readers.
Anyone interested in it?