L'architecture Entity Component System est-elle orientée par définition?

20

L' architecture Entity Component System est-elle orientée objet, par définition? Cela me semble plus procédural ou fonctionnel. À mon avis, cela ne vous empêche pas de l'implémenter dans un langage OO, mais il ne serait pas idiomatique de le faire de manière résolument OO.

Il semble que ECS sépare les données (E & C) du comportement (S). Comme preuve :

L'idée est de n'avoir aucune méthode de jeu intégrée dans l'entité.

Et :

Le composant consiste en un ensemble minimal de données nécessaires à un usage spécifique

Les systèmes sont des fonctions à usage unique qui prennent un ensemble d'entités qui ont un composant spécifique


Je pense que ce n'est pas orienté objet car une grande partie de l'orientation objet consiste à combiner vos données et votre comportement ensemble. Comme preuve :

En revanche, l'approche orientée objet encourage le programmeur à placer des données là où elles ne sont pas directement accessibles par le reste du programme. Au lieu de cela, les données sont accessibles en appelant des fonctions spécialement écrites, communément appelées méthodes, qui sont regroupées avec les données.

ECS, d'autre part, semble être tout au sujet de séparer vos données de votre comportement.

Daniel Kaplan
la source

Réponses:

21

introduction


Les systèmes à composants d'entité sont une technique architecturale orientée objet.

Il n'y a pas de consensus universel sur ce que signifie le terme, de même que la programmation orientée objet. Cependant, il est clair que les systèmes à composants d'entité sont spécifiquement conçus comme une alternative architecturale à l' héritage . Hiérarchies d'héritage sont naturels pour exprimer ce qu'est un objet est , mais dans certains types de logiciels (comme les jeux), vous préférez exprimer ce qu'un objet fait .

Il s'agit d'un modèle d'objet différent de celui des «classes et héritage» auquel vous êtes probablement habitué à travailler en C ++ ou Java. Les entités sont aussi expressives que les classes, tout comme les prototypes comme en JavaScript ou Self - tous ces systèmes peuvent être implémentés les uns par rapport aux autres.

 

Exemples


Le mot Let qui Playerest une entité Position, Velocityet des KeyboardControlledcomposants qui font les choses évidentes.

entity Player:
  Position
  Velocity
  KeyboardControlled

Nous savons qu'il Positionfaut être affecté par Velocityet Velocitypar KeyboardControlled. La question est de savoir comment nous aimerions modéliser ces effets.

 

Entités, composants et systèmes


Supposons que les composants n'aient aucune référence l'un à l'autre; un Physicssystème externe traverse tous les Velocitycomposants et met à jour l' Positionentité correspondante; un Inputsystème traverse tous les KeyboardControlledcomposants et met à jour le Velocity.

          Player
         +--------------------+
         | Position           | \
         |                    |  Physics
       / | Velocity           | /
  Input  |                    |
       \ | KeyboardControlled |
         +--------------------+

Cela répond aux critères:

  • Aucune logique de jeu / métier n'est exprimée par l'entité.

  • Les composants stockent des données décrivant le comportement.

Les systèmes sont désormais responsables de la gestion des événements et de la mise en œuvre du comportement décrit par les composants. Ils sont également chargés de gérer les interactions entre les entités, telles que les collisions.

 

Entités et composants


Cependant, supposons que les composants n'ont des références les uns aux autres. Maintenant, l'entité est simplement un constructeur qui crée certains composants, les lie et gère leur durée de vie:

class Player:
  construct():
    this.p = Position()
    this.v = Velocity(this.p)
    this.c = KeyboardControlled(this.v)

L'entité peut désormais envoyer des événements d'entrée et de mise à jour directement à ses composants. Velocityrépondrait aux mises à jour et KeyboardControlledrépondrait aux commentaires. Cela répond toujours à nos critères:

  • L'entité est un conteneur «stupide» qui ne transmet que les événements aux composants.

  • Chaque composant adopte son propre comportement.

Ici, les interactions entre composants sont explicites, et non imposées de l'extérieur par un système. Les données décrivant un comportement (quelle est la quantité de vitesse?) Et le code qui le décrète (quelle est la vitesse?) Sont couplées, mais de manière naturelle. Les données peuvent être considérées comme des paramètres du comportement. Et certains composants n'agissent pas du tout - a Positionest le comportement d' être dans un endroit .

