Journal entity.JS - un "Entity System" en JavaScript

Posté par  . Licence CC By‑SA.
28
14
mar.
2013

Sommaire

J'ai commencé un "Entity component system" en JavaScript. Il s'agit d'une architecture logicielle non orientée objets, plus flexible pour créer des jeux. Plusieurs grands jeux multijoueurs en ligne qui sont sortis ces dernières années utilisent au moins en partie cette architecture (Battlefield 3, Tony Hawk Pro Skater).

Entity System

On pourrait traduire "Entity component system" en français par "Entité composant système". Personnellement j'utilise le raccourci ES pour "Entity System", que j'ai souvent rencontré.

D'un point de vue architecture, ce qui est important dans un ES ce sont les entités, les composants et les systèmes.

Les composants sont les briques de base. Ils représentent un aspect d'une entité et contiennent les données correspondant à cet aspect. Les composants ne contiennent aucune logique de jeu, contrairement à la POO (Programmation Orientée Objets). Donc les méthodes des composants (s'il y en a) ne sont que de simple getters et setters, qui ne font aucune opération sur les données.
En fait l'idée est de mettre la logique du jeu dans les systèmes. Le fait de découpler la logique de l'endroit où sont stockée les données supprime en grande partie la structuration de celles-ci, ce qui diminue la rigidité du jeu, permettant de plus facilement le modifier.
Exemples de composants avec leur propriétés (données):
- Position: peut avoir les propriétés x et y. Une méthode possible pourrait être setPosition(x, y)
- Mobile: peut avoir les propriétés vitesse et direction.
- Projectile peut avoir la propriété dégâts.

Plusieurs composants peuvent être liés entre eux pour former des entités. Il n'y a aucune restriction sur quels composants peuvent être liés ensemble, et de nouveaux composants peuvent être rajoutés ou supprimés à tout moment du jeu. Par exemple vous pouvez lier des composants de type Position, Mobile et Projectile pour faire un missile. Vous stockez la position du missile, sa vitesse, sa direction et combien de dégâts il causera dans ces composants. Il vous faudra peut-être aussi un composant indiquant quelle image utiliser pour l'affichage à l'écran, etc. Vous pouvez ajouter tous les composant que vous voulez. Cet ensemble de composants est ce qu'on appelle une entité.

Conceptuellement, une entité est une liste de composants. Rien de plus, rien de moins. (Pas de donnée, pas de logique de jeu non plus). Quelques exemple d'entités: un personnage, un missile, une arme, un objet, une ville, un paysage, une bulle de dialogue, etc.
Les entités n'ont pas de type. Le "type" d'une entité est quelque chose de très fluide qui change en fonction de ses composants. Il est facile de faire voler un chien ou de zombifier n'importe quel personnage ou animal juste en rajoutant quelques composants. (Et si tout d'un coup vous pensez que ce serait bien dans votre jeu d'avoir des maisons zombifiées, vous n'êtes pas obligé de changer toute la structure du code de votre maison. Il suffit de rajouter quelques composants)

La logique du jeu se trouve dans les systèmes. Mais tout n'est pas mélangé. On compartimente par "aspects". Chaque système ne traite qu'un certain type de composants. Par exemple un système Déplacements va chercher tous les composants Position et Mobile, puis modifier la position en fonction de la vitesse et de la direction. Cela se fait en cherchant parmi toutes les entités du jeu, celles qui lient un composant Position et un composant Mobile, et en traitant ces deux composants. Un système ne s'intéresse donc qu'a un nombre restreint de type de composants et ne se demande pas si l'entité qui possède ces composants est un missile, un chien ou une maison.

Le comportement et l'aspect des objets du jeux est défini par les composants qu'il possède. Les comportements sont codés dans des systèmes différents qui sont exécutés en boucle en cour de jeu. La plupart des systèmes sont indépendants, ce qui permet de facilement les paralléliser, d'en ajouter, d'en modifier, etc..

En fait si on compare, en programmation OOP on a les données et les logiques dans les entités (les objets). Avec un ES on vide les entités en mettant les données dans les composants et les logiques dans les systèmes. D'ailleurs plusieurs implémentations d'ES représentent une entité uniquement par son numéro (et non par un objet), et chaque composant enregistre le numéro de l'entité à laquelle il est associé.

Je ne vais pas entrer plus en détails sur les avantages et les inconvénients des ES. Mon but est juste d'introduire les concepts de base pour ceux qui ne connaissent pas, car les informations disponibles sur le web sont toutes en anglais. Mais si vous avez d'autres sources d'informations je serai ravi de les connaître.

Pour aller plus loin:
Un article bien fait pour commencer et qui permet de comprendre les avantages des ES étapes par étapes: http://www.richardlord.net/blog/what-is-an-entity-framework
Un wiki central sur les ES avec toutes les informations disponibles: http://entity-systems.wikidot.com/

entity.JS

