Skip to main content
added 146 characters in body
Source Link
user321630
user321630

The way you have it now is, if you'll forgive me, about the most inefficient way I can imagine to do it for every kind of use case I can imagine. The problem there is that first you're dynamically-allocating every single component instance. That's often going to result in a loss of spatial locality between components. And then storing a separate container per entity which actually has its own size and capacity and pointer and dynamic allocations is also going to be quite a memory and performance overhead if you have a large, large number of entities. Lastly if you aren't storing components of a particular type contiguously in their own container, then that means when your system wants to fetch a list of components of a particular type (probably the most common query to an ECS), the ECS is going to have to iterate through every single entity in the entire scene that exists checking to see if it has that component (which involves potentially iterating through every single component in each entity).

I suspect this solution can be quite performant if you do it this way. TypicallyIt does involve hash lookups to get from a particular entity to a component of a specific type, but typically your most critical execution paths in an ECS involve plowing through all available components in a scene of a particular type without even going through the entities first, like your physics system might want to plow through all the motion components in the system to transform, or your rendering system might want to plow through all the sprites (in 2D) or meshes/model (in 3D) in the system to render (or if a spatial index is involved, some system might want to plow through those components to update the spatial index only for your rendering system to then use the spatial index to render the appropriate components in the screen/frustum). This solution allows that to be done by just sequentially iterating through the hash map (which tends to store elements contiguously) storing all components of a given type without any kind of traversal from entity to an associated component.

The way you have it now is, if you'll forgive me, about the most inefficient way I can imagine to do it for every kind of use case I can imagine. The problem there is that first you're dynamically-allocating every single component instance. That's often going to result in a loss of spatial locality between components. And then storing a separate container per entity which actually has its own size and capacity and pointer and dynamic allocations is also going to be quite a memory and performance overhead if you have a large, large number of entities. Lastly if you aren't storing components of a particular type contiguously in their own container, then that means when your system wants to fetch a list of components of a particular type (probably the most common query to an ECS), the ECS is going to have to iterate through every single entity in the entire scene that exists checking to see if it has that component.

I suspect this solution can be quite performant if you do it this way. Typically your most critical execution paths in an ECS involve plowing through all available components in a scene of a particular type, like your physics system might want to plow through all the motion components in the system to transform, or your rendering system might want to plow through all the sprites (in 2D) or meshes/model (in 3D) in the system to render (or if a spatial index is involved, some system might want to plow through those components to update the spatial index only for your rendering system to then use the spatial index to render the appropriate components in the screen/frustum). This solution allows that to be done by just sequentially iterating through the hash map (which tends to store elements contiguously) storing all components of a given type without any kind of traversal from entity to an associated component.

The way you have it now is, if you'll forgive me, about the most inefficient way I can imagine to do it for every kind of use case I can imagine. The problem there is that first you're dynamically-allocating every single component instance. That's often going to result in a loss of spatial locality between components. And then storing a separate container per entity which actually has its own size and capacity and pointer and dynamic allocations is also going to be quite a memory and performance overhead if you have a large, large number of entities. Lastly if you aren't storing components of a particular type contiguously in their own container, then that means when your system wants to fetch a list of components of a particular type (probably the most common query to an ECS), the ECS is going to have to iterate through every single entity in the entire scene that exists checking to see if it has that component (which involves potentially iterating through every single component in each entity).

I suspect this solution can be quite performant if you do it this way. It does involve hash lookups to get from a particular entity to a component of a specific type, but typically your most critical execution paths in an ECS involve plowing through all available components in a scene of a particular type without even going through the entities first, like your physics system might want to plow through all the motion components in the system to transform, or your rendering system might want to plow through all the sprites (in 2D) or meshes/model (in 3D) in the system to render (or if a spatial index is involved, some system might want to plow through those components to update the spatial index only for your rendering system to then use the spatial index to render the appropriate components in the screen/frustum). This solution allows that to be done by just sequentially iterating through the hash map (which tends to store elements contiguously) storing all components of a given type without any kind of traversal from entity to an associated component.

added 849 characters in body
Source Link
user321630
user321630

