实体组件系统 (ECS):实体专有的组件数据在具有该组件的所有实体之间共享

Entity Component System (ECS): Entity-Exclusive Component Data Being Shared Among All Entities With That Component

我会尽量保持简短

上下文

我的基本 C++(SDL 和 OpenGL)2D 游戏引擎有一个 ECS。我有一个名为 TextSystem 的系统,它需要 3 个组件。 TransformComponent, RenderComponent, & TextComponent.

这是为系统设置的签名的代码片段。

ECSHandler::Instance()->Init();

//Register components.
ECSHandler::Instance()->RegisterComponent<TransformComponent>();
ECSHandler::Instance()->RegisterComponent<RenderComponent>();
ECSHandler::Instance()->RegisterComponent<TextComponent>();

//movement signature here

renderSignature.set(ECSHandler::Instance()->GetComponentType<TransformComponent>());
renderSignature.set(ECSHandler::Instance()->GetComponentType<RenderComponent>());

textSignature.set(ECSHandler::Instance()->GetComponentType<TransformComponent>());
textSignature.set(ECSHandler::Instance()->GetComponentType<RenderComponent>());
textSignature.set(ECSHandler::Instance()->GetComponentType<TextComponent>());

//Register systems.
//mpMovementSystem = ECSHandler::Instance()->RegisterSystem<MovementSystem>();
mpRenderSystem = ECSHandler::Instance()->RegisterSystem<RenderSystem>();
mpTextSystem = ECSHandler::Instance()->RegisterSystem<TextSystem>();
//ECSHandler::Instance()->SetSystemSignature<MovementSystem>(signature);
ECSHandler::Instance()->SetSystemSignature<RenderSystem>(renderSignature);
ECSHandler::Instance()->SetSystemSignature<TextSystem>(textSignature);

//mpSystems.insert({ typeid(MovementSystem).name(), mpMovementSystem });
mpSystems.insert({ typeid(RenderSystem).name(), mpRenderSystem });
mpSystems.insert({ typeid(TextSystem).name(), mpTextSystem });

TextSystem 所做的就是将 RenderComponent 中的“纹理”变量设置为由 text/font 制作的纹理.这是使用名为 LoadTextureFromFont 的函数完成的。

另一个处理渲染的系统,RenderingSystem,如果实体已经注册到 TextSystem 作为 RenderingSystem 具有 TextSystem 需要的所有组件,transformrender组件。

因此,TextSystem 更改实体的纹理以根据文本输入更新实体(TextComponent[=69 中的“输出”变量=]) 并且 RenderSystem 呈现该实体。

    void TextSystem::Update()
    {
        for (auto const& entity : mEntities)
        {
            auto& render = ECSHandler::Instance()->GetComponent<RenderComponent>(entity);
            auto& text = ECSHandler::Instance()->GetComponent<TextComponent>(entity);

            render.texture = ResourceManager::LoadTextureFromFont(text.output, true, text.font);
        }
    }
    void RenderSystem::Draw()
    {
        for (auto const& entity : mEntities)
        {
        auto& transform = ECSHandler::Instance()->GetComponent<TransformComponent>(entity);
        auto& render = ECSHandler::Instance()->GetComponent<RenderComponent>(entity);

        ...

        glBindVertexArray(mQuadVAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL);
        glBindVertexArray(0);
    }
}

TextSystem 的更新在 RenderingSystem 的绘制之前调用。

问题

当在 render 组件中为在 TextSystem 中注册的实体重新分配纹理变量时,应用的最新纹理 (通过 LoadTextureFromFont)应用于具有 TextComponent 的所有实体。本质上,最后一个 TextComponent 成为具有所述组件的所有实体的 TextComponent。纹理的大小是根据原文的大小制作的,所以很长的文字被最新的文字替换后会显得不成比例。

ResourceManager::AddText("testText", "Message", glm::vec2(200.f, 200.f), ResourceManager::GetFont("CircularMedium"));
ResourceManager::AddText("testText2", "This is a message.", glm::vec2(300.f, 200.f), ResourceManager::GetFont("CircularMedium"));

任何其他组件都不会发生这种情况,严格来说,这个组件(仅包含一个字符串和字体对象)似乎不是实体独有的。

我已尽我所能解决此问题(10-12 小时...)但谷歌搜索没有产生预期的结果。

如果需要任何东西(更多代码片段 and/or 上下文)请告诉我!我不确定这个问题是否适合 Stack Overflow 或 Game Development。

从 GetTextureFromFont 返回的“Texture”变量是一个全局变量。