En concevant un système entité-composant pour mon moteur, je suis tombé sur un petit problème dans la manière de stocker et de récupérer un type particulier de composant.
Tout d'abord, permettez-moi de clarifier un peu la terminologie que je vais utiliser dans cette question:
- J'appelle " Component " une structure de données qui stocke les données pertinentes pour un système particulier.
- J'appelle « système » une agrégation de méthodes et de structures de données qui utilise des composants pour mettre à jour l'état du jeu / l'interface avec l'utilisateur.
- Une " Entité " est simplement un ID utilisé pour récupérer des composants spécifiques et modifier leurs données dans la logique du jeu.
Chaque système possède un tableau (mappé par ID) de son type de composant (par exemple, Physique-> Composant physique, AI-> AIComponent, Rendu -> RenderingComponent), afin de pouvoir itérer efficacement sur les données.
Cependant, tous les composants n'appartiennent pas spécifiquement à un système. Par exemple, un composant Transform stocke la position, la rotation et l'échelle d'un objet. C'est l'une des parties les plus importantes d'une entité (Unity la rend obligatoire, même), car elle est utilisée par de nombreux systèmes, par exemple la physique, l'IA, le rendu, etc.
C'est à peu près le problème auquel je suis confronté. Étant donné que Transform est utilisé par de nombreux autres systèmes, comment dois-je procéder pour en récupérer un à utiliser pour chaque composant? Une solution possible que je vois est de faire en sorte que chaque composant stocke son propre ID d'entité. Il serait facile de récupérer n'importe quel composant comme celui-ci, mais ce ne serait pas aussi efficace, et cela irait également à l'encontre du concept d'un composant comme un ensemble de données isolé et indépendant, qui n'en connaît aucun autre.
Existe-t-il un moyen approprié de résoudre ce problème? Transformer devrait-il même être un composant?
la source
Réponses:
Il s'agit d'une question assez large, dont la réponse dépend fortement de votre architecture. Cependant, je vais essayer de vous donner une réponse générale.
Vos systèmes physiques et de rendu nécessiteront certainement la transformation, mais pas le système AI. Par conséquent, il est logique d'encapsuler la transformation dans sa propre classe de composants. Tous ces systèmes intéressés utiliseraient les mêmes données.Par conséquent, il est logique que l'entité ait un pointeur vers l'objet de transformation ou un identifiant pour un objet de transformation stocké ailleurs.
Si vous choisissez cette dernière solution, chaque système intéressé par une transformation devra accéder à l'emplacement de stockage de l'objet de transformation.
Si vous choisissez le premier, tout ce que chaque système doit faire est d'accéder à l'entité elle-même et de demander la transformation.
Dans le premier cas, le problème devient comment accorder l'accès au stockage des transformations à chaque système, sans enfreindre les règles de POO, si vous vous souciez de ces choses.
Le dernier cas n'a pas de tels problèmes, mais nécessite de changer la conception de votre objet entité pour stocker des pointeurs vers des objets plutôt que des identifiants d'objets composants.
Ma préférence personnelle est de concevoir la classe d'entité pour stocker des pointeurs vers des objets composants, car cela simplifie de nombreux problèmes de conception. De cette façon, chaque système qui nécessite une transformation peut la demander à l'entité et l'ignorer s'il ne le fait pas. Cependant, cela entraîne une surcharge de calcul inhérente aux pointeurs, à savoir le coût des échecs de cache.
Jetez un œil à cet aperçu ECS pour plus d'informations à ce sujet.
En fin de compte, c'est à vous de décider ce qui est le plus important pour vous: la facilité de développement ou les performances.
Je voudrais souligner, enfin, que votre question est un excellent exemple des questions de conception auxquelles les partisans d'ECS réfléchissent, et il n'y a pas de solution miracle définitive.
la source