Each component type is stored in its own contiguous memory block as a VLS. There are no heap/storefree store allocations/deallocations on a per-component instance level (they are stored contiguously in an array that grows, similar to std::vector, and you can use that here, though it needs to behave like a free list with O(1) removals from the middle without invalidating any other indices).

Then you can store a polymorphic list of ComponentMap which actually stores each component subtype instance by value instead of storing BaseComponent* with dynamic allocations per component instance.

I suspect this solution can be quite performant if you do it this way. Typically your most critical execution paths in an ECS involve plowing through all available components in a scene of a particular type, like your physics system might want to plow through all the motion components in the system to transform, or your rendering system might want to plow through all the sprites (in 2D) or meshes/model (in 3D) in the system to render (or if a spatial index is involved, some system might want to plow through those components to update the spatial index only for your rendering system to then use the spatial index to render the appropriate components in the screen/frustum). This solution allows that to be done by just sequentially iterating through the hash map (which tends to store elements contiguously) storing all components of a given type without any kind of traversal from entity to an associated component.

Each component type is stored in its own contiguous memory block as a VLS. There are no heap/store allocations/deallocations on a per-component instance level (they are stored contiguously in an array that grows, similar to std::vector, and you can use that here, though it needs to behave like a free list with O(1) removals from the middle without invalidating any other indices).

Then you can store a polymorphic list of ComponentMap which actually stores each component subtype instance by value instead of storing BaseComponent* with dynamic allocations per component instance.

Each component type is stored in its own contiguous memory block as a VLS. There are no heap/free store allocations/deallocations on a per-component instance level (they are stored contiguously in an array that grows, similar to std::vector, and you can use that here, though it needs to behave like a free list with O(1) removals from the middle without invalidating any other indices).

Then you can store a polymorphic list of ComponentMap which actually stores each component subtype instance by value instead of storing BaseComponent* with dynamic allocations per component instance.

I suspect this solution can be quite performant if you do it this way. Typically your most critical execution paths in an ECS involve plowing through all available components in a scene of a particular type, like your physics system might want to plow through all the motion components in the system to transform, or your rendering system might want to plow through all the sprites (in 2D) or meshes/model (in 3D) in the system to render (or if a spatial index is involved, some system might want to plow through those components to update the spatial index only for your rendering system to then use the spatial index to render the appropriate components in the screen/frustum). This solution allows that to be done by just sequentially iterating through the hash map (which tends to store elements contiguously) storing all components of a given type without any kind of traversal from entity to an associated component.

deleted 24 characters in body
Source Link
user321630
user321630
class Entity
{
public:
    template <class T>
    T* get() const
    {
        for (size_t j=0; jauto <comp: components.size(); ++j)
        {
            T*auto ptr = dynamic_cast<T*>(components[j]comp);
            if (ptr) 
                return ptr;
        }
        return nullptr;
    }

private:
    vector<BaseComponent*> components;
};
class Entity
{
public:
    template <class T>
    T* get() const
    {
        for (size_t j=0; j < components.size(); ++j)
        {
            T* ptr = dynamic_cast<T*>(components[j]);
            if (ptr)
                return ptr;
        }
        return nullptr;
    }

private:
    vector<BaseComponent*> components;
};
class Entity
{
public:
    template <class T>
    T* get() const
    {
        for (auto comp: components)
        {
            auto ptr = dynamic_cast<T*>(comp);
            if (ptr) 
                return ptr;
        }
        return nullptr;
    }

private:
    vector<BaseComponent*> components;
};
added 417 characters in body
Source Link
user321630
user321630
Loading
added 275 characters in body
Source Link
user321630
user321630
Loading
added 275 characters in body
Source Link
user321630
user321630
Loading
added 885 characters in body
Source Link
user321630
user321630
Loading
added 885 characters in body
Source Link
user321630
user321630
Loading
added 136 characters in body
Source Link
user321630
user321630
Loading
added 2 characters in body
Source Link
user321630
user321630
Loading
added 2 characters in body
Source Link
user321630
user321630
Loading
added 64 characters in body
Source Link
user321630
user321630
Loading
added 64 characters in body
Source Link
user321630
user321630
Loading
Source Link
user321630
user321630
Loading