(Ce que je décris est basé sur cette conception: qu'est-ce qu'un framework de système d'entité?, Faites défiler vers le bas et vous le trouverez)
J'ai des problèmes pour créer un système de composants d'entité en C ++. J'ai ma classe Component:
class Component { /* ... */ };
Ce qui est en fait une interface, pour la création d'autres composants. Donc, pour créer un composant personnalisé, je viens d'implémenter l'interface et d'ajouter les données qui seront utilisées dans le jeu:
class SampleComponent : public Component { int foo, float bar ... };
Ces composants sont stockés dans une classe Entity, qui donne à chaque instance d'Entity un ID unique:
class Entity {
int ID;
std::unordered_map<string, Component*> components;
string getName();
/* ... */
};
Les composants sont ajoutés à l'entité en hachant le nom du composant (ce n'est probablement pas une si bonne idée). Lorsque j'ajoute un composant personnalisé, il est stocké en tant que type de composant (classe de base).
Maintenant, d'un autre côté, j'ai une interface système, qui utilise une interface Node à l'intérieur. La classe Node est utilisée pour stocker certains des composants d'une seule entité (car le système n'est pas intéressé à utiliser tous les composants de l'entité). Lorsque le système doit le faire update()
, il n'a qu'à parcourir les nœuds qu'il a stockés, créés à partir de différentes entités. Donc:
/* 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 */
};
Maintenant, le problème: disons que je construis les SampleNodes en passant une entité au SampleSystem. Le SampleNode "vérifie" ensuite si l'entité possède les composants requis à utiliser par le SampleSystem. Le problème apparaît lorsque j'ai besoin d'accéder au composant souhaité à l'intérieur de l'entité: le composant est stocké dans une collection Component
(classe de base), donc je ne peux pas accéder au composant et le copier sur le nouveau nœud. J'ai temporairement résolu le problème en convertissant le Component
down en un type dérivé, mais je voulais savoir s'il y avait une meilleure façon de le faire. Je comprends si cela signifierait repenser ce que j'ai déjà. Merci.
la source
addComponent()
méthode ne devrait-elle pas également être une méthode de modèle? Si je définis unaddComponent(Component* c)
, tout sous-composant que j'ajoute sera stocké dans unComponent
pointeur ettypeid
fera toujours référence à laComponent
classe de base.Chewy a raison, mais si vous utilisez C ++ 11, vous pouvez utiliser de nouveaux types.
À la place d'utiliser
const std::type_info*
comme clé dans votre carte, vous pouvez utiliserstd::type_index
( voir cppreference.com ), qui est un wrapper autour dustd::type_info
. Pourquoi l'utiliseriez-vous? Lestd::type_index
stocke en fait la relation avec le enstd::type_info
tant que pointeur, mais c'est un pointeur de moins dont vous devez vous soucier.Si vous utilisez effectivement C ++ 11, je recommanderais de stocker les
Component
références dans des pointeurs intelligents. La carte pourrait donc ressembler à ceci:L'ajout d'une nouvelle entrée peut se faire de la manière suivante:
où
component
est de typestd::shared_ptr<Component>
. La récupération d'une référence à un type donné deComponent
pourrait ressembler à:Notez également l'utilisation de
static_pointer_cast
au lieu destatic_cast
.la source
cast
. Je commence à penser qu'il serait impossible de mettre en œuvre cela, ou une conception de système similaire sans transtypages.Component
pointeurs dans un seul conteneur nécessite nécessairement leur conversion vers le type dérivé. Mais, comme l'a souligné Chewy, vous avez d'autres options à votre disposition, qui ne nécessitent pas de casting. Moi-même, je ne vois rien de "mauvais" à avoir ce type de plâtres dans la conception, car ils sont relativement sûrs.