#SnakeECS : An entity component system
75 messages · Page 1 of 1 (latest)
I noticed in yours you have to specify the component types up front. It can be done without, at the cost of making destruction of entities tricky.
template <class Component>
std::vector<Component> components;
is magic perfectly normal but super neat.
Interesting idea, how would I approach identifying that component without any runtime cost? I use a type list currently so that i can index to the list at compile time
What do you mean by "identify"?
Assigning an index to the component based on what unique component type it is
Component A = 0, Component B = 1,… etc
I didn't look that closely to your system. I don't see why you would need that.
You could use the address of components 🤷
I'm not sure if you're familiar with the above code. The trick is that components<int> and components<double> are two independent vectors. There is no need to identify the type of a component, every component in components<Whatever> is a Whatever.
Yea i get that however there would be no efficient way to look up a component inside of a pool of components without iterating through each component and type checking
Assigning an id to the component allows for O(1) access
I think I know what you mean.
I used
template <class Component>
std::vector<std::size_t> ids;
where the implicit rule is that ids<Type>[i] is the id of components<Type>[i] for any i.
For lookup for a given ID you have to std::lower_bound (oh, they are also sorted) to find the index.
You can probably use std::unordered_map instead of a vector and get an official O(1).
Or maybe not 🤔
I'm not sure.
Having a list of components definitely makes everything easier.
That would work however that would require a runtime cost , i did something similar to that in a previous project but i found a bottleneck with this runtime checking so i shifted the identification to compile time instead via the type list
How do you find the location of a component at compile time?
Actually, you could do
template <class Component>
std::unordered_map<std::size_t, Component> components;
There you go, official O(1) lookup.
Check out the utils/type_list file, its not necessary finding location of the component but more so identifying the components at compile time (indexing them)
And yes i have a lookup table for components so looking up the LOCATION is already O(1)
_dense.push_back(std::pair<size_t, T>(id, elem));
Not moving smh
You can't use std::unique_ptr as a component 😛
Not sure why there are virtual functions involved in your sparse set.
The idea of interfacing the sparse set is so that you can pool all sparse sets of different components together
For example the component_pool
Hmm, yeah, when you put all your components in a single container you have to identify your type afterwards. I wanted to avoid that.
Though, disclaimer, I have no clue if any of my decisions were good or bad.
Avoiding that would not be so cache friendly unfortunately but i agree in the sense that it may look pointless at first, ill see what i can restructure to avoid the virtual overhead
You'd pool the components of entities together, right? Something like
C1E1, C2E1, C4E1, C2E2, C3E2, ...
The thing is, I'm not sure what exactly cache-friendly means here. You're not going to iterate over all components of an entity, you're just going to iterate over a set of components.
Yes sort of like a big table in memory
And since the set varies, there is no way to make it actually cache-friendly.
If I were to iterate over the C2 components in the above example, it would not be very cache-friendly. It's effectively random jumps, though maybe not completely random. At least it always goes forwards.
Well thats what the sparse set is for, the point of it is to reduce any gaps by having all these sets of components tightly packed reducing cache misses when iterating through them, your example assumes the components arent next to each other
Yes, that's what the order was supposed to express.
Maybe it looks more like
C1E1, C2E1, C2E2, C3E2, C4E1, ...
in your system?
Yes exactly
A vector
Or an unordered map
I used a vector, but in hindsight an unordered map would have been smarter.
I see, thats pretty much what im doing instead i have sparse_set<Type> lol
I wouldnt recommend a map since hash collisions can make iterating slow
And also maps dont typically use contiguous storage as their underlying structure
Something that didn't go as I thought is destructing entities. When an entity gets destroyed, so do its components, right? Well, I know that entity ID got destroyed, but I don't know what components it has. components doesn't help, that requires knowing the type of the components, which I don't. I ended up making std::vector<void(*)(std::size_t)> a component and it would carry an instance of
template <class Component>
void clean_up(std::size_t id) {
components<Component>.erase(id);
ids<Component>.erase(id);
}
for each component. It felt like huge overhead.
You have it easier, just go through the list of types and check.
Hmm i feel like you might need to restructure your code a little bit i dont think its a good approach to make that a component that should be a part of your system, but i dont have any context of your ecs so it may or may not be fine
It's part of the system, it's just a hidden component that the system gives each entity with one.
See thats kind of iffy, i dont think there should be a component that handles deleting components, that should be the concern of your world/manager/registry, can you shoot me the link to the ecs id like to take a look and see if I can spot a fix
i think toeger meant hooks. they are components related to entity lifetime that gets processed by system
flecs seems to implement this iirc
Whats the difference between hooks and just any other component? Both exist during or the lifetime of the entity no?
sorry lemme @ you
well hooks are basically functions
Ohhhh i see
typically the lifetime related hooks are built into the ecs
this is what toeger meant i believe
Thats an interesting idea im going to implement that i think
in other words they are callbacks associated with entity lifecycles
yeah it is exposed
you can see more here. it's a good resource
Interesting wow ill definitely look into it when i get home thanks for the idea
👍
https://github.com/Toeger/ecs/blob/master/entity_base.h?ts=4 line 35 is where it adds a component. It adds an id to ids, a component to components and through line 47 a remover for the component.
As for alternatives, besides just listing component types explicitly you could do so implicitly, collecting type-erased checkers for each type. However, that would mean that each component type adds an extra check to the destructor of every entity, which is probably worse.