Appliquer l'ECS à Javaquarium

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Salut !

J'ai commencé un premier essai de l'exercice Javaquarium en Java pour appliqur l'ECS mais je suis arrivé à un hic.

D'abord, je vais définir ma vision de l'ECS (je me suis assez longuement documenté mais je ne l'ai encore jamais appliqué) :
- une entité est une liste de composants qui la définissent;
- un composant est une propriété, comme la façon de se reproduire ou le régime de l'entité;
- un système est ce qui gère une entité (ça doit être là que j'ai un problème, je ne sais pas trop comment le définir en fait).

À propos de l'entité, je sais qu'on peut la considérer comme un id, point. Ensuite, couplé au pattern Pool, on optimise énormément grâce à une limitation des Cache Miss. Mais dans les langages Java, C#, Python ou je n'sais quoi, c'est automatisé (d'après un pote) et donc pas besoin de s'en préoccuper.
Et d'un point de vue concept, je préfère la définition : une entité est une liste de composants qui la définissent. Ensuite, les systèmes n'agissent sur telle ou telle entité que si elle a les composants adéquats.

Concrètement : les systèmes représentent les comportements, les composants les caractéristiques/propriétés d'une entité et l'entité un poisson ou une algue, pour l'instant. Plus tard, je m'amuserais bien à ajouter d'autres type d'animaux, des objets non vivants comme du bois (enfin, non vivant, vous voyez c'que j'veux dire) ou un caillou etc…

Pour l'instant, j'avais dans l'idée de faire 3 types de systèmes : ComportementReproducteur, ComportementAlimentaire, ComportementVieillesse (pour les poissons, une perte de pv, le contraire pour les algues) avec par exemple différents composant de reproduction (hermaphrodite, hétérosexuel, sexe changeant avec le temps), d'alimentation (carnivore, herbivore) et de vieillesse (vie de poisson, vie d'algue). Mais ce doit être une mauvaise voix car ça ne fonctionne pas :
Imaginons une entité qui contient le composant HermaphroditeOpportuniste. Le système ComportementReproducteur doit comprendre qu'il s'agit d'une entité hermaphrodite opportuniste.
1er hic : dans le système ComportementReproducteur, je ne vois pas comment faire autrement qu'avec une série de conditions pour faire reproduire l'entité en fonction de son composant de reproduction (ici HermaphroditeOpportuniste). Si j'ajoute un nouveau type de reproduction, j'ajoute une nouvelle condition avec le code correspondant dans la méthode evolve() (ou update(), ou compute(), fin bref, nommez-là comme vous voulez). On ne peut donc pas vraiment ajouter un nouveau type de reproduction de façon simple et efficace.
2e hic : si j'utilise une suite de condition (ou un switch()), j'aurais la logique de tous les différents type de reproduction dans une seule et même méthode et donc un seul système. Je casse complètement la logique de l'ECS.

Je dois avoir un problème dans mon interprétation de l'ECS, peut-être arriverez-vous à m'éclairer.

La solution que j'ai prise pour l'instant est de contenir les systèmes (les comportements) dans l'entité et de ne pas utiliser de composants. Chaque entité contient donc une instance de ComportementReproducteur ou ComportementAlimentaire, par exemple. Ce qui est en fait le pattern Strategy décrit dans le tuto Java, mais j'aimerais réussir à appliquer un ECS complet. En fait, je m'entraine à l'ECS dans différents langages parce que j'aimerais créer un jeu de RTS civilisationnel (type AoE, quoi) et choisir le langage qui me correspondra le plus (à-priori le C++ avec SFML) que je commencerai de façon très simplifié. Pour ça, il faut que j'ai en tête une conception très modulaire et performante : je le modifierai encore probablement dans 5, 10, 20 ans (avec de grosses mises à jour lorsque le langage et les concepts évolueront) et donc devenir conséquent petit à petit.

EDIT : J'ai mis mon code sur GH mais je vais recommencer de zéro.

Édité par louk

+0 -0

Je t'ai répondu il y à peu mais je reposte ici pour avoir un suivi de la discussion :)

Pour tes hics :

Il s'agit là d'un problème de conception indépendant de la modélisation ECS. Pour moi il faudrait que tu utilises le polymorphisme (que ce soit du pointeur de fonction, de l'héritage on s'en fiche). En fait, même si tu suis un ECS, les systèmes sont (pour moi) ni plus ni moins que des programmes objets standards. Si tu as un système de reproduction, il s'agit (encore pour moi hein, pense pas que c'est absolument comme ça) en réalité d'une façade) simplifié qui va faire les traitements de création de poisson (ici c'est une factory ou ses variantes), de choix d'algorithme (le pattern strategy) et un peu de polymorphisme, ce qui va te permettre de gérer de manière propre toute tes façons de reproduire, tout en créant les poissons qu'il faut. Comme une classe ne doit avoir qu'une fonction, les systèmes sont (toujours imho) des classes qui cachent tout un tas de classe qui elles n'ont qu'un seul rôle.

+0 -0
Auteur du sujet

J'ai décidé de reprendre tout le code de zéro et je vais essayer de faire un ECS complet. Je vais peut-être suivre un conseil de B0oucEtMystere sur le topique d'informaticienzero (Taper "Javaquarium et conception" dans la barre de recherche, on le trouve tout de suite). Il définit les systèmes par une classe de trait et les composants nécessaire au bon déroulement de ce système.

D'abord, je vais commencer par les morceaux de codes les plus hauts niveaux (méthode main et classe Aquarium). Ça va m'aider à trouver comment structurer le tout.

Ensuite, je vais utiliser une classe Factory et/ou une classe Store. Store ferait le lien entre Composants et Entités, la Factory se chargera de gérer les entités (création/destruction). En fait Factory sera probablement l'aquarium.

Aussi, il faut sans doute que je réfléchisse à si j'utilise un système qui se charge uniquement de la mise à jour des entités.

Pour terminer, je définis mes différents composants et systèmes.

J'ai la démarche, manque plus qu'à réfléchir l'architecture en utilisant du crayon et un papier (ou plutôt l'inverse).

