标签: entity-component-system

四方嵌套unordered_map怪兽的替代方法?

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

从技术上讲,以下内容可以满足我的需要,但显然是不行的:

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*         
Run Code Online (Sandbox Code Playgroud)

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

每个周期,我们将根据指针的类型遍历指针,一次一层。场景变化很少(每2-3分钟一次)。可以使用类型和ID的组合来访问组件。代码会定期检查在同一ID中还存在哪些其他Component类型。场景,图层和类型通过其名称进行访问,名称存储为32位CRC哈希。速度至关重要。ID是由代码分配的数字,仅从0开始。ID在每个场景中都是唯一的。

毫无疑问,有一些疯狂的(惯用的)成语可以帮助我,但我从未听说过。有人认识吗? 到目前为止,我没有提出任何备选方案,但是无论如何,我都会列出它们:

选项1:

std::unordered_map<uint32_t, std::vector<Component*>>
ID -> Component*
Run Code Online (Sandbox Code Playgroud)

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

选项2:

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

选项3:

std::vector<Component*>
std::unordered_map<uint32_t, std::vector<int>>
Run Code Online (Sandbox Code Playgroud)

(类型/层/场景/ ID)->分量*仅使用矢量索引存储所有分量。有一个unordered_map,它在主存储向量中包含索引向量。当我们检查两者之间的冲突时,ID和字符串哈希都可以存在(不太可能)。场景,图层和类型的名称必须唯一。ID返回该ID的组成部分的所有索引的向量,Name或类型返回包含该类型或场景的所有索引的向量。这些向量的所有这些迭代都让人感到骇俗。

选项4:

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

c++ game-engine c++17 entity-component-system

3
推荐指数
1
解决办法
118
查看次数

为什么可以修改在函数内部声明的静态常量变量?

我正在为我的游戏引擎实施 ECS 框架,并研究在运行时识别组件类型的方法。这意味着我可以在内存中连续动态地对类似类型的组件进行分组。例如,我可以有两个单独的数组PositionVelocity组件,我的系统可以循环遍历它们。

我目前使用typeid(),但我遇到了一篇使用static const变量为每种类型生成唯一 ID的文章。总体思路可以总结在下面的代码片段中:

#include <iostream>

struct Position { float x, y; };
struct Velocity { float dx, dy; };

template <typename T>
int test(int x) {
    static const int y = x;
    return y;
}

int main(int argc, char **argv) {
    std::cout << test<Position>(1) << " ";
    std::cout << test<Position>(2) << " ";
    std::cout << test<Velocity>(3) << " ";
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这个输出1 1 3,但我希望因为它试图修改一个常量(特别是在第二次调用时),它将无法编译。为什么这样做?

c++ entity-component-system

3
推荐指数
1
解决办法
102
查看次数

从集合保持接口返回类而不是接口

我想创建一个小的Entity-Component-System示例并创建一些组件,如

internal struct Position : IComponent
{
    public int X { get; set; }
    public int Y { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

internal struct MovementSpeed : IComponent
{
    public int Value { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

每个组件实现一个当前为空的接口IComponent.当系统循环实体时,我想快速找到相关组件.

我想过创建一个Dictionary,它将组件类型作为键,将当前实体的组件作为值.

我开始了 public Dictionary<Type, IComponent> Components { get; }

我可以使用添加组件 myEntity.Components.Add(typeof(Movement), new Movement() as IComponent);

但是我怎样才能归还一个组件?我创建了一个运动系统示例

internal class Movement : ISystem
{
    public void Update()
    {
        foreach (Entity entity in EntityPool.activeEntities.Values) // Loop through all entities
        {
            Dictionary<Type, IComponent> components …
Run Code Online (Sandbox Code Playgroud)

c# entity-component-system

2
推荐指数
1
解决办法
64
查看次数

我的游戏引擎实体组件系统中的 GetComponent&lt;&gt;() 函数返回编译器错误 C2440

此问题与在 Windows 10 操作系统中运行的 C++ 应用程序中 Visual Studio 2019 的编译器错误有关。这可能是一个中级或更高级别的问题。

概括

我有这个功能:

template<typename T> T* Scene::GetComponent(EntityID entityID) {
    CompTypeID typeID = TypeToID<T>();
    if (HasComponent<T>(entityID)) {
        CompIndex index = componentIndexes[typeID][entityID];
        return components[typeID][index];
    }
    else return nullptr;
}
Run Code Online (Sandbox Code Playgroud)

此函数导致编译器错误 C2440:

'return':无法使用 [_Ty=Component*] 和 [T=Name] 从 '_Ty' 转换为 'T*'

此错误还附加了以下两条消息:

消息:从基类转换到派生类需要 dynamic_cast 或 static_cast

消息:请参阅对使用 [T=Name] 编译的函数模板实例化 'T *Scene::GetComponent(EntityID)' 的引用

此错误出现 3 次,每次 T 等于 Name、Transform 和 Sprite(到目前为止我的游戏引擎中的每个组件)

MSDN 上的编译器错误 C2440:https ://docs.microsoft.com/en-us/cpp/error-messages/compiler-errors-1/compiler-error-c2440?view = vs-2019

功能说明

ECS设计

我的实体组件系统通过两个数组数组存储实体和组件。

第一个是componentIndexes,用于按实体索引到第二个数组中,第二个数组components将根据索引返回一个组件。从本质上讲,如果您听说过使用“稀疏”数组和“密集”数组来压缩数组,那么这 …

c++ components compiler-errors game-engine entity-component-system

2
推荐指数
1
解决办法
276
查看次数