Les interactions peuvent être gérées au niveau de l'entité («quand une Playercollision avec un Enemy…») ou au niveau des composants individuels («lorsqu'une entité avec Lifeentre en collision avec une entité avec Strength…»).

 

Composants


Quelle est la raison pour laquelle l'entité existe? S'il s'agit simplement d'un constructeur, nous pouvons le remplacer par une fonction renvoyant un ensemble de composants. Si nous voulons plus tard interroger des entités par leur type, nous pouvons tout aussi bien avoir un Tagcomposant qui nous permet de faire exactement cela:

function Player():
  t = Tag("Player")
  p = Position()
  v = Velocity(p)
  c = KeyboardControlled(v)
  return {t, p, v, c}
  • Les entités sont aussi stupides que possible - ce ne sont que des ensembles de composants.

  • Les composants répondent directement aux événements comme précédemment.

Les interactions doivent maintenant être gérées par des requêtes abstraites, découplant complètement les événements des types d'entités. Il n'y a plus de types d'entités à interroger - les Tagdonnées arbitraires sont probablement mieux utilisées pour le débogage que la logique de jeu.

 

Conclusion


Les entités ne sont pas des fonctions, des règles, des acteurs ou des combinateurs de flux de données. Ce sont des noms qui modélisent des phénomènes concrets - en d'autres termes, ce sont des objets. C'est comme le dit Wikipedia - les systèmes à composants d'entité sont un modèle d'architecture logicielle pour la modélisation d'objets généraux.

Jon Purdy
la source
2
La principale alternative à l'OO basé sur une classe, l'OO basée sur un prototype, semble également coupler les données et le comportement. En fait, il semble différer d'ECS tout autant que l'OO basé sur une classe. Pourriez-vous expliquer ce que vous entendez par OO?
Pour ajouter à la question de @ delnan, êtes-vous en désaccord avec l'extrait de l'article wikipedia OO que j'ai cité?
Daniel Kaplan
@tieTYT: La citation de Wikipédia parle d'encapsulation et de dissimulation d'informations. Je ne pense pas que cela prouve qu'un couplage données-comportement soit nécessaire, mais seulement qu'il est courant.
Jon Purdy
@delnan: Je ne veux rien dire par OO. La programmation orientée objet, pour moi, est exactement ce qu'elle dit sur l'étain: programmation avec des «objets» (par opposition aux fonctions, règles, acteurs, combinateurs de flux de données, etc.) où la définition particulière d' objet est définie par l'implémentation.
Jon Purdy
1
@tieTYT: Je décrivais juste des implémentations que j'ai vues dans la nature, afin de transmettre que c'est un terme large - pas contradictoire, mais certainement plus large que la description de Wikipedia.
Jon Purdy
20

NON. Et je suis surpris du nombre de personnes qui ont voté autrement!

Paradigme

Il est orienté données alias données, car nous parlons de l' architecture et non du langage dans lequel il est écrit. Les architectures sont des réalisations de styles ou de paradigmes de programmation , qui peuvent généralement être déconseillés dans un langage donné.


Fonctionnel?

Votre comparaison avec la programmation fonctionnelle / procédurale est une comparaison pertinente et significative. Notez, cependant, qu'un langage "fonctionnel" est différent du paradigme "procédural" . Et vous pouvez implémenter un ECS dans un langage fonctionnel comme Haskell , ce que les gens ont fait.


Là où la cohésion se produit

Votre observation est pertinente et précise :

"... [ECS] ne vous empêche pas de l'implémenter dans un langage OO, mais il ne serait pas idiomatique de le faire de manière résolument OO"


ECS / ES n'est pas EC / CE

Il existe une différence entre les architectures basées sur les composants, "Entity-Component" et "Entity-Component-System". Puisqu'il s'agit d'un modèle de conception en évolution, j'ai vu ces définitions utilisées de manière interchangeable. Les architectures "EC" ou "CE" ou "Entity-Component" placent le comportement dans les composants , tandis que les architectures "ES" ou "ECS" mettent le comportement dans les systèmes . Voici quelques articles ECS, qui utilisent tous deux une nomenclature trompeuse, mais donnent une idée générale:

Si vous essayez de comprendre ces termes en 2015, assurez-vous que la référence de quelqu'un à "Entity Component System" ne signifie pas "Entity-Component architecture".

