首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ECS序列化

ECS序列化
EN

Stack Overflow用户
提问于 2018-10-22 08:59:58
回答 2查看 1.6K关注 0票数 1

我目前正在为一个游戏引擎开发一个ECS系统,并且偶然发现了一个序列化问题。是我在ECS实现中用于组件存储的数据结构,它是一个预先构造的组件池,这些组件是可回收的。因此,添加一个实体就像为预构造的组件分配值一样简单。系统被设计为使用组件索引,而不是类型,,这就是问题所在。当序列化和反序列化组件时,被视为BaseComponent指针.

组件结构层次化

代码语言:javascript
复制
struct BaseComponent {}; // struct used as base to store components

template<typename T>
struct Component : public BaseComponent {
    static const uint_fast32_t ID; // identifier used by the rest of the system
}

struct SomeComponent : public Component<SomeComponent> {
    // component specific data
}

是组件特定的数据,我想序列化、反序列化并将数据分配给SomeComponent.中的适当字段。

我有一个简单的解决方案,但是当涉及到干净的代码时,它是相当模糊的。我找到的解决方案是将组件内存直接转储到文件中,并通过char缓冲区将其读入内存。然而,这不允许指针,在我看来,这是相当令人厌恶的。我发现的另一个解决方案是,如果可能的话,使用变量函数来构造一个临时的、使用变量展开进行聚合初始化的函数。但是,此方法不解决序列化和反序列化问题,只解决分配问题。

因此,我的问题是:在不知道类型信息的情况下,是否有一种很好的方法来序列化和反序列化多态类型?

EN

回答 2

Stack Overflow用户

发布于 2018-10-22 09:34:51

在这种情况下,我会考虑CRTP模式。基类定义序列化/反序列化函数,这些函数在交付的类中调用实际实现。维基百科的文章有一些很好的例子。

票数 0
EN

Stack Overflow用户

发布于 2018-10-23 14:43:00

首先要做的是:我认为您正在尝试避免这种情况,但无论如何,您都需要为您拥有的每种组件定义一个序列化/反序列化函数。

明白了,你有三个选择。

  1. 不使用BaseComponent指针。
  2. 将BaseComponent更改为具有虚拟序列化/反序列化成员函数(以及一个虚拟析构函数,以确保安全)。然后在组件结构中使用CRTP,就像@licensed建议的那样。如下所示:

结构BaseComponent {虚拟std::字符串序列化()= 0;};模板结构组件: public BaseComponent {静态uint_fast32_t ID;虚拟std::字符串序列化(){返回static_cast(this)->serialize();};结构SomeComponent:公共组件{std::字符串序列化(){返回"{a: b,c: d}";};结构OtherComponent:公共组件{std::字符串序列化(){返回"{d: c,b: a}";};{ OtherComponent o1,o2;SomeComponent s1,s2;std::vector组件;components.push_back(&o1);components.push_back(&s1);components.push_back(&o2);components.push_back(&s2);用于(auto* comp : components) { std::cout << comp-> << "\n";}

  1. 将BaseComponent更改为有一个枚举或id,您可以使用它来识别大开关中的派生组件类型,这样就可以恢复类型。

枚举类ComponentKind { SomeComponent,OtherComponent };结构BaseComponent { ComponentKind类;};模板结构组件:公共BaseComponent {静态const uint_fast32_t ID;};结构SomeComponent: public ComponentKind=:ComponentKind::SomeComponent;} std::string序列化(){返回"{a: c: d}";} };struct OtherComponent: public OtherComponent{ OtherComponent() {OtherComponent(){OtherComponent= ComponentKind::OtherComponent;} std::string OtherComponent(){返回"{d: c,b: a}";};};std::OtherComponent序列化(BaseComponent* comp) {OtherComponent(comp->OtherComponent){ case (ComponentKind::SomeComponent):返回OtherComponentcase (ComponentKind:: OtherComponent ):返回static_cast(comp)->serialize();默认值:“;}{OtherComponent o1,o2;SomeComponent s1,s2;std::vector组件;components.push_back(&o1);components.push_back(&s1);components.push_back(&o2);components.push_back(&s2);for (auto* comp : components) { std::cout <<序列化(Comp) << "\n";}enum类ComponentKind { SomeComponent,OtherComponent };结构BaseComponent { ComponentKind样;};模板结构组件: public BaseComponent { static uint_fast32_t ID;};struct SomeComponent: public Component { SomeComponent() = ComponentKind::SomeComponent;}std::字符串序列化(){返回"{a: b,c: d}";};结构OtherComponent:公共组件{ OtherComponent() {OtherComponent(){OtherComponent()= ComponentKind::OtherComponent;}std::字符串序列化(){返回"{d: c,b}“;} };};字符串序列化(BaseComponent* comp) {开关(comp->种类){ case (ComponentKind:: SomeComponent ):返回static_cast(comp)->serialize();大小写(ComponentKind:: OtherComponent ):返回static_cast(comp)->serialize();默认值:返回“;} void (){OtherComponent o1,o2;SomeComponent s1,s2;std::vector组件;components.push_back(&o1);components.push_back(&s1);components.push_back(&o2);components.push_back(&s2);for (auto* comp : components) {std:cout <<序列化(Comp) << "\n";}}

选项2在BaseComponent上创建一个vtable (动态多态性能开始),并强制您使用虚拟析构函数以确保安全(请查看Scott关于该问题的单词)。

选项3,不需要一个vtable,而是抛出类型安全,并迫使您非常小心的static_casting各地。

我认为人们更喜欢备选方案3而不是2,但老实说,我会考虑第一个方案1。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52925664

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档