3

我一直在尝试寻找一种有效的方法来存储和检索许多对象。让我解释一下我想要实现的目标,然后列出我想出的选项(但我不满意)。

以下在技术上做了我需要它做的事情,但显然是一个禁忌:

std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::unordered_map<uint32_t, Component*>>>>
//Scene -> Layer -> Type -> Id -> Component*         

最内部的地图根据其 ID 保存组件。它之前的每个类型都有一个映射(组件的子类)。后者是这样完成的,以便当我检索它们时,我可以完全安全地动态地将它们转换为它们的类型,因为知道 TYPE 哈希映射只包含它们的类型的指针,还允许使用 count 来快速检查某个 ID 是否存在某些东西. 后面的地图按层存储,第一个地图按场景存储。在任何时候,将举行大约 30-50 个场景,每个场景包含大约 6-10 个图层,每个图层包含大约 30-40 个类型,每个类型包含 1 到 500 个对象。

每个循环我们都会根据指针的类型迭代指针,一次一层。场景很少改变(每 2-3 分钟)。使用 Type 和 Id 的组合访问组件。代码会定期检查哪些其他组件类型存在于同一 Id 中。场景、层和类型可以通过它们的名称进行访问,名称存储为 32 位 CRC 散列。速度至关重要。ID 是由代码分配的数字,只是从 0 开始。ID 在每个场景中都是唯一的。

毫无疑问,有一些疯狂的(阅读:常见的)成语可以帮助我,而我从未听说过。有谁知道吗? 到目前为止,我提出的任何替代方案都不可接受,但无论如何我都会列出它们:

选项1:

std::unordered_map<uint32_t, std::vector<Component*>>
ID -> Component*

组件保存它来自哪个类型、场景和图层,每当我们遍历所有条目时,我们都会忽略不来自当前场景或图层的条目。或者,按顺序存储它们,以便您只需在一定范围内进行迭代。向量包含组件,当我们需要访问某种类型的组件时,我们会通过向量进行搜索。不理想,因为它需要一个周期进行多次搜索。或者使用 unordered_map 代替向量。

选项 2:

与嵌套地图相同,但带有向量。映射将 Id 转换为向量内的索引。

选项 3:

std::vector<Component*>
std::unordered_map<uint32_t, std::vector<int>>

(Type / Layer / Scene / Id) -> Component* 简单地用向量的索引存储所有组件。有一个 unordered_map,其中包含主存储向量中的索引向量。当我们检查两者之间的冲突时,ID 和字符串哈希都可以存在(不太可能)。对于场景、图层和类型,名称必须是唯一的。ID 返回该 ID 的组成部分的所有索引的向量,名称或类型返回包含该类型或场景的所有索引的向量。感觉 hackish,所有这些向量的迭代。

选项 4:

组件获取一个“Component* next”指针来遍历属于同一实体的组件。最后一个组件链接到第一个。组件再次获得类型和场景/图层成员。

4

2 回答 2

6

使用散列函数和相等函数指定您自己的密钥。

   class cKey
    {
    public:
      size_t scene;
      size_t layer;
      size_t type;
      size_t id;
    };

    unordered_map< cKey, Component*,
     hashkey, equalkey  >

一个人将如何迭代一层的所有组件?

cKey key;
key.scene = S;
key.layer = L;

for( key.type = 0; key.type< LastType; key.type ++ ) {
for( key.id = 0; key.id < LastID; key.id++ ) {
   Component * pC = the_map.find( key ).second;
   ...

您可以在https://gist.github.com/JamesBremner/d71b158b32e4dd8ffaf8cbe93cf3f180找到一个实现, 它在 250 毫秒内迭代 50,000 个组件的映射中的一个层。

于 2019-06-20T14:36:17.783 回答
4

我建议将地图分成多个地图:

std::unordered_map<std::uint32_t, std::vector<std::uint32_t>> layer_by_scene;
std::unordered_map<std::uint32_t, std::vector<std::uint32_t>> entity_by_layer;
std::unordered_map<uint32_t, std::vector<std::uint32_t>> component_by_entity;
std::unordered_map<uint32_t, Component*> components;

但是,请注意,在通常的实体组件系统中,您将尝试避免指针在基于节点的容器中追逐和跳跃。

于 2019-06-20T15:11:50.753 回答