chiot
la source
1
Ceci est la bonne réponse. ECS ne cadre pas très bien avec les paradigmes OOP, car ECS consiste à séparer les données et le comportement, tandis que OOP est à l'opposé.
Nax 'vi-vim-nvim'
"tandis que la POO est à peu près le contraire" Il n'y a pas de définition acceptée de ce qu'est la POO, à moins que des définitions académiques inutiles comme SmallTalk ne soient jamais utilisées dans la pratique.
Jean-Michaël Celerier
10

Les systèmes de composants d'entité (ECS) peuvent être programmés d'une manière OOP ou fonctionnelle selon la façon dont le système est défini.

Voie OOP:

J'ai travaillé sur des jeux où une entité était un objet composé de divers composants. L'entité a une fonction de mise à jour qui modifie l'objet en place en appelant successivement update sur tous ses composants. Il s'agit clairement de POO dans le style - le comportement est lié aux données et les données sont modifiables. Les entités sont des objets avec des constructeurs / destructeurs / mises à jour.

Manière plus fonctionnelle:

Une alternative est que l'entité soit des données sans aucune méthode. Cette entité peut exister à part entière ou simplement être un identifiant lié à divers composants. De cette façon, il est possible (mais ce n'est pas courant) d'être pleinement fonctionnel et d'avoir des entités immuables et des systèmes purs qui génèrent de nouveaux états de composants.

Il semble (par expérience personnelle) que cette dernière voie gagne en traction et pour une bonne raison. La séparation des données d'entité du comportement entraîne un code plus flexible et réutilisable (imo). En particulier, l'utilisation de systèmes pour mettre à jour des composants / entités par lots peut être plus performante et évite complètement les complexités de la messagerie interentités qui affligent de nombreux ECO POO.

TLDR: Vous pouvez le faire dans les deux cas, mais je dirais que les avantages de bons systèmes de composants d'entité découlent de leur nature plus fonctionnelle.

AGD
la source
Plus de traction d'autant plus que tout l'intérêt des composants était de s'éloigner des hiérarchies POO insolubles, bonne description de l'avantage.
Patrick Hughes
2

Les systèmes de composants d'entité orientés données peuvent coexister avec des paradigmes orientés objet: - Les systèmes de composants se prêtent au polymorphisme. - Les composants peuvent être à la fois des objets POD (données anciennes simples) et ALSO (avec une classe et des méthodes), et le tout est toujours `` orienté données '', à condition que les méthodes de classe de composants manipulent uniquement les données appartenant à l'objet local.

Si vous choisissez ce chemin, je vous recommande d'éviter d'utiliser des méthodes virtuelles, car si vous les avez, votre composant n'est plus uniquement des données de composant, plus ces méthodes coûtent plus cher à appeler - ce n'est pas COM. Gardez vos classes de composants propres de toute référence à tout élément externe, en règle générale.

L'exemple serait vec2 ou vec3, un conteneur de données avec quelques méthodes pour toucher ces données, et rien de plus.

