Je travaille sur un système de composants d'entité en C ++ que j'espère suivre le style d'Artemis (http://piemaster.net/2011/07/entity-component-artemis/) dans lequel les composants sont principalement des poches de données et c'est le Systèmes qui contiennent la logique. J'espère tirer parti de l'approche centrée sur les données de cette approche et créer de bons outils de contenu.
Cependant, je ne parviens pas à comprendre comment extraire une chaîne d'identifiant ou un GUID d'un fichier de données et l'utiliser pour construire un composant pour une entité. Évidemment, je ne pourrais avoir qu'une grosse fonction d'analyse:
Component* ParseComponentType(const std::string &typeName)
{
if (typeName == "RenderComponent") {
return new RenderComponent();
}
else if (typeName == "TransformComponent") {
return new TransformComponent();
}
else {
return NULL:
}
}
Mais c'est vraiment moche. J'ai l'intention d'ajouter et de modifier fréquemment des composants et, espérons-le, de construire une sorte de ScriptedComponentComponent, de sorte que vous puissiez implémenter un composant et un système dans Lua à des fins de prototypage. J'aimerais pouvoir écrire une classe héritant d'une BaseComponent
classe, peut-être ajouter quelques macros pour que tout fonctionne, puis laisser la classe disponible pour une instanciation au moment de l'exécution.
En C # et Java, cela serait assez simple, car vous avez de belles API de réflexion pour rechercher des classes et des constructeurs. Mais je le fais en C ++ parce que je veux augmenter ma maîtrise de cette langue.
Alors, comment cela se fait-il en C ++? J'ai lu sur l'activation de RTTI, mais il semble que la plupart des gens s'en méfient, en particulier dans une situation où je n'en ai besoin que pour un sous-ensemble de types d'objets. Si j'ai besoin d'un système RTTI personnalisé, où puis-je aller pour commencer à apprendre à en écrire un?
la source
Réponses:
Un commentaire:
L'implémentation d'Artemis est intéressante. J'ai proposé une solution similaire, sauf que j'ai appelé mes composants "Attributs" et "Comportements". Cette approche de la séparation des types de composants a très bien fonctionné pour moi.
En ce qui concerne la solution:
le code est facile à utiliser, mais sa mise en œuvre risque d’être difficile à suivre si vous n’êtes pas expérimenté en C ++. Alors...
L'interface souhaitée
Ce que j'ai fait est d'avoir un référentiel central de tous les composants. Chaque type de composant est associé à une chaîne donnée (qui représente le nom du composant). Voici comment vous utilisez le système:
La mise en oeuvre
L'implémentation n'est pas si mauvaise, mais c'est quand même assez complexe. cela nécessite une certaine connaissance des modèles et des pointeurs de fonction.
Remarque: Joe Wreschnig a fait quelques remarques intéressantes dans les commentaires, notamment sur le fait que mon implémentation précédente reposait sur trop d'hypothèses sur l'efficacité du compilateur dans l'optimisation du code. le problème n'était pas préjudiciable, mais je m'en foutais aussi. J'ai également remarqué que l'ancienne
COMPONENT_REGISTER
macro ne fonctionnait pas avec les modèles.J'ai changé le code et maintenant tous ces problèmes devraient être résolus. La macro fonctionne avec des modèles et les problèmes soulevés par Joe ont été résolus: il est maintenant beaucoup plus facile pour les compilateurs d’optimiser le code inutile.
composant / composant.h
composant / detail.h
composant / composant.cpp
Étendre avec Lua
Je dois noter qu'avec un peu de travail (ce n'est pas très difficile), cela peut être utilisé pour travailler de manière transparente avec des composants définis en C ++ ou en Lua, sans jamais avoir à y penser.
la source
shared_ptr
, mais votre conseil est toujours bon.On dirait que ce que vous voulez, c'est une usine.
http://en.wikipedia.org/wiki/Factory_method_pattern
Ce que vous pouvez faire est de faire en sorte que vos divers composants enregistrent auprès de l’usine le nom auquel ils correspondent, puis vous disposez d’une carte identifiant la chaîne identifiant la signature de la méthode du constructeur pour générer vos composants.
la source
Component
classes, des appelsComponentSubclass::RegisterWithFactory()
, non? Y a-t-il un moyen de le configurer plus dynamiquement et automagiquement? Le flux de travail que je recherche est de 1. Écrivez une classe en ne regardant que l’en-tête et le fichier cpp correspondants 2. Re-compiler le jeu 3. Ouvrez l’éditeur de niveaux et la nouvelle classe de composants pouvant être utilisés.J'ai travaillé avec la conception de Paul Manta à partir de la réponse choisie pendant un certain temps et suis finalement arrivé à cette implémentation d'usine plus générique et concise que je suis prêt à partager avec tous ceux qui abordent cette question à l'avenir. Dans cet exemple, chaque objet fabrique dérive de la
Object
classe de base:La classe Factory statique est la suivante:
La macro pour enregistrer un sous-type de
Object
est la suivante:Maintenant, l'utilisation est la suivante:
La capacité de nombreux identificateurs de chaîne par sous-type était utile dans mon application, mais la restriction à un seul identificateur par sous-type serait relativement simple.
J'espère que cela a été utile!
la source
En me basant sur la réponse de @TimStraubinger , j'ai construit une classe fabrique à l'aide de normes C ++ 14 permettant de stocker des membres dérivés avec un nombre arbitraire d'arguments . Mon exemple, contrairement à celui de Tim, ne prend qu'un nom / touche par fonction. Comme Tim, chaque classe stockée est dérivée d'une classe de base , la mienne étant appelée Base .
Base.h
EX_Factory.h
main.cpp
Sortie
J'espère que cela aidera les personnes ayant besoin d'utiliser une conception Factory qui ne nécessite pas de constructeur d'identité pour fonctionner. C'était amusant de concevoir, j'espère donc que cela aidera les personnes qui ont besoin de plus de flexibilité dans leurs conceptions d' usine .
la source