Ca c'est le projet. Un ES (Entity System) en JavaScript plutôt orienté rapidité et efficacité. La licence sera la licence MIT.

Pour l'instant, il n'y a pas de code. Le but c'est de faire l'API en premier et ensuite de faire le code. Le premier brouillon de l'API se trouve ici: http://lite.framapad.org/p/Wbo5sHqiD2

Voilà, ça m'a pris pas mal de temps pour faire ce premier brouillon, et je cherche à avoir des retours. Je voudrais aussi savoir qui est intéressé par ce concept. Et qui voudrait participer ou suivre le développement. C'est encore le tout début du projet, donc il y a déjà des idées, mais rien n'est encore complètement défini. Si cela vous intéresse, contactez-moi à travers linuxfr.org, ou laissez un commentaire. J'avertis juste que le développement se fera en anglais.

Voici un peu ce qu'il est prévu de faire (pas forcément dans cet ordre, et ça va dépendre de mon temps libre):
- recevoir des retours sur l'API, discuter, modifier (ou pas :P )
- finir d'écrire le brouillon contenant les lignes directrices de l'implémentation de l'API (comment organiser les données, lister les optimisations possibles, expliquer certains choix de l'API)
- ré-écrire le brouillon de l'API au propre avec des couleurs, un formatage correct et des exemples de code
- d'ici 2-3 semaines (c'est toujours plus long que ce qu'on prévoit…): commencer l'implémentation de l'API
- ouvrir un repo sur github, y mettre l'API et le code

En plus du projet entity.JS, il y a le projet de faire un framework de jeu basé sur entity.JS et Node.js et qui pourra supporter canvas et webgl ainsi que tout ce qui peut être utile dans un jeu. Cela n'est pas toujours évident. Par exemple les moteurs de rendu webgl s'attendent à des données structurées sous une forme OOP, ce qui demande soit de modifier une bonne partie du moteur, soit de faire un pont entre les 2 structures de données (généralement aux dépends des performances). Je suis en discussion avec un développeur de moteur de rendu webgl 2D, mais mes connaissances dans ce domaines sont minces (1 projet OpenGL basique en Java il y a quelques années). Donc si d'autres personnes sont intéressées, elles sont les bienvenues.