Homère
la source
2
ce post est assez difficile à lire (mur de texte). Pourriez-vous le modifier sous une meilleure forme? En outre, il serait utile que vous expliquiez aux lecteurs pourquoi ils peuvent trouver un article de blog lié utile et pertinent pour la question posée ...
gnat
... au cas où si vous êtes en quelque sorte lié à ce blog (n'est-ce pas?), il serait également souhaitable de divulguer l'affiliation
gnat
Oui, c'est mon blog, je suis étroitement affilié à mon blog public, qui divulgue les détails d'un système de composants d'entité orienté objet basé sur des principes de conception orientés données, qui je pense est pertinent et peut-être utile, j'ai néanmoins supprimé le lien vers supprimer tout biais.
Homer
2

Je pense que ECS est fondamentalement distinct de la POO et a tendance à le voir de la même manière que vous, comme plus proche de la nature fonctionnelle ou surtout procédurale avec une séparation très distincte des données de la fonctionnalité. Il y a aussi un semblant de programmation d'un genre traitant des bases de données centrales. Bien sûr, je suis la pire personne en ce qui concerne les définitions formelles. Je me préoccupe uniquement de la façon dont les choses ont tendance à être, pas de ce qu'elles sont définies conceptuellement.

Je suppose une sorte d'ECS où les composants agrègent les champs de données et les rendent accessibles au public / au niveau mondial, les entités agrégent les composants et les systèmes fournissent des fonctionnalités / un comportement sur ces données. Cela conduit à des caractéristiques architecturales radicalement difficiles à partir de ce que nous appellerions généralement une base de code orientée objet.

Et bien sûr, il y a un certain flou des limites dans la façon dont les gens conçoivent / implémentent un ECS, et il y a un débat sur ce qui constitue exactement un ECS en premier lieu. Pourtant, ces limites sont également floues dans le code écrit dans ce que nous appelons les langages fonctionnels ou procéduraux. Parmi tous ces flous, la constante fondamentale d'un ECS avec une séparation des données de la fonctionnalité me semble bien plus proche de la programmation fonctionnelle ou procédurale que la POO.

L'une des principales raisons pour lesquelles je ne pense pas qu'il soit utile de considérer ECS comme appartenant à une classe de POO est que la plupart des pratiques SE associées à la POO tournent autour de la stabilité de l'interface publique, avec des fonctions de modélisation des interfaces publiques , pas des données. L'idée fondamentale est que la majeure partie des dépendances publiques va vers des fonctions abstraites, pas vers des données concrètes. Et à cause de cela, la POO a tendance à coûter très cher à changer les comportements de conception fondamentaux, tout en rendant très bon marché la modification de détails concrets (comme les données et le code requis pour implémenter la fonctionnalité).

ECS est radicalement différent à cet égard, compte tenu de la façon dont les choses sont couplées alors que la majeure partie des dépendances publiques se dirigent vers des données concrètes: des systèmes aux composants. En conséquence, toutes les pratiques SE associées à ECS tourneraient autour de la stabilité des données , car les interfaces (composants) les plus publiques et les plus utilisées sont en fait uniquement des données.

En conséquence, un ECS rend très facile de faire des choses comme substituer un moteur de rendu OpenGL à un moteur DirectX, même si les deux sont implémentés avec des fonctionnalités radicalement différentes et ne partagent pas les mêmes conceptions, à condition que les moteurs DX et GL avoir accès aux mêmes données stables. En attendant, cela coûterait très cher et nécessiterait de réécrire un tas de systèmes pour changer, par exemple, la représentation des données d'un MotionComponent.

C'est très opposé à ce que nous associons traditionnellement à la POO, au moins en termes de caractéristiques de couplage et de ce qui constitue une «interface publique» par rapport à des «détails d'implémentation privés». Bien sûr, dans les deux cas, les «détails d'implémentation» sont faciles à modifier, mais dans ECS, c'est la conception des données qui est coûteuse à modifier (les données ne sont pas un détail d'implémentation dans ECS), et dans la POO, c'est la conception de fonctionnalités coûteuses à modifier (la conception des fonctions n'est pas un détail d'implémentation dans la POO). C'est donc une idée très différente des «détails de mise en œuvre», et l'un des principaux appels pour moi d'un ECS du point de vue de la maintenance était que dans mon domaine, les données nécessaires pour faire les choses étaient plus faciles à stabiliser et à concevoir correctement une fois pour toutes à l'avance que toutes les différentes choses que nous pouvions faire avec ces données (qui changeraient tout le temps à mesure que les clients changeaient d'avis et que de nouvelles suggestions d'utilisateurs arrivaient). En conséquence, j'ai trouvé les coûts de maintenance en chute libre lorsque nous avons commencé à orienter les dépendances des fonctions abstraites vers des données brutes et centrales (mais toujours avec soin quels systèmes accèdent à quels composants pour permettre de maintenir les invariants à un degré raisonnable malgré toutes les données conceptuellement étant accessible au niveau mondial).

Et dans mon cas au moins, le SDK ECS avec l'API et tous les composants sont réellement implémentés en C et ne ressemble en rien à la POO. J'ai trouvé C plus que suffisant pour un tel objectif étant donné le manque inhérent d'OO dans les architectures ECS et le désir d'avoir une architecture de plugin qui peut être utilisée par la plus large gamme de langages et de compilateurs. Les systèmes sont toujours implémentés en C ++ car C ++ rend les choses très pratiques là-bas et les systèmes modélisent l'essentiel de la complexité et là je trouve utile pour beaucoup de choses qui pourraient être considérées comme plus proches de la POO, mais c'est pour les détails d'implémentation. La conception architecturale elle-même ressemble toujours à un C. très procédural

Je pense donc qu'il est un peu déroutant, à tout le moins, d'essayer de dire qu'un ECS est OO par définition. À tout le moins, les principes fondamentaux font un virage complet à 180 degrés par rapport à bon nombre des principes fondamentaux généralement associés à la POO, à commencer par l'encapsulation et peut-être se terminant par ce qui serait considéré comme les caractéristiques de couplage souhaitées.


la source