如何最好地管理游戏引擎中的组件?

时间:2017-02-08 05:07:03

标签: c++ architecture components game-engine

所以我正在开发我的第一个游戏引擎而且我已经碰壁了。目前我有一个Entity基类,它有一个组件指针向量,它将保存指向某些系统管理器类(graphisManager,PhysicsManager等)中组件对象的指针。这是我当前的Entity标题(剥离以专注于主要问题):

Entity.h

class Component;

namespace BlazeGameWorld
{
    class Entity
    {
    public:
        BlazeFramework::Math::Vector2D position;

    protected:
        Vector<Component*> components;

        static BlazeGraphics::GraphicsManager graphicsManager;
        static BlazePhysics::PhysicsManager physicsManager;
        static BlazeInput::InputManager inputManager;
        //....other managers

    private:

        ///////////////////////////////////////////////////////////////////////

    public:
        Entity();
        ~Entity();

        virtual bool Initialize();
        virtual bool Shutdown();

        virtual void Update() = 0;

        void AddComponent(Component* p_component);

        //Part of the broadcast messaging system for components to be able
        //to talk to one another in a decoupled way.
        void SendMessage(uint messageID);

    protected:

    private:
    };
}

正如您所看到的,我们的想法是拥有静态SystemManager类,它们将管理指向堆上实际组件的指针。这是一个潜在的PhysicsManager类的粗略Header(和其他Manager类类似):

PhysicsManager.h

class PhysicsComponent;

namespace BlazePhysics
{
    class PhysicsManager
    {
    public:

    protected:
        int numPhysicsComponents;
    private:
        Vector<PhysicsComponent*> physicsComponents;

        /////////////////////////////////////////////////////////////

    public:
        PhysicsManager();
        ~PhysicsManager();

        bool Initialize();
        bool Shutdown();

        void Update();

        template <typename PhysicsComponentType>
        PhysicsComponentType* CreatePhysicsComponent();

    private:
    };

    //template definitions
    template <typename PhysicsComponentType>
    PhysicsComponentType* PhysicsManager::CreatePhysicsComponent()
    {
        PhysicsComponentType* physicsComponent = new PhysicsComponentType
        physicsComponents.push_back(physicsComponent);

        return physicsComponents.at(numPhysicsComponents++);
    }
}

所以我可以在PhysicsManger向量中存储所有不同的physicsComponent指针(指向CollisionComponents,PositionComponents等)。问题是如果我想调用特定物理组件的方法,我无法编译。例如,如果(在PhysicsManager的更新循环中)我想更新一个collisionComponent的CheckCollision()方法,每个帧我不能只在for循环physicsComponents.at(i).CheckCollision中说,因为编译器在编译时不知道什么一个CollisionComponent是。有没有办法可以首先推断出数组中组件的类型,然后如果匹配CollisionComponent则调用CheckCollision方法?或者有更好的实现这个,因为这似乎有点笨重?

1 个答案:

答案 0 :(得分:2)

实体不应该了解您的系统,它们应该只是一个组件集合。否则引入另一个引擎系统的过程也需要改变实体类,这违背了ECS的整个目的。

系统也不应该管理组件。一个系统可以使用几个组件,并且许多系统可以使用,例位置/碰撞几何组件。

所以,在我看来:

  • 理想情况下,组件应该是简单的仅数据类,而所有处理都是在系统内完成的。
  • 实体必须只提供添加和删除组件的方法,并且 告诉它是否有特定的组件。
  • 某种实体管理器必须以缓存友好的方式存储组件,以便系统访问它们,并且应该能够提供一组实体,这些实体具有特定的系统组件/标签集。

这样,例如,如果要为某些实体添加脚本行为,您只需添加ScriptComponentScriptingSystem即可。您现有的所有代码都不需要任何更改。

This question在这个主题上有很多非常有用的资源。