Si vous avez des questions, n'hésitez pas. J'essaierai de répondre au mieux.

  • # ChromaShift, un exemple concret

    Posté par  (site web personnel) . Évalué à 1.

    Merci beaucoup pour cette présentation !
    J'ai découvert cette architecture il y a quelques semaines en m'intéressant à l'utilisation de programmation fonctionnelle dans le cadre d'un jeu vidéo.

    J'étais tombé sur cet article de Chris Granger qui présente un jeu écrit en ClojureScript :
    http://www.chris-granger.com/2012/12/11/anatomy-of-a-knockout/

    Pour ceux qui veulent fouiller un peu plus les sources sont disponibles sur son github :
    https://github.com/ibdknox/ChromaShift

    • [^] # Re: ChromaShift, un exemple concret

      Posté par  . Évalué à 1.

      Merci, je ne connaissais pas. Je vais peut-être contacter ce Chris Granger, ça pourrait être intéressant.

      Ca m'a également permis de découvrir Light Table. Projet à suivre. (Malheureusement je ne connais pas ClojureScript, mais apparemment il va ajouter d'autres langages à son IDE)

      • [^] # Re: ChromaShift, un exemple concret

        Posté par  (site web personnel) . Évalué à 1.

        Je suis de loin l'évolution de LightTable (que j'ai connu en lisant cet article) en testant un peu le programme à chaque annonce de mise à jour.

        Le projet est intéressant et le résultat donne envie je trouve (enfin … surtout depuis la 0.3, parce qu'avant ça ressemblait plus à un joli notepad++ qu'autre chose). Javascript est déjà en partie supporté (il en parle rapidement ici), mais pour le moment l'intégration n'est pas aussi bonne que pour Clojure.

        Et comme le projet a dépassé les 300k$ sur Kickstarter, python devrait normalement être le prochain langage à être supporté :

        If we hit $300k, Python will be the third language to be supported out of the gate.

        Comme tu dis, c'est un projet à suivre :)

  • # Un autre « framework » : ma vie mon œuvre

    Posté par  . Évalué à 6.

    C'est « marrant », j'ai passé 4 ans de ma vie à faire une thèse sur l'aide au développement des systèmes multi-agents (SMA).

    Un SMA : un truc avec pleins d'entités qui interagissent entre elles et qui sont régis par leur environnement sur certains aspects.
    Ça vous fait penser à quelque chose ?

    Les gens qui bossent sur les SMAs s'en foutent un peu de savoir comment ils sont implémentés, mais c'est ce à quoi je me suis intéressé.

    Et la solution à laquelle je suis arrivée ressemble TRÈS fortement à l'architecture ES que tu viens de nous présenter.
    Je parles bien de l'architecture de l’implémentation d'un SMA, et non pas de l'architecture des SMA eux-même : de la même façon qu'un jeu a une architecture différente selon les types d'entités représentées,leur comportement, leur capacités ; tout les jeux peuvent être implémentés en utilisant une architecture ES.

    Ça prend la forme d'une grosse thèse, et puis d'une implem sous forme d'un langage de description d'architectures implémentables en Java.

    Le modèle est plus « simple » qu'un ES, il est composé d'espèces et d'écosystème (le parallèle « serait » entité et système), il est récursif (des ES composés d'ES en quelque sorte) et s'appuie sur une brique de base qui est un peu plus riche qu'un composant logiciel (l'écosystème).
    Le composant n'est qu'une version simplifié d'un écosystème au final.

    C'est pas pareil, mais ça y ressemble quand même beaucoup et c'est pas étonnant, vu que les jeux vidéos ont des organisations qui sont très proches de celles des SMAs !

    Je rentre pas dans les détails ici, si il y a des gens intéressés vous pouvez toujours vous taper ma thèse (http://www.irit.fr/~Victor.Noel/PhD/Dissertation) ou regarder l'outil d'aide au développment (http://www.irit.fr/~Victor.Noel/Projects/MAY) qui n'est bien sûr que trop peu documenté.

    • [^] # Re: Un autre « framework » : ma vie mon œuvre

      Posté par  (site web personnel) . Évalué à 2.

      C'est marrant, j'ai développé un SMA dans lequel chaque agent est dirigé par une machine à état hiérarchique fini (pas encore mis sur github, code trop crade).
      Est-ce que ce serait un sous ensemble de ton approche ?

      « Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker

      • [^] # Re: Un autre « framework » : ma vie mon œuvre

        Posté par  . Évalué à 2.

        Je pense que non, car mon approche ne permet pas d'implémenter des agents, mais l'architecture nécessaire à l'implémentation d'un agent :)

        En gros, ça permet, par composition, de choisir quels mécanismes lient l'agent à son environnement.

        Un peu comme les systèmes « lient » les entités entre elles et dans leur environnements selon plusieurs aspects.

        Une façon simple de voir si c'est comparable ou non, c'est de répondre à cette question : comment tes agents interagissent entre eux et avec leur environnement ?

        • [^] # Re: Un autre « framework » : ma vie mon œuvre

          Posté par  (site web personnel) . Évalué à 2.

          Mes agents interagissent avec les autres et leur environnement par un mécanisme fourre-tout : les évènements.

          En gros, chaque transition de l'automate se fait si l'équation booléenne exécutée rend vrai, et cette équation se type ainsi :

          type 'event transition =
            | Condition    of (unit -> bool)
            | Event        of 'event * (unit -> 'event list )
            | EventOr      of 'event * (unit -> 'event list ) * 'event transition
            | EventAnd     of 'event * (unit -> 'event list ) * 'event transition
            | EventXor     of 'event * (unit -> 'event list ) * 'event transition
            | EventNot     of 'event * (unit -> 'event list )
            | ConditionOr  of (unit -> bool)   * 'event transition
            | ConditionAnd of (unit -> bool)   * 'event transition
            | ConditionXor of (unit -> bool)   * 'event transition
            | ConditionNot of (unit -> bool);;
          
          

          T'as pas un abstract ou un brouillon français de ta thèse (la flemme de lire en anglais ^^ ) ?

          « Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker

          • [^] # Re: Un autre « framework » : ma vie mon œuvre

            Posté par  . Évalué à 2.

            Donc ce n'est pas du tout la même chose, je ne me situe pas au niveau de "l'architecture interne" des agents (genre ton automate permet de décrire comment ça marche dedans), mais je me situe à l'extérieur, au niveau de l'interaction, et mon objectif est de permettre d'avoir des moyens d'interaction, mais aussi des mécanismes d'exécution (scheduling, connections au reste du monde, connexion à l'environnement) qui soient tous le plus proche du problème.
            Au final, on est plus dans la fabrication de framework/plateforme SMA, que dans la fabrication de SMA directement (mais comme l'idée sur laquelle je m'appuie est qu'il n'est pas possible d'échapper à la fabrication de ce framework quand on fabrique des SMA, alors ça aide au dev des SMA).

            En français j'ai bien un article de journal, je peux te l'envoyer par mail (pas le droit de le diffuser publiquement…), envoie moi un message, ça me ferait plaisir d'être lu, même partiellement :]

            Mon argument, c'est que si tu utilises un truc comme le tiens, tu es obligé de traduire ta solution à ton problème dans le "langage" de tes concepts, un peu comme quand on fait de l'objet, on traduit toute interaction en éléments du système sous forme de méthode.
            Comme c'est un peu limitant en terme d'abstraction, la communauté du dev (industrielle et académique) a fait des design pattern, des frameworks, qui permettent de palier ces limitations, et ça marche bien.
            Mais dans les SMAs, enfin en tout cas dans ceux que j'étudie, on a une conception tellement proche du problème et tellement éloignée de l'implémentation, que ces "contraintes", ces limitations sont trop importantes, on a besoin pour implémenter son SMA d'abstraction ultra adaptées au problème (genre on veut pouvoir raconter dans son implem que notre agent envoie des messages, mais perçoit ses voisins, ce voisinage étant maintenu par l'environnement car il est dynamique et représente l'extérieur du système qu'on ne contrôle pas, qu'il y a des échanges en local mais aussi à distance, qu'ils ne doivent pas être gérés de la même façon par l'agent, etc, et d'autres trucs comme ça).
            Et donc, mon truc permet de fabriquer ces abstractions adaptées au problème, ou plus précisément d'en réutiliser pour les composer et faire sa plateforme SMA maison.

            C'est là qu'on fait le lien avec les ES, au final, ça semble permettre de définir et de réutiliser des systèmes entre différents jeux, pour les composer dans les entités et définir leur structure et leur dynamique de façon très adaptée et très proche du problème que l'on veut modéliser.
            Et on peut mettre dans ces systèmes l'implémentation de ces différentes préoccupations de façon bien séparée.
            Forcement, tout les gens qui bossent sur le jeux retrouvent leur billes sans aucun "gap" entre ce qu'ils ont dans la tête (des tanks qui se déplacent, qui ont une tourelle) et la façon dont c'est organisé dans l'implémentation (l'entité tank et tout les composants qui la concernent, et les systèmes qui l'intègrent au reste du monde).
            En objet, chacun de ces concepts se seraient retrouvés un peu partout dans différentes parties du code il me semble.

    • [^] # Re: Un autre « framework » : ma vie mon œuvre

      Posté par  . Évalué à 1.

      L'architecture ES est en fait très simple, je pense même beaucoup plus simple à comprendre que l'architecture POO avec ses classes et ses objets. Elle est souple et très puissante, ça ne m'étonne pas du tout que ça puisse être utilisé ailleurs que dans des jeux, bien que je ne pense pas que ce soit adapté pour faire une des interfaces graphiques (GUI) par exemple.

      D'ailleurs entity.JS permet de faire des ES, mais ce n'est pas spécifiquement orienté vers le développement de jeux vidéos. entity.JS peut être utilisé dans n'importe quel projet JavaScript tout en offrant de bonnes performances (notamment peu, voir pas de GC).

      Juste une question. Qu'entends-tu par un ES récursif ?

      qui n'est bien sûr que trop peu documenté.

      Fallait commencer par la doc :P

      • [^] # Re: Un autre « framework » : ma vie mon œuvre

        Posté par  . Évalué à 2.

        Je ne suis pas sûr que ce soit vraiment comparable en terme d'abstractions : d'un côté on a des entités, des systèmes et des composants, de l'autre, on a des écosystèmes et des espèces qui ne peuvent exister qu'au sein d'un écosystème.

        Mais si on triche un peu et qu'on fait un parallèle, alors un ES récursif serait un ES dont certaines des entités et/ou des systèmes sont eux-même définis par un ES, et que le lien entre le contenant et l'ES contenu soit cohérent avec les ES.

        Tu vois l'idée ? Je ne suis pas sûr que ce soit applicable aux ES en fait…
        Dans mon approche, en fait sans cette récursivité, ça sert à rien, on peut rien faire, un peu comme si on avait de la prog orienté composant mais sans composant composites : ce serait chiant :)

        • [^] # Re: Un autre « framework » : ma vie mon œuvre

          Posté par  . Évalué à 1.

          Eh eh, oui c'est possible, par exemple si tu mets un jeu dans un jeu. Par exemple tu es dans un MMORPG et tu va vers une console et tu peux jouer à un jeux dessus.

          Enfin bon s'est un peu tiré par les cheveux…

          • [^] # Re: Un autre « framework » : ma vie mon œuvre

            Posté par  . Évalué à 2.

            Oui, là la récursivité est un peu différente, c'est pas simplement un truc dans un truc, mais c'est un truc pour fabriquer un autre truc…

            Bon, je sais pas, je crois que c'est juste différent, mais je suis très content de voir que mon approche ressemble à un paradigme qui est utilisé sérieusement dans l'industrie, ça veut dire que mon travail n'est pas complètement loufoque :)
            Je dis ça parce qu'il est utilisable (et utilisé en pratique), mais il y a quand même beaucoup d'idées qui en font un truc élégant et beau théoriquement, mais qui en pratique est juste lourdingue à utiliser pour le moment (en particulier cette récursivité qui apporte la réutilisation et la composition des différents « aspects » (i.e. les systèmes des ES).

            Je pense que j'y réfléchirais plus précisément pour en faire une analyse comparée dans le futur !

  • # Objet toujours

    Posté par  (site web personnel) . Évalué à 3.

    Ca ressemble beaucoup au pattern role!

    J'avais envisagé la même chose pour Webcrise:

    https://linuxfr.org/users/devnewton/journaux/webcrise-ebauche-d-architecture

    Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.

    • [^] # Re: Objet toujours

      Posté par  . Évalué à 1.

      Tu en es où dans Webcrise ? As-tu un lien ?

      J'essaie de regarder le code de jeux implémentés avec un ES pour voir les besoins, les difficultés et trouver des idées. Donc si ton code est assez proche d'un ES, ça m'intéresse.

  • # Moteur de rendu

    Posté par  (site web personnel) . Évalué à 5.

    Pour le rendu, tu peux regarder du côté de three.js assez impressionant (pour du javascript…) qui peut utiliser canvas ou webgl.

    http://mrdoob.github.com/three.js

    Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.

    • [^] # Re: Moteur de rendu

      Posté par  . Évalué à 1. Dernière modification le 15 mars 2013 à 13:48.

      Pour un moteur 3D ça semble bien. Je suis en train de regarder la doc. Faudrait faire une interface entre les objets de Three.js et les composants de l'ES, mais peut-être qu'on peut utiliser Object.defineProperty() dans les composants avec des setters qui écrivent directement les données dans les objets de Three.js. Cela pourrait être pas mal, à défaut d'un vrai moteur 3D implémenté en ES :)

      Par contre il y a une chose sur laquelle j'ai encore plein de questions. Comment représenter une hiérarchie d'objets avec des composants qui par définition sont stockés dans une structure plate et non ordonnée. Par exemple, comment implémenter un scenegraph avec des composants qui permet d'avoir des sous objets dont la position dépend d'un objet parent ? Concrètement, le bras d'un personnage dépend du personnage, il suffit de bouger le personnage et toutes les parties du corps sont automatiquement à la bonne place.

      • [^] # Re: Moteur de rendu

        Posté par  (site web personnel) . Évalué à 2.

        Pourquoi ne pas simplement traiter le scenegraph et ses noeuds comme des composants?

        Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.

      • [^] # Re: Moteur de rendu

        Posté par  . Évalué à 2.

        Par exemple, comment implémenter un scenegraph avec des composants qui permet d'avoir des sous objets dont la position dépend d'un objet parent ?

        Une possibilité :

        composant Transformation
            vec2 localPosition, worldPosition;
            float localRotation, worldRotation;
            Entity parent; // optionnel
        
        

        Les coordonnées local* sont définies dans le repère du parent.
        Les systèmes qui veulent modifier la position d'une entité manipulent les attributs local*.
        Le système de Transformation détermine les attributs world* en fonction de local* et du parent si il y en a un), sinon world* = local*

        • [^] # Re: Moteur de rendu

          Posté par  . Évalué à 1.

          C'est pas mal pour l'update: les systèmes n'ont à s'occuper que des attributs local*

          Par contre lors du rendu graphique, c'est plus compliqué. Lorsque le système de rendu graphique fait l'itération des composants Transformation, à chaque fois qu'il y a un parent, il devra passer par le parent. Donc les parents sont visités au moins autant de fois qu'ils ont d'enfants (et de sous enfants). En POO et OpenGL on commence toujours par les parents et on descend la hiérarchie en multipliant les matrices de position à chaque étape. Au final chaque objet n'est visité qu'une fois.

          C'est vrai qu'en ES l'itération peut être optimisée car on peut mettre tous les composants dans un seul tableau à la suite, et donc le CPU peut optimiser les accès mémoire. Mais là on doit visiter tous les composants parents plusieurs fois, et je me demande s'il ne serait pas possible de faire mieux. Par exemple en définissant des composants TransformationEnfant et des composants TransformationParent, ou d'autres idées du même style. Car il ne faut pas oublier que les composants ne sont pas ordonnés, et donc l'itération avec un type de composant se fait dans le "désordre".

          Revenons à ton exemple. Il suffirait de rajouter un boolean qui indique si les coordonnées world* ont déjà été recalculées à partir du parent, afin de limiter un peu le nombre de visites. A partir d'un enfant on ne remonterai alors plus que d'un niveau dans la hiérarchie, sauf si le parent n'a pas encore été recalculé. (Bon en fait au lieu d'un boolean j'utiliserai un int qui contiendrai un numéro incrémenté à chaque game loop, mais c'est pour l'idée). Pour l'instant, c'est un système de ce style que j'utiliserai.

          • [^] # Re: Moteur de rendu

            Posté par  . Évalué à 1.

            C'est pas mal pour l'update: les systèmes n'ont à s'occuper que des attributs local*
            Par contre lors du rendu graphique, c'est plus compliqué. Lorsque le système de rendu graphique fait l'itération des composants Transformation, à chaque fois qu'il y a un parent, il devra passer par le parent.

            Pas vraiment.
            Le système qui s'occupe du rendu utilise les coordonnées world* uniquement, puisqu'il n'est intéressé que par la position absolue des objets, pas leur position relative (et c'est le cas de la plupart des systèmes : ils ne sont intéressés que par la position absolue d'un objet).

            Par contre, lors de sa mise à jour le TransformationSystem fait effectivement la recherche du parent pour chaque entité (avec une mini-optim ressemblant à celle que tu décris).

            • [^] # Re: Moteur de rendu

              Posté par  . Évalué à 1. Dernière modification le 15 mars 2013 à 16:34.

              Je n'y avais pas pensé comme ça, c'était trop simple. Je garde l'idée merci :)

              En fait, vu que l'update se fait moins souvent que le rendu, ça permet d'éliminer beaucoup de multiplications de matrices et donc d'avoir un rendu encore plus rapide.

  • # Objection

    Posté par  (site web personnel) . Évalué à 6.

    Voici l'objection d'un pote après que j'eu partagé le lien :

    "Et perso je reste farouchement opposé à ce type d'approche. C'est incontestablement très élégant, mais quand on se retrouve avec le code path de la main loop éparpillé un peu partout, le debug devient tout de suite beaucoup moins évident, car suivre l'exécution devient un jeu de piste."

    Des gens ont la même expérience ?

    • [^] # Re: Objection

      Posté par  . Évalué à 3.

      J'ai plutôt l'expérience inverse.
      Pour nos jeux, nous utilisons cette architecture. Aucune classe n'a de méthode update, excepté les systèmes. La main-loop ressemble donc à ça :

      read_input
      for_each system do
          system.update(dt)
      render()
      
      

      Pas non plus de système de callback/messagerie pour venir intercaler des appels de fonction type onMessage() qui casse l'aspect séquentiel.

      Je trouve le résultat plutôt simple à comprendre et à debugger - mais c'est peut-être parce que c'est moi qui l'ai écrit :)

      • [^] # Re: Objection

        Posté par  (site web personnel) . Évalué à 3.

        Oui, j'allais dire, c'est étrange, car à première vue, même si la programmation de jeux vidéos n'est pas du tout ma spécialité, j'ai du mal à voir en quoi c'est forcément plus difficile de debugger ce genre de code, c'est juste une "philosophie" de code path différente. Après, ça dépend probablement de la pureté en ES du code, si on a mélangé un peu les concepts entre eux, ça rend peut-être la chose indigeste…

        • [^] # Re: Objection

          Posté par  . Évalué à 3.

          C'est ce que je pense aussi, mais il y a aussi parfois des contraintes externes.

          L'architecture ES est relativement nouvelle, et il y a plusieurs façon de faire les choses. J'ai essayé de la présenter de façon pure dans ce journal, car c'est le chemin que je vais suivre pour entity.JS. Mais si tu va sur le wiki http://entity-systems.wikidot.com/ tu verra d'autres façons de faire.

          En plus c'est un changement important de paradigme et les programmeurs ont souvent de la difficulté à ne pas remettre de la POO (Programmation Orientée Objets) dans leur code ES, même de façon inconsciente. Et ça m'arrive aussi :)

          Souvent quand on essaie d'en parler, on se retrouve confronté à pas mal de résistance au début (et c'est normal). Voir cet article: Evolve your hierarchy du jeu Tony Hawk's Pro Skater 3, où l'auteur est amené à faire des migrations progressives vers l'ES.

    • [^] # Re: Objection

      Posté par  . Évalué à 2.

      C'est vrai, mais ça vient surtout, à mon avis, du fait que les outils de debug qu'on a actuellement on été fait pour autre chose que ce paradigme de programmation !

      j'irais jusqu'à dire qu'avec des outils de debug ES sur du code ES, ce sera mille fois mieux que du debug OO sur du code OO :)

      Il y a donc encore du boulot : l'argument de ton pote est valide dans une vision court terme !

    • [^] # Re: Objection

      Posté par  . Évalué à 6. Dernière modification le 15 mars 2013 à 13:33.

      Merci pour ce retour.

      C'est vrai, au lieu d'avoir une grande "game loop", on se retrouve avec une liste de systèmes appelés les uns après les autres. Pour autant, ça dépend vraiment de comment tu fais ta game loop. Si elle se résume à une suite d'appels vers d'autre fonctions, alors ça revient un peu au même que d'utiliser des système, la flexibilité en moins. Si une bonne partie du code du jeu se retrouve dans la game loop, alors je te dirai qu'il faut peut-être revoir la structure de ton jeu.

      Mais ça dépend aussi de la taille du jeu. Pour un petit jeu, il vaut peut-être mieux utiliser une architecture plus simple qu'un ES. A l'origine l'architecture ES est faite pour supporter des jeux avec des millions d'objets différents du style des MMORPG où les données sont stockées dans des bases de données, et où des centaines de personnes travaillent en même temps sur le jeu. (Ce qui ne l'empêche pas de marcher pour des plus petits jeux évidemment)

      Maintenant c'est vrai que le code est éparpillé mais ce n'est pas fait n'importe comment et l'architecture permet de s'y retrouver et de limiter les erreurs si on respecte les règles.

      Pour le code path lors d'un débug, tout n'est pas mélangé car chaque système ne va toucher qu'à un nombre restreint de composants (souvent 1 ou 2). Dans le brouillon de l'API, chaque système doit exposer quels composants il va toucher avant d'être initialisé, puis lorsqu'il est initialisé, il va recevoir uniquement des références vers les composants qu'il a demandé. En plus de permettre d'optimiser l'utilisation des composants pour chaque système, cela permet d'inspecter quel système touche quel composant, ce qui simplifie le débogage.

      Ensuite, mon idée est d'avoir des groupes de système avec la possibilité de les hiérarchiser. Par exemple les groupes: update, update.AI, update.environement, update.physics, render, render.images, … Ensuite on ajoute les systèmes au bon groupe, et tout peut s'exécuter à la suite. Tu peux regarder l'objet ExecutionHandler dans le brouillon, qui permet de faire des groupes d'exécution. (Et qui va optimiser l'exécution en gardant à jour une liste de systèmes à exécuter dans l'ordre.)

      L'intérêt c'est qu'on peut faire des "méta opérations" sur les systèmes comme par exemple mettre en pause un groupe ou calculer le temps d'exécution d'un système ou processus de façon simple et intégrée au navigateur. Voir pourquoi pas lors du développement, insérer des fonction avant/après l'exécution d'un système pour vérifier des conditions spécifiques.

      J'espère avoir répondu un peu à ta question.

      PS: Tu peux voir ici un exemple de relations entre les systèmes et les composants dans un jeu: System-Component Dependencies tiré de l'article The Components and Systems of Morgan's Raid.

      • [^] # Re: Objection

        Posté par  (site web personnel) . Évalué à 2.

        Génial, merci pour cette super réponse, aussi intéressante que ton journal.

        • [^] # Re: Objection

          Posté par  . Évalué à 1.

          C'est un plaisir.

          Un des autres avantages de ES (Entity System), c'est que c'est beaucoup plus simple pour des non-programmeurs (graphistes, concepteurs de jeux, etc.) à comprendre et à modifier sans tout casser, car il n'y as pas besoin de se conformer à une structure de classe rigide et à sa hiérarchie. Tout est directement visible dans le code d'un système ou de quelques systèmes et facile à changer en cas de besoin. Dans la plupart des cas, il suffit de rajouter les composants voulus aux entités voulues et ça tourne.

          Ca peut même se faire facilement en plein jeu, ce qui fait que la création d'un éditeur de carte par exemple est très facile et se base simplement sur l'interface de jeu normale. Ensuite pour enregistrer la carte, il suffit d'enregistrer les composants, ce qui correspond à un simple dump des composants dans un fichier. Pas besoin de sérialiser des objets, les données sont déjà sous forme sérialisée en mémoire :)

        • [^] # Re: Objection

          Posté par  . Évalué à 6.

          C'est un plaisir.

          Un des autres avantages de ES (Entity System), c'est que c'est beaucoup plus simple pour des non-programmeurs (graphistes, concepteurs de jeux, etc.) à comprendre et à modifier sans tout casser, car il n'y as pas besoin de se conformer à une structure de classes rigide et à sa hiérarchie. Tout est directement visible dans le code d'un système ou de quelques systèmes et facile à changer en cas de besoin. Dans la plupart des cas, il suffit de rajouter les composants voulus aux entités voulues et ça tourne.

          Ca peut même se faire facilement en plein jeu, ce qui fait que la création d'un éditeur de carte par exemple est très facile et se base simplement sur l'interface de jeu normale. Ensuite pour enregistrer la carte, il suffit d'enregistrer les composants, ce qui correspond à un simple dump des composants dans un fichier. Pas besoin de sérialiser des objets, les données sont déjà sous forme sérialisée en mémoire :)

  • # Framapad bac à sable

    Posté par  . Évalué à 2.

    J'ai mis le brouillon sur framapad exprès pour qu'on puisse y ajouter tous les commentaires voulus.

    Apparemment quelques personnes ne connaissant pas le concept des framapad (etherpad) font des tests et cassent les liens qui s'y trouvaient. C'est normal, j'ai fais ça aussi la première fois…

    Donc tout spécialement pour ceux qui veulent découvrir framapad, je vous conseille d'aller voir ce lien: https://framapad.org/ puis soit de se faire un pad, soit d'utiliser le pad de test pour faire vos propres expériences. Vous verrez, c'est vraiment très pratique.

    Veuillez m'excuser, j'aurai dû inclure ce message dans le journal.

    J'ai donc rétabli les liens et ce qui était cassé. En plus je recopie les liens vers les brouillons ici:
    - Design: http://lite.framapad.org/p/kQVEUslyvE
    - API: http://lite.framapad.org/p/GhOo1ivlba

  • # Différent ?

    Posté par  . Évalué à 3.

    Je ne vois bien en quoi c'est différent de la POO où on a souvent les objets du « modèle » qui ne contiennent que des getters/setters et où le traitement des données se fait dans d'autres objets.

    « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

    • [^] # Re: Différent ?

      Posté par  . Évalué à 2. Dernière modification le 15 mars 2013 à 18:01.

      Effectivement expliqué comme ça, ça a l'air pareil. On peut tout à fait modéliser un ES dans un langage POO. Est-ce que dans ton cas, tu as une vraie séparation de la logique et des données ? Comment fais-tu pour modifier le comportement de ton modèle ? Comment sont stockés les objets du "modèle" ? Est-ce que le type du modèle est défini par le modèle ou uniquement par ses objets, ce qui permet de transformer un modèle en n'importe quel autre en changeant ses objets ?

      Sinon, tu peux essayer de lire http://www.richardlord.net/blog/what-is-an-entity-framework Peut-être que ça t'aidera à mieux voir les subtilités entre des architectures qui paraissent proches ?

    • [^] # Re: Différent ?

      Posté par  (site web personnel) . Évalué à 3.

      La POO englobe l'ES.

      • [^] # Re: Différent ?

        Posté par  . Évalué à 3.

        Oui, mais de la même façon que la machine de turing englobe l'objet : c'est pas très pratique :)

        • [^] # Re: Différent ?

          Posté par  (site web personnel) . Évalué à 1.

          Il n'y avait pas grand chose à répondre de plus à partir du moment où moult commentaires au dessus et le journal lui-même expliquent clairement les spécificités de ce paradigme…

    • [^] # Re: Différent ?

      Posté par  (site web personnel) . Évalué à 3.

      De manière générale, la POO est plus contraignante que la programmation par composant (y en a qui aiment être très contraints par le langage, moi j'aime bien quand le langage me fiche un peu la paix…). La programmation par composant te permet une souplesse au runtime que la POO ne te permet pas. Par exemple, avec un ECS tu peux proposer a l'utilisateur un editeur d’entité ou il pourra construire lui même son entité customisee. Avec la POO pour faire ca tu devrais avoir une classe qui hérite de tous les objets de bases, ce qui est assez infâme.

    • [^] # Re: Différent ?

      Posté par  . Évalué à -1. Dernière modification le 16 mars 2013 à 03:39.

      C'est pas de la programmation objet ca, c'est des structs un peu moins casse couilles a utiliser. De l'imperatif quoi.
      Le concept meme de l'objet c'est d'encapsuler la logique avec les donnees.

      Dit autrement, si la plupart de ton "modele" ne contient que des getter/setter, t'as un gros probleme de conception.

      Linuxfr, le portail francais du logiciel libre et du neo nazisme.

  • # "Talk is cheap, show me the code!"

    Posté par  (site web personnel) . Évalué à 6.

    Je sais qu'il y a deux écoles, mais pour pas beaucoup plus de temps que tu as passe a écrire cette doc,
    tu pourrais avoir un début de première implémentation qui marche. Ça t'aurait permis de trouver tout
    un tas de problèmes de designs en l’implémentant, car en réfléchissant sur le papier tu n'as aucun
    garde-fou, alors qu'en implémentant, si une idée ne fonctionne pas, ça se voit tout de suite.

    En codant des tests unitaires en même temps, les tests deviennent une spécification, c'est juste
    qu'elle est écrite en JS au lieu d’être écrite en anglais.

    Sinon, les ECS c'est la vie, j'ai deux projets en cours basés plus ou moins sur ce paradigme
    (un en C++, l'autre en JS), et j'en suis très content.

    Bon courage pour la suite, mais réveille moi quand t'as du code qui tourne :)

    • [^] # Re: "Talk is cheap, show me the code!"

      Posté par  . Évalué à 2.

      Merci. En fait, c'est la première fois que je commence vraiment par la documentation. Souvent en javascript la seule doc que j'écris c'est le code…

      T'inquiètes pas, je reviendrai faire du bruit par ici quand il y aura un peu plus de contenu.

      A part ça, si c'est possible de lire ton code quelque part, ça m'intéresse pour voir comment tu utilises l'architecture ES, comment tu initialises ton jeu et comment tu intègres l'ES et son environnement par exemple.

  • # Project online

    Posté par  . Évalué à 1.

    • [^] # Re: Project online

      Posté par  . Évalué à 1. Dernière modification le 25 mars 2013 à 14:06.

      J'ai préféré changer le nom du projet pour éviter les conflits avec d'autres projets. (Le mot "entity" est trop général)

      Je l'ai donc rebaptisé esEngine, pour Entity System Engine.

      L'adresse: https://github.com/jlgrall/esEngine

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.