1

我正在编写一个实体组件系统,我遇到了一个常见问题:组件相互依赖。我将使用一个例子:

假设您制作了一个项目组件,其中包含项目共有的数据(例如,重量)。但是,如果您想制作设备组件怎么办?任何设备也必须是一个项目,所以你有两个依赖组件。这种is-a关系似乎很适合继承,所以我做了一个继承组件。

问题是,我现在需要两个“多态层”,而我编写的枚举标记系统不再工作了。此外,我可能希望稍后将该设备组件分支为更多类型。

#include <memory>
#include <map>

enum COMPONENT_TAG {
    COMP_BASE,
    COMP_ITEM,
    COMP_ITEM_EQUIP
};

struct VirtualBaseComponent { // component

    COMPONENT_TAG tag;
    virtual ~VirtualBaseComponent() = 0;
};
VirtualBaseComponent::~VirtualBaseComponent() {};

struct ItemComponent : public VirtualBaseComponent {
    COMPONENT_TAG tag = COMP_ITEM;
    ~ItemComponent() {};
};

struct EquipmentComponent : public ItemComponent {
    COMPONENT_TAG tag = COMP_ITEM_EQUIP;
    ~EquipmentComponent() {};
};

struct Entity {
    std::map<COMPONENT_TAG, std::unique_ptr<VirtualBaseComponent>> components;

    template <typename T>
    T* get_component(COMPONENT_TAG tag) {

        auto found = components.find(tag);
        VirtualBaseComponent* baseptr;
        if (found == components.end()) {
            baseptr = nullptr;
        } else {
            baseptr = found->second.get();
        }
        return dynamic_cast<T*>(baseptr);
    }
};

int main() {
    {
    //set up a random item (a box)
    Entity box;
    box.components.insert(std::make_pair(COMP_ITEM, std::make_unique<ItemComponent>()));

    //fetching a base component: ok, this works fine
    ItemComponent *boxptr = box.get_component<ItemComponent>(COMP_ITEM);
    //do_stuff(boxptr->item_property);
    }


    {// set up a sword
    Entity sword;
    sword.components.insert(std::make_pair(COMP_ITEM_EQUIP, std::make_unique<EquipmentComponent>()));

    //but here, if I actually want to use some "item property" of the sword not related to its equipment-ness...
    //oops! that retrieves a nullptr, because sword does not have a base item tag
    ItemComponent *swordptr = sword.get_component<ItemComponent>(COMP_ITEM);

    ItemComponent a = *swordptr; //dereferencing it crashes the program
    }


}

那么,如何以多态方式设置和获取这些类型的组件呢?我想我可以在 get_component 方法中对标签进行 if 检查的大列表,但乍一看,这对我来说似乎是一个愚蠢的解决方案。

4

0 回答 0