Je m'intéresse au système d'entités basé sur les composants depuis un certain temps, et j'ai lu d'innombrables articles dessus (Les jeux Insomiac , le joli standard Evolve Your Hierarchy , la T-Machine , Chronoclast ... pour n'en nommer que quelques-uns).
Ils semblent tous avoir une structure à l'extérieur de quelque chose comme:
Entity e = Entity.Create();
e.AddComponent(RenderComponent, ...);
//do lots of stuff
e.GetComponent<PositionComponent>(...).SetPos(4, 5, 6);
Et si vous apportez l'idée de données partagées (c'est le meilleur design que j'ai vu jusqu'à présent, en termes de ne pas dupliquer les données partout)
e.GetProperty<string>("Name").Value = "blah";
Oui, c'est très efficace. Cependant, ce n'est pas exactement le plus facile à lire ou à écrire; il se sent très maladroit et travaille contre vous.
J'aimerais personnellement faire quelque chose comme:
e.SetPosition(4, 5, 6);
e.Name = "Blah";
Bien que, bien sûr, le seul moyen d'accéder à ce type de conception soit de retour dans le type de hiérarchie Entity-> NPC-> Enemy-> FlyingEnemy-> FlyingEnemyWithAHatOn que cette conception essaie d'éviter.
Quelqu'un a-t-il vu une conception pour ce type de système de composants qui est toujours flexible, tout en conservant un niveau de convivialité? Et d'ailleurs, parvient-il à contourner le stockage de données (probablement le problème le plus difficile) dans le bon sens?
Quelles conceptions existe-t-il pour un système d'entités basé sur des composants qui soit convivial mais toujours flexible?
la source
Je suggérerais qu'une sorte de classe Interface pour vos objets Entity serait bien. Il pourrait faire la gestion des erreurs avec la vérification pour vous assurer qu'une entité contient également un composant de la valeur appropriée dans un seul emplacement afin que vous n'ayez pas à le faire partout où vous accédez aux valeurs. Alternativement, la plupart des conceptions que j'ai jamais faites avec un système basé sur des composants, je traite directement les composants, en demandant, par exemple, leur composant positionnel, puis en accédant / mettant à jour les propriétés de ce composant directement.
Très basique à un niveau élevé, la classe prend l'entité en question et fournit une interface facile à utiliser pour les composants sous-jacents comme suit:
la source
En Python, vous pouvez intercepter la partie 'setPosition' de
e.SetPosition(4,5,6)
via en déclarant une__getattr__
fonction sur Entity. Cette fonction peut parcourir les composants et trouver la méthode ou la propriété appropriée et la renvoyer, de sorte que l'appel ou l'affectation de fonction se déroule au bon endroit. Peut-être que C # a un système similaire, mais il pourrait ne pas être possible car il est typé statiquement - il ne peut probablement pas compiler àe.setPosition
moins que e n'ait défini quelque part la position dans l'interface.Vous pouvez également faire en sorte que toutes vos entités implémentent les interfaces pertinentes pour tous les composants que vous pourriez y ajouter, avec des méthodes de stub qui déclenchent une exception. Ensuite, lorsque vous appelez addComponent, vous redirigez simplement les fonctions de l'entité pour l'interface de ce composant vers le composant. Un peu compliqué cependant.
Mais le plus simple serait peut-être pas surcharger l'opérateur [] de votre classe d' entité pour rechercher les composants attachés à la présence d'une propriété valide et retourner que, donc il peut être attribué à comme ceci:
e["Name"] = "blah"
. Chaque composant devra implémenter son propre GetPropertyByName et l'entité les appellera tour à tour jusqu'à ce qu'elle trouve le composant responsable de la propriété en question.la source
GetProperty
méthode .. Seul inconvénient est la manipulation et la comparaison des chaînes. Mais c'est un point discutable.Pour développer la réponse de Kylotan, si vous utilisez C # 4.0, vous pouvez taper statiquement une variable pour qu'elle soit dynamique .
Si vous héritez de System.Dynamic.DynamicObject, vous pouvez remplacer TryGetMember et TrySetMember (parmi les nombreuses méthodes virtuelles) pour intercepter les noms de composants et renvoyer le composant demandé.
J'ai écrit un peu sur les systèmes d'entités au fil des ans, mais je suppose que je ne peux pas rivaliser avec les géants. Quelques notes ES (quelque peu dépassées et ne reflètent pas nécessairement ma compréhension actuelle des systèmes d'entités, mais cela vaut la peine d'être lu, à mon humble avis).
la source
object
paramètre out - mais tout cela sera résolu au moment de l'exécution. Je pense que c'est une manière glorifiée de garder une interface fluide sur ie entity.TryGetComponent (compName, out component). Je ne suis pas sûr d'avoir compris la question, cependant :)Je vois beaucoup d'intérêt ici dans ES sur C #. Découvrez mon port de l'excellente mise en œuvre ES Artemis:
https://github.com/thelinuxlich/artemis_CSharp
En outre, un exemple de jeu pour vous familiariser avec son fonctionnement (en utilisant XNA 4): https://github.com/thelinuxlich/starwarrior_CSharp
Les suggestions sont les bienvenues!
la source
J'ai décidé d'utiliser l'excellent système de réflexion de C #. Je l'ai basé sur le système de composants général, plus un mélange des réponses ici.
Les composants sont ajoutés très facilement:
Et peut être interrogé soit par nom, type, ou (si communs comme Santé et Position) par propriétés:
Et supprimé:
Les données sont, encore une fois, communément accessibles par les propriétés:
Qui est stocké côté composant; moins de frais généraux s'il n'a pas HP:
La grande quantité de frappe est facilitée par Intellisense dans VS, mais pour la plupart, il y a peu de frappe - la chose que je cherchais.
Dans les coulisses, je stocke un
Dictionary<Type, Component>
et jeComponents
remplace laToString
méthode de vérification du nom. Mon design original utilisait principalement des chaînes pour les noms et les choses, mais c'est devenu un cochon avec lequel travailler (oh regardez, je dois lancer partout aussi le manque de propriétés faciles d'accès).la source