Et pour finir, coder le tout. Mais ça, c'est toujours ce qui prend le moins de temps (quand on connait bien le langage qu'on utilise, du moins).

Édité par louk

+0 -0

Cette réponse a aidé l'auteur du sujet

Bonjour,

Perso, j'ai réfléchi à une classe ECS de ce genre :

Structure ECS

La partie qui reste soudé, correspond au lien de composition de Manager avec Entity et Component. Le Manager s'occupe d'ajouter / retourner ou supprimer les entités et les composants, puis d'associer un composant à une entité.

Du coup, j'ai pensé à un tableau pour les attributs d'Entity : static.component correspond à l'identifiant du composant parent, static.default spécifie si l'attribut est l'héritage d'un composant (true ou false), value à la valeur de l'entité et name un rappel du nom de l'entité. L'idée étant de pouvoir clipser des composants mais aussi de pouvoir indépendamment du modèle, ajouter des attributs tel que la position (X;Y). Attention toutefois pour des questions de propreté, on ne doit pas en abuser ! :)

Si la partie System est propre au projet, j'ai pensé à l'intégré dans le processus. Car il va interagir via le Manager pour par exemple lister les entités qui possèdent le composant X. Et via getEntity(), le système pourra agir directement sur le modèle (les attributs hérités de Component).

Je l'ai actuellement codé en Javascript. Il me manque des méthodes intelligentes dans le Manager pour être utilisable sur un projet. Mais en testant déjà la création d'entité et de composant, le résultat est plutôt efficace. Sans compter que j'ai résolu le problème d’accessibilité entre Entity et Component. C'est tout simplement Manager qui organise tout l'application (ce que tu appelles Factory ou Store).

Tant de choses, tant de vies, tant de possibilités.

+0 -0

Salut ! Je suis en train d'implémanter l'ECS dans le cadre d'un projet basé sur le Javaquarium du coup j'ai fait un joli diagramme de classe (je le posterais plus tard quand il sera propre).

J'ai quelque chose qui ressemble à ce que tu as fais mais il y a une différence. Si tu as lu quelques articles, beaucoup se répète et disent que l'entity n'est qu'un id. D'ailleurs en C (ou C++) il ne s'agirait que d'un typedef sur int. Je stock donc les entities dans les components. Ca implique d'avoir une facade (je te laisse regarder le design pattern) si on veut protéger le component.

Au final c'est comme ça que mon équipe a choisi de faire, les entités ne sont que des id et les components sont plus "complexes" puisqu'ils connaissent les entités composés.

Pourquoi avoir fait comme ça ? Eh bien tu t'en rendra compte, les systèmes traitent l'ensemble des entités d'un component, dans ton cas tu vas devoir faire pleins de liste ou alors parcourir l'ensemble des entités.. Soucis de performance évident.

Je ne sais pas ce qu'en pense les autres mais il me semble que tu devrais t'orienter sur ce que je viens de te raconter (si c'est pas très clair pose(z) vos question je suis fatigué)

+2 -0

Effectivement, c'est un gain de performance. :) Mais par contre tu auras toujours un souci pour supprimer une entité. Il faudra lister tout les composants pour savoir si ton entité se trouve dans l'un d'eux.

Je vais reprendre ton idée pour l'implémenter et tester ça avec Javaquarium. Si j'ai des idées pour l'améliorer un peu plus - notamment au niveau des systèmes : est-ce qu'on peut créer une classe System qui puisse servir pour tout type de projet confondu ? :) je n'ai pas trouvé grand chose au sujet de l'implémentation.

Tant de choses, tant de vies, tant de possibilités.

+0 -0

Je vais faire une analogie très limité au MVC. En fait ton système c'est un peu comme ton Modèle, c'est lui qui contient les algorithmes. Chaque système est associé a un component. Du coup tu vas avoir autant de system que de component qui en nécessite. Si l'on prend le Javaquarium, tu aurais un système qui s'occupe de l'alimentation, la reproduction et le vieillissement. Et chacun d'entre eux serait sous divisé pour s'adapter aux différentes espèces.

Pour la suppression, je n'y avait absolument pas penser, mais c'est finalement assez simple. Puisque nous sommes en multithreading, il suffirait de rajouter un booléen à l'entité pour dire s'il est existe ou pas et lorsqu'un système se rend compte qu'une entité est morte, il la supprime tout simplement.

+0 -0
Auteur du sujet

C'est intéressant tout ça. Je vais y réfléchir. J'ai pas beaucoup touché à mon code et je suis pas encore très avancé, je peux me permettre de tout recommencer s'il le faut.

En attendant, je veux bien voir ton diagramme de classe ! Je pense aussi poster ici le code que j'ai commencé.

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte