Я писал систему компонент-сущность и столкнулся с тем, что должно быть общей проблемой: компонентами, которые зависят друг от друга. Я буду использовать пример:
Допустим, вы создаете компонент предмета, который содержит данные, общие для предметов (например, вес). Но тогда, что, если вы хотите сделать компонент оборудования? Любой элемент оборудования также ДОЛЖЕН быть элементом, поэтому у вас будет два зависимых компонента. Такого рода отношения казались подходящими для наследования, поэтому я создал наследующий компонент.
Проблема в том, что теперь мне нужны два «слоя полиморфизма», и система тегов enum, которую я написал, больше не работает. Кроме того, я, возможно, захочу позже разделить этот компонент оборудования на несколько типов.
#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
}}
Итак, как мне установить и извлечь эти виды компонентов полиморфным способом? Думаю, у меня мог бы быть большой список проверок if на теги в методе get_component, но на первый взгляд это кажется мне глупым решением.
Задача ещё не решена.
Других решений пока нет …