Quel est le niveau de granularité approprié pour une architecture basée sur des composants?

26

Je travaille sur un jeu avec une architecture basée sur des composants. An Entitypossède un ensemble d' Componentinstances, chacune ayant un ensemble d' Slotinstances avec lesquelles stocker, envoyer et recevoir des valeurs. Fonctions d'usine telles que Playerproduire des entités avec les composants requis et les connexions d'emplacement.

J'essaie de déterminer le meilleur niveau de granularité pour les composants. Par exemple, en ce moment Position, Velocityet Accelerationsont tous des composants séparés, connectés en série. Velocityet Accelerationpourrait facilement être réécrit en un Deltacomposant uniforme , ou Position, Velocityet Accelerationpourrait être combiné avec des composants tels que Frictionet Gravityen un Physicscomposant monolithique .

Un composant devrait-il avoir la plus petite responsabilité possible (au prix de beaucoup d'interconnectivité) ou les composants associés devraient-ils être combinés en composants monolithiques (au prix de la flexibilité)? Je penche vers le premier, mais je pourrais utiliser un deuxième avis.

Jon Purdy
la source
Allez-vous utiliser votre propre moteur physique ou intégrer un moteur existant?
Den
@ Den: J'écris du code de physique , mais ce n'est en aucun cas un moteur . Cinématique 2D banale.
Jon Purdy

Réponses:

14

Il y a une ligne entre la granularité complète, conduisant à aucun gaspillage de code ou état de type blob (c'est pourquoi les architectures de composants sont privilégiées), et la convivialité.

Évidemment, les choses peuvent avoir un Position, mais elles ne sont pas nécessairement dynamiques (alors pourquoi avoir Velocityet Acceleration?). Cependant, quelque chose avec un Velocityva être un objet en mouvement, il est donc logique d'avoir également Accelerationgroupé.

Allez-vous avoir un cas où v et a vont être nécessaires, mais vous ne voulez pas de simulation physique pour eux? De même, y aura-t-il un point Gravitys'il ne s'agit pas d'objets physiques?

tl; dr Group ce qui a du sens.

Le canard communiste
la source
1
Ça me paraît juste. Mon système a très peu de centralisation: si un Entitya un Positionet quelques composants qui font Positionparticiper la physique, alors Entityc'est de facto physique. Je pense que ce que je peux faire, c'est simplement ajouter quelques composants pour le regroupement logique, et garder tous les composants fondamentaux à une seule responsabilité. Ainsi , en ajoutant, par exemple, un Movableà un Entityaurait le même effet que l' ajout d' un Position, Velocityet Acceleration.
Jon Purdy
6

Pour éviter la microgestion de chaque variable que je suggérerais en commençant lourdement, choisissez des divisions autour de la responsabilité et refactorisez lorsque la situation se présente logiquement. Vous pouvez commencer les premiers dessins sur papier. À un moment donné, ces grosses divisions de responsabilité deviendront les éléments constitutifs de vos entités.

Donc, pour un exemple précipité, vous avez Game. Le jeu se divise en environnement + état. L'environnement se divise en StaticWorld + MovingStuff. L'état se divise en AIControlled + PlayerControlled. L'idée grossière de dommages se divise en TakesDamage + GivesDamage.

Etc.

Un peu comme le conseil commun de "Construire des jeux, pas des moteurs!" pour les nouveaux praticiens, je recommande "Construire des jeux, pas des systèmes de composants élaborés!" car ce n'est qu'avec une expérience personnelle avec un jeu en cours que vous saurez si un système de composants élaboré est nécessaire dans les travaux futurs.

Patrick Hughes
la source
Je ne suis pas un nouveau développeur. Si j'ai des composants basés sur des concepts plutôt que sur le comportement (c.-à-d. De haut en bas ou de bas en haut), mon architecture ne sera-t-elle pas plus fragile et plus élaborée? Je peux implémenter n'importe quel comportement que je souhaite à partir de petits composants, mais je ne peux pas toujours obtenir le comportement souhaité à partir de composants précombinés. Sans oublier que je ne peux pas prédire tout ce que je veux réaliser même dans le cadre d'un match.
Jon Purdy
L'inconvénient du bas vers le haut est que les communications entre les composants deviennent un problème, et les gens ont tendance à démarrer de manière beaucoup trop micro à l'échelle de ce qu'ils modélisent. J'essayais principalement de m'éloigner du super micro "xyz est un composant" "la rotation est un composant" "rgb est un composant" pour quelqu'un qui n'a pas d'expérience.
Patrick Hughes
C'est suffisant. Je voulais juste m'assurer de bien vous comprendre. Avec le système de fente que j'ai, c'est simple et efficace pour que les composants communiquent, donc je ne vois vraiment aucun inconvénient à l'échelle "super-micro". Je n'ai pas l'intention de refactoriser cela dans un moteur autonome, mais si je le fais, alors je peux toujours introduire des abstractions telles que les groupes de composants que je mentionne dans mon commentaire sur la réponse de The Communist Duck.
Jon Purdy
4

Ma conjecture serait de combiner des composants qui auront beaucoup d'interaction. Dans votre cas, je garderais la position dans un seul composant et garderais la vitesse et l'accélération ensemble dans un composant physique.

Mais cela dépend beaucoup des fonctionnalités de votre jeu (sauf si vous créez un framework sans jeu spécifique en tête).

XGouchet
la source
2
Le problème avec la combinaison de composants avec beaucoup d'interaction est que parfois l'autre partie n'est pas nécessaire.
The Communist Duck
4

Je me rends compte que c'est une vieille question mais peut-être que quelqu'un trouvera cette réponse utile.

Je crois que Systemscela vous aidera mieux à comprendre comment construire des composants. Les systèmes existent dans des architectures où les composants ne contiennent pas leur propre logique, à part les simples getter / setters et les fonctions d'assistance. Les systèmes fonctionnent sur des entités qui satisfont aux exigences des composants. C'est pourquoi il est préférable de séparer les données des composants autant qu'il est logique que ces données soient traitées sans les autres données.

Par exemple, vous pouvez avoir un MovementSystemqui met à jour ses entités en Positionfonction de leur Velocity. Cela pourrait être pour des entités simples dans le jeu. Mais, pour le joueur et les ennemis, vous voudrez peut-être un mouvement qui a Accelerationété traité AcceleratedMovementSystem. Mais pour les obstacles, vous voudrez peut-être Friction. Le Terrain peut également avoir des frottements, mais il n'aura pas de composante de vitesse. Mais qu'en est-il Gravity? Ajoutez-le simplement Player, Enemy et Obstacle, et créez-en un GravitySystempour le traiter.

L'essentiel est que plus découplées votre Componentssont, plus extensible le Entitiessera lors de l' utilisation Systems.

Edit: rendu la dernière déclaration plus claire.

Edit: Ok, j'ai travaillé sur mon propre système et j'ai réalisé cette réalisation. Un exemple pour diviser la position et la vitesse est que la manipulation de la vitesse fait changer la position avec un MovementSystem. Par conséquent, un «InputMovementSystem» n'a pas besoin d'une position pour que le lecteur se déplace de l'entrée utilisateur, car le MovementSystem récupérera les changements de vitesse à appliquer à la position. Certes, cela fonctionnerait toujours bien pour les assembler, mais c'est un exemple de la raison pour laquelle ils n'ont pas besoin d'être.


J'ai lu récemment un article de blog qui disait quelque chose comme ceci:

"Si vous avez des données qui peuvent être regroupées avec 2 composants différents, il est préférable de créer un troisième composant avec ces données."

Dan H.
la source