Outils d'utilisateurs

Outils du Site


javaquarium

Différences

Cette page vous donne les différences entre la révision choisie et la version actuelle de la page.

Lien vers cette vue

javaquarium [2016/05/15 22:31]
gbdivers
javaquarium [2016/05/30 20:08] (Version actuelle)
gbdivers [Exercice 3.3 : Mais… la sexualité des poissons est horriblement compliquée !]
Ligne 2318: Ligne 2318:
 {{ :ecs1.png |}} {{ :ecs1.png |}}
  
-Par exemple, dans le javaquarium, toutes les entités "poisson" possèdent une données "nom" et "age". Il est donc possible de les mettre dans un même composant. Au contraire, la donnée "points de vie" concerne toutes les entités "être vivant", pas uniquement les entités "poisson".+Par exemple, dans le javaquarium, toutes les entités "poisson" possèdent une données "nom" et "age". Il est donc possible de les mettre dans un même composant. Au contraire, la donnée "points de vie" concerne toutes les entités "être vivant", pas uniquement les entités "poisson". Il sera donc logique de la placer dans un composant différent.
  
 Il faut cependant modérer un peu ce critère. Supposons que 99 % des entités sont des poissons. Dans ce cas, cela signifie que si on regroupe les trois données (nom, age et points de vie), il y aura 1 % des composants qui auront deux données vides (nom et age, pour les entités "algue"). Or, séparer ces données dans deux composants aura un coût (mémoire et/ou performances). Il peut être intéressant d'avoir un seul composant qui regroupe toutes les données dans ce cas. Il faut cependant modérer un peu ce critère. Supposons que 99 % des entités sont des poissons. Dans ce cas, cela signifie que si on regroupe les trois données (nom, age et points de vie), il y aura 1 % des composants qui auront deux données vides (nom et age, pour les entités "algue"). Or, séparer ces données dans deux composants aura un coût (mémoire et/ou performances). Il peut être intéressant d'avoir un seul composant qui regroupe toutes les données dans ce cas.
Ligne 2354: Ligne 2354:
 </code> </code>
  
-Dans cette approche, il est nécessaire de conserver la cohérence des données, c'est a dire que les données correspondant au même index dans les deux collections appartiennent a la même entité. Avec cette structure de données, il est assez facile de maintenir la cohérence, il suffit d'effectuer les mêmes opérations sur les deux collections en même temps (insertion, suppression, tri, etc.).+Dans cette approche, il est nécessaire de conserver la cohérence des données, c'est a dire que les données correspondant au même indice dans les deux collections appartiennent a la même entité. Avec cette structure de données, il est assez facile de maintenir la cohérence, il suffit d'effectuer les mêmes opérations sur les deux collections en même temps (insertion, suppression, tri, etc.).
  
-Lorsque l'on accède a un élément d'une de deux collections, il est possible d’accéder directement a la seconde collection, en utilisant l'indice ou avec deux boucles synchroniser (une autre approche est d’utiliser boost.zip_iterator). L'indice peut être déterminé via une variable (par exemple dans une boucle) ou avec ''std::distance'' (complexité algorithmique constant).+Lorsque l'on accède a un élément d'une de deux collections, il est possible d’accéder directement a la seconde collection, en utilisant l'indice ou avec deux boucles synchronisées (une autre approche est d’utiliser boost.zip_iterator). L'indice peut être déterminé via une variable (par exemple dans une boucle) ou avec ''std::distance'' (complexité algorithmique constant).
  
 <code cpp> <code cpp>
Ligne 2372: Ligne 2372:
 </code> </code>
  
-Dans la troisièmement approche, les éléments de la seconde collection ne sont plus identifiés par rapport a leur position dans la collection, mais pas l'ajout d'une donnée supplémentaire permettant d'identifier chaque élément (par exemple l'identifiant des entités).+Dans la troisièmement approche, les éléments de la seconde collection ne sont plus identifiés par rapport a leur position dans la collection, mais par l'ajout d'une donnée supplémentaire permettant d'identifier chaque élément (par exemple l'identifiant des entités).
  
 <code cpp> <code cpp>
Ligne 2379: Ligne 2379:
 </code> </code>
  
-Dans cette approche, il n'est pas nécessaire de synchroniser les données, il est possible d’ajouter ou de supprimer un composant A sans modifier le composant B (et réciproquement). Par contre, les accès aux composants A et B nécessiteront de faire une recherche dans les deux collections (par exemple pour supprimer les composants lors de la suppression d'une entité).+Dans cette approche, il n'est pas nécessaire de synchroniser les données, il est possible d’ajouter ou de supprimer un élément dans la collection A sans modifier la collection B (et réciproquement). Par contre, les accès aux composants A et B nécessiteront de faire une recherche dans les deux collections (par exemple pour supprimer les composants lors de la suppression d'une entité)
 + 
 +Dans ce cas, plus une collection sera grande, plus le temps d’accès sera longue.
  
 <code cpp> <code cpp>
