(O que estou descrevendo é baseado neste design: o que é uma estrutura de sistema de entidades ? , role para baixo e você a encontrará)
Estou tendo problemas para criar um sistema de componente de entidade em C ++. Eu tenho minha classe Component:
class Component { /* ... */ };
Na verdade, é uma interface para outros componentes serem criados. Então, para criar um componente personalizado, eu apenas implementei a interface e adicionei os dados que serão usados no jogo:
class SampleComponent : public Component { int foo, float bar ... };
Esses componentes são armazenados dentro de uma classe Entity, que fornece a cada instância de Entity um ID exclusivo:
class Entity {
int ID;
std::unordered_map<string, Component*> components;
string getName();
/* ... */
};
Os componentes são adicionados à entidade com hash no nome do componente (provavelmente essa não é uma ótima idéia). Quando adiciono um componente personalizado, ele é armazenado como um tipo de componente (classe base).
Agora, por outro lado, eu tenho uma interface de sistema, que usa uma interface de nó dentro. A classe Node é usada para armazenar alguns dos componentes de uma única entidade (como o Sistema não está interessado em usar todos os componentes da entidade). Quando o sistema precisa update()
, ele só precisa percorrer os Nós armazenados, criados a partir de diferentes entidades. Então:
/* 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 */
};
Agora o problema: digamos que eu construa o SampleNodes passando uma entidade para o SampleSystem. O SampleNode "verifica" se a entidade possui os componentes necessários para serem utilizados pelo SampleSystem. O problema aparece quando preciso acessar o componente desejado dentro da Entidade: o componente é armazenado em uma Component
coleção (classe base), portanto, não consigo acessar o componente e copiá-lo para o novo nó. Resolvi o problema temporariamente convertendo-o Component
em um tipo derivado, mas queria saber se existe uma maneira melhor de fazer isso. Entendo se isso significaria redesenhar o que eu já tenho. Obrigado.
fonte
addComponent()
método não precisaria ser também um modelo? Se eu definir aaddComponent(Component* c)
, qualquer subcomponente que eu adicionar será armazenado em umComponent
ponteiro etypeid
sempre se referirá àComponent
classe base.O Chewy está certo, mas se você estiver usando o C ++ 11, terá alguns novos tipos que poderá usar.
Em vez de usar
const std::type_info*
como chave no seu mapa, você pode usarstd::type_index
( consulte cppreference.com ), que é um invólucro ao redor dostd::type_info
. Porque você usaria isso? Nastd::type_index
verdade, ele armazena o relacionamento com ostd::type_info
ponteiro, mas esse é um ponteiro a menos para você se preocupar.Se você estiver realmente usando o C ++ 11, eu recomendaria armazenar as
Component
referências dentro de ponteiros inteligentes. Portanto, o mapa pode ser algo como:A adição de uma nova entrada pode ser feita assim:
onde
component
é do tipostd::shared_ptr<Component>
. A recuperação de uma referência a um determinado tipoComponent
pode ser semelhante a:Observe também o uso de em
static_pointer_cast
vez destatic_cast
.fonte
cast
. Estou começando a pensar que seria impossível implementar isso ou um design de sistema semelhante sem lançamentos.Component
ponteiros em um único contêiner exige necessariamente convertê- los no tipo derivado. Mas, como Chewy apontou, você tem outras opções disponíveis, que não requerem transmissão. Eu mesmo não vejo nada de "ruim" em ter esse tipo de conversão no design, pois é relativamente seguro.