我应该在 ECS 中使用静态类吗?

Ear*_*rab 5 c++ static

嘿,我目前正在开发一个小型实体组件系统,其中有类似 的类EntityManager,ComponentManager并且SystemManager这些类只实例化一次,并且彼此之间进行了大量通信。

我创建了一个world拥有所有管理人员的类,并作为管理人员之间所有交流的中心。将所有经理设为静态会使很多事情变得更容易、更容易理解,而且我什至不需要世界级。

我知道静态类(我知道“静态类”不存在,但我的意思是只有静态成员的类)表现得好像它们是全局变量,而全局变量是 Bad®。
所以我想知道在这种情况下建议做什么

谢谢你的回答

车

编辑: World 类如下所示:

class World
{
public:
    EntityManager* entityManager;
    ComponentManager<PositionComponent>* componentManager;
    MovementSystem* movementSystem;
    Entity e;

public:
    World(sf::RenderWindow& window);
    void update();
};
Run Code Online (Sandbox Code Playgroud)

为了与每个管理器通信,需要一个指向世界的指针来访问其他管理器。像这样world->entityManager->getEntitys()

小智 1

(我建议该项目是一个游戏或类似的东西)

我不建议您将所有成员设为静态。它的主要问题是你失去了对对象生命周期的控制。您无法在运行时轻松销毁和创建新对象,因为没有对象。例如,如果您想在运行时更改管理器,则必须手动实现清理代码。对于 C++ 对象,C++ 通过值帮助您处理错误/警告、默认值和类成员。

在 gamedev 中实现和使用管理器的流行方法有以下几种:

  • 使用单例模式。在这种情况下,类有一个静态方法,该方法返回到非静态对象的链接。
  • 在方法调用期间手动传递方法所需的依赖项。

我认为单例模式对于您来说是性价比最好的方式。尽管对这种模式有很多批评,但它的工作做得很好(我看到的大多数游戏项目都使用 Singleton 方法来实现管理器类)。

关于这个模式,我想向您建议一件重要的事情。不要使用单例模式的默认实现。创建用于创建和销毁对象的方法,而不是将其隐藏在 getter 中。这是经理粘合代码的简单示例:

class Manager {
private:
    static Manager* ms_manager;
public:
    static void CreateManager() { ms_manager = new Manager(); }
    static void DestroyManager() { delete ms_manager; }
    static Manager* GetInstance() { return ms_manager; }
};
Run Code Online (Sandbox Code Playgroud)

用法是:

Manager::GetInstance()->SomeMethod();
Run Code Online (Sandbox Code Playgroud)

传递依赖关系方法有其自身的优点。在每个 Update 方法中传递所有内容可能听起来太困难,但事实并非如此。您可以创建上下文类,在其中设置所有依赖项并将其传递给需要它的每个方法。它几乎就像您的 World 类,但它的结构必须具有最少的代码并且没有依赖项。不要按值存储任何游戏对象(仅基元、几何向量和类似的东西)。可能是这样的:

struct Context {
    EntityManager* entityManager;
    ComponentManager<PositionComponent>* componentManager;
    MovementSystem* movementSystem;
    Entity* rootEntity;
};
Run Code Online (Sandbox Code Playgroud)

用法是:

GameObject::Update(Context& context) { context.entityManager->SomeMethod(); }
Run Code Online (Sandbox Code Playgroud)

这种方法的要点是您可以在运行时调整某些对象的上下文。例如,如果您有 LOD,您可以在上下文中保存当前的 LOD 级别,并在运行时根据与相机的距离对某些对象进行更改。