(То, что я описываю, основано на этом дизайне: что такое каркас системы сущностей? Прокрутите вниз, и вы найдете его)
У меня возникли проблемы с созданием системы компонент-компонент в C ++. У меня есть класс компонентов:
class Component { /* ... */ };
На самом деле это интерфейс для создания других компонентов. Итак, чтобы создать собственный компонент, я просто реализую интерфейс и добавляю данные, которые будут использоваться в игре:
class SampleComponent : public Component { int foo, float bar ... };
Эти компоненты хранятся внутри класса Entity, который дает каждому экземпляру Entity уникальный идентификатор:
class Entity {
int ID;
std::unordered_map<string, Component*> components;
string getName();
/* ... */
};
Компоненты добавляются в сущность путем хэширования имени компонента (это, вероятно, не такая уж хорошая идея). Когда я добавляю пользовательский компонент, он сохраняется как тип компонента (базовый класс).
Теперь, с другой стороны, у меня есть системный интерфейс, который использует интерфейс Node внутри. Класс Node используется для хранения некоторых компонентов одной сущности (поскольку Система не заинтересована в использовании всех компонентов сущности). Когда это необходимо Системе update()
, ей нужно только перебирать хранящиеся в ней Узлы, созданные из разных объектов. Так:
/* System and Node implementations: (not the interfaces!) */
class SampleSystem : public System {
std::list<SampleNode> nodes; //uses SampleNode, not Node
void update();
/* ... */
};
class SampleNode : public Node {
/* Here I define which components SampleNode (and SampleSystem) "needs" */
SampleComponent* sc;
PhysicsComponent* pc;
/* ... more components could go here */
};
Теперь проблема: скажем, я строю SampleNodes, передавая сущность в SampleSystem. Затем SampleNode «проверяет», имеет ли объект необходимые компоненты, которые будут использоваться SampleSystem. Проблема возникает, когда мне нужен доступ к нужному компоненту внутри сущности: компонент хранится в Component
коллекции (базового класса), поэтому я не могу получить доступ к компоненту и скопировать его на новый узел. Я временно решил проблему, приведя Component
к производному типу, но я хотел знать, есть ли лучший способ сделать это. Я понимаю, будет ли это означать перепроектирование того, что у меня уже есть. Благодарю.
источник
addComponent()
метод не должен быть метод шаблона тоже? Если я определю aaddComponent(Component* c)
, любой подкомпонент, который я добавлю, будет сохранен вComponent
указателе иtypeid
всегда будет ссылаться наComponent
базовый класс.У Chewy это правильно, но если вы используете C ++ 11, у вас есть несколько новых типов, которые вы можете использовать.
Вместо того, чтобы использовать
const std::type_info*
в качестве ключа на вашей карте, вы можете использоватьstd::type_index
( см. Cppreference.com ), который является оберткой дляstd::type_info
. Зачем тебе это использовать?std::type_index
Фактически сохраняет отношения сstd::type_info
как указатель, но это один указатель меньше для вас , чтобы беспокоиться о.Если вы действительно используете C ++ 11, я бы порекомендовал хранить
Component
ссылки внутри умных указателей. Таким образом, карта может быть что-то вроде:Добавление новой записи можно сделать так:
где
component
имеет типstd::shared_ptr<Component>
. Получение ссылки на данный типComponent
может выглядеть так:Обратите внимание также на использование
static_pointer_cast
вместоstatic_cast
.источник
cast
. Я начинаю думать, что было бы невозможно реализовать это или подобный дизайн системы без приведения.Component
указателей в одном контейнере обязательно требует приведения их к производному типу. Но, как указывал Чуи, у вас есть другие варианты, которые не требуют кастинга. Я сам не вижу ничего «плохого» в том, чтобы использовать этот тип бросков в дизайне, поскольку они относительно безопасны.