
Envoyé par
Disixlis
et j'ai lu que les classe devais être immuable
ouais, m'enfin, un Vector n'a rien d'immuable.

Envoyé par
Disixlis
En fait, je dois supprimer l'ancien composant du vecteur avant d'en mettre un nouveau, mais j'avoue ne pas l'avoir clairement énoncé.
Rechercher et remplacer voilà le but de cette méthode.
Un rechercher/remplacer par Stream n'est pas une bonne idée : un Stream ne doit pas modifier la source du Stream. Elle en produit un nouveau. Ce qui veut dire que tu serais obliger de recréer une instance de collection à chaque fois. C'est d'ailleurs le cas dans mon exemple avec retainAll.
La solution :
1 2
| this.entities.get(id).removeIf(c.getClass()::isInstance)
this.entities.get(id).add(c); |
correspond plus à ta demande. Mais n'est pas la plus optimisée : on supprime, donc on décale l'ensemble des composants situés à la suite vers la gauche (une copie de tableau inutile, puisqu'il suffirait de remplacer l'élément situé à l'index en question).
On pourrait faire :
1 2 3 4 5 6 7
| Optional<Component> old = components.stream().filter(c.getClass()::isInstance).findFirst();
if (old.isPresent() ) {
Collections.replaceAll(components, old.get(), c);
}
else {
components.add(c);
} |
Mais pas sûr que ça plus optimisé que :
1 2 3 4 5 6 7 8 9 10 11
| int index=-1;
for(int i=0; i<components.size(); i++) {
if ( c.getClass().isInstance(components.get(i)) ) {
index=i;
components.set(index, c);
break;
}
}
if ( index==-1 ) {
components.add(c);
} |
Si tu n'as pas héritage entre Component, on peut aussi utiliser une map :
Map<Class<?>, Component> components = new HashMap<>();
Pour ajouter ou remplacer :
components.put(c.getClass(), c);
Pour supprimer :
components.remove(c.getClass());
Ou pour supprimer par type (sans avoir l'instance) :
components.remove(MyComponent.class);
Pour parcourir :
1 2
| for(Component component: components.values()) {
} |
Cependant, dans le cadre d'un ECS, on a deux types de listes de Component : celle de l'Entity et celle du System. Si cette solution peut fonctionner pour celle de l'Entity, puisqu'une Entity est censé n'avoir qu'un composant de chaque type (et encore, on pourrait profiter du modèle objet pour avoir des composants abstraits, par exemple pour gérer les armes mutiples du joueur). En revanche, celle d'un System va contenir forcément plusieurs composants de même classe (c'est sa fonction). Et du coup, ça ne fonctionne pas du tout.
Je ne sais pas ce que dit l'état de l'art des ECS, mais à mon avis il est bien plus simple de gérer des composants mutables, dans le cadre d'une boucle évenementielle (un thread unique de traitement, synchronisé sur l'EDT). Dans un ECS, on peut gérer un thread par System. Normalement, le modèle devrait interdire le partage de composants par deux systèmes. Mais j'imagine qu'on doit pouvoir trouver des composants qu'on pourrait partager entre System. Dans ce cas, on pourrait utiliser des SystemManager qui aurait un seul thread pour gérer un ensemble de Systems. Mais avec ce système, il est compliqué de gérer la synchro avec l'EDT, et on peut facilement introduire des saccades dans l'animation de l'UI.
Une solution pourrait être de gérer les composants par binding, ce qui permettrait de gérer tout le traiment par stream. Le composant serait immuable, on regénerait les listes de composants à chaque boucle. La suppression ne serait plus necéssaire que pour la "mort" d'une entité, ou sa mutation éventuelle : on pourrait gérer ça par un flag. Lors de la boucle de traitement, on ignore simplement les composants marqués par le flag.
Partager