Ligne 2418: Ligne 2420:
 Bien sur, ces analyses ne prennent pas en compte l’efficacité du cache ou la corrélation avec l'algorithme. Dans tous les cas, une analyse plus approfondie (profiling) sera nécessaire pour bien choisir l'approche a utiliser. Bien sur, ces analyses ne prennent pas en compte l’efficacité du cache ou la corrélation avec l'algorithme. Dans tous les cas, une analyse plus approfondie (profiling) sera nécessaire pour bien choisir l'approche a utiliser.
  
-Voila les principales approches qui me semblent intéressantes pour un ECS. Mais je ne prétends pas être exhaustif. Par exemple, si la majorité des entités ont une majorité de composants ou si le nombre d’entités et de composants n'est pas important, il est possible de stocker toutes les données directement dans un tableau 2D, avec les entités en ligne et les systèmes en colonne.+Voila les principales approches qui me semblent intéressantes pour un ECS. Mais je ne prétends pas être exhaustif. Par exemple, si la majorité des entités ont une majorité de composants ou si le nombre d’entités et de composants n'est pas important, il est possible de stocker toutes les données directement dans un tableau 2D, avec les entités en ligne et les systèmes en colonne. 
  
-De plus, l'approche ECS sera intéressante surtout si le tableau contient plus de ligne que de colonne. Si par exemple, on a 1000 composants possible et 10 entités utilisant 2 ou 3 composants différents, alors chaque collection de composants pourra contenir 0 ou 1 éléments. Et la complexité d'un ECS sera au final pénalisant.+Je me suis également limite aux collections triées, pour permettre les accès les plus rapides. Mais il est par exemple possible d'utiliser l'approche 4 sans trier les objets dans la collection B. Lors de la suppression d'un composant, on laisse simplement un "trou" dans la collection et on l'utilise lorsque l'on ajoute un nouveau composant. Dans ce cas, il y a un surcoût pour trouver les "trous" et un cache qui peut être moins efficace, mais on gagne par rapport au l’étape de "compactage" de la mémoire. Voire il est possible de conserver les composants B sans collection. Dans ce cas, on gagne sur les étapes de "compactage" et de gestion des "trous", mais on perd au niveau du cache mémoire et des allocations et désallocations. 
 + 
 +{{ :ecs4.png |}} 
 + 
 +De plus, l'approche ECS sera intéressante surtout si le tableau contient plus de ligne que de colonne. Si par exemple, on a 1000 composants possible et 10 entités utilisant 2 ou 3 composants différents, alors chaque collection de composants pourra contenir 0 ou 1 éléments. Et la complexité d'un ECS sera au final pénalisant. Dans ce cas, une approche orientée objet classique, basée sur une hiérarchie de classes, pourra être une approche intéressante.
  
 La conclusion est que le choix de l'approche ne peut pas être définie uniquement sur des considérations techniques d’implémentation. Le //game design// influencera beaucoup l'approche (ou plus probablement "les approches") selon les données a manipuler et les traitements appliquées. Par exemple, on pourra choisir l'approche 4 pour le système de rendu (la majorité des entités sera visibles) et l'approche 3 pour les armes (si les ennemis humains portant une arme sont minoritaires). La conclusion est que le choix de l'approche ne peut pas être définie uniquement sur des considérations techniques d’implémentation. Le //game design// influencera beaucoup l'approche (ou plus probablement "les approches") selon les données a manipuler et les traitements appliquées. Par exemple, on pourra choisir l'approche 4 pour le système de rendu (la majorité des entités sera visibles) et l'approche 3 pour les armes (si les ennemis humains portant une arme sont minoritaires).
 +
 +Un bon moteur d'ECS, a mon sens, ne proposera donc pas une approche fixe dans son design, mais proposera aux développeurs de choisir le design qu'ils préfèrent utiliser, selon les besoin du //game design//. (Le C++ permet de proposer plusieurs approches sans surcoût a l’exécution. Ici, les classes de traits et de politique est une approche intéressante pour implémenter cela.)
  
  
Ligne 2429: Ligne 2437:
 Dans cette partie, je vais réécrire le code, mais en séparant a l’extrême les composants, c'est a dire en considérant que une information correspond a un composant. Dans cette partie, je vais réécrire le code, mais en séparant a l’extrême les composants, c'est a dire en considérant que une information correspond a un composant.
  
 +{{ :ecs5.png |}}
  
  
javaquarium.1463344276.txt.gz · Dernière modification: 2016/05/15 22:31 par gbdivers