我正在设计编译时ECS。设计有其特定性 - 例如,将有各种各样的实体。这意味着组件的总数可能相当高,而每个实体的组件数量将相当低(有一些明显的现在 - 几乎无处不在的公共,如Sprite
或BoundingBox
)< / p>
我会实现以下界面:
/* Tell the compiler which fields we would use in this entity */
Entity<GraphicsComponent, PhysicsComponent> entity;
/* Populate the handles with the appropriate data (integer, pointer, doesn't matter) */
// via explicit creation
Entity.add<GraphicsComponent>(RenderSystem::create<GraphicsComponent>());
// or in some other way?
我写的Entity
课程的开始:
template <typename ...>
class Entity final {};
但是,我不知道如何为各个组件类型创建句柄数据字段,如果它甚至可能的话。任何人都可以帮助我或解释为什么它不起作用(或可能建议不同的解决方案)?
答案 0 :(得分:2)
只需使用std::tuple
即可。注: get
要求Components...
中的每一个都是不同的类型
template <typename ... Components>
class Entity final {
std::tuple<Components...> components;
template<typename Component>
void add(Component component) // possibly cv / ref qualified
{
std::get<std::decay_t<Component>>(components) = component;
}
};
答案 1 :(得分:2)
将std::variant
用于灵活性和简单性的混合,代价是可能会牺牲一些内存。
template<typename... Components>
class Entity final {
using variant = std::variant<Components...>;
std::vector<variant> components;
public:
template<typename T>
void add(T&& t) {
components.push_back(std::forward<T>(t));
}
};
当组件的大小变化很大时,会出现内存问题。假设一个是1个字节而另一个是200个字节,std::vector
中的所有条目将至少大200字节。
另一个解决方案是std::any
。
template<typename... Components>
class Entity final {
std::vector<std::any> components;
public:
template<typename T>
void add(T&& t) {
static_assert((std::is_same_v<Components, std::decay_t<T>> || ...));
components.push_back(std::forward<T>(t));
}
};
std::any
除了非常小的对象之外,肯定会拥有堆上的所有内容,但不会遇到std::variant
的上述问题。
在使用std::any
的情况下,我们仅使用类型系统来启用检查,而不是管理数据的布局。