Jusqu'à présent, les systèmes de composants d'entité que j'ai utilisés ont fonctionné principalement comme l'artemis de Java:
- Toutes les données dans les composants
- Systèmes indépendants sans état (au moins dans la mesure où ils ne nécessitent pas d'entrée lors de l'initialisation) itérant sur chaque entité qui contient uniquement les composants qui intéressent un système particulier
- Tous les systèmes traitent leurs entités d'un seul coup, puis tout recommence.
Maintenant, j'essaie d'appliquer cela à un jeu au tour par tour pour la première fois, avec des tonnes d'événements et de réponses qui doivent se produire dans un ordre défini les uns par rapport aux autres, avant que le jeu puisse continuer. Un exemple:
Le joueur A reçoit des dégâts d'une épée. En réponse à cela, l'armure de A entre en jeu et réduit les dégâts subis. La vitesse de déplacement de A est également réduite en raison de son affaiblissement.
- Le dommage subi est ce qui déclenche toute l'interaction
- L'armure doit être calculée et appliquée aux dégâts entrants avant que les dommages ne soient appliqués au joueur.
- La réduction de la vitesse de déplacement ne peut être appliquée à une unité qu'après que les dégâts ont été réellement infligés, car elle dépend du montant final des dégâts.
Les événements peuvent également déclencher d'autres événements. La réduction des dégâts de l'épée à l'aide d'une armure peut faire éclater l'épée (cela doit avoir lieu avant que la réduction des dégâts ne soit terminée), ce qui peut à son tour provoquer des événements supplémentaires en réponse, essentiellement une évaluation récursive des événements.
Dans l'ensemble, cela semble entraîner quelques problèmes:
- Beaucoup de cycles de traitement gaspillés: la plupart des systèmes (sauf pour les choses qui fonctionnent toujours, comme le rendu) n'ont tout simplement rien à faire quand ce n'est pas "à leur tour" de fonctionner et passent la plupart du temps à attendre que le jeu entre. un état de travail valide. Cela gâche tous ces systèmes avec des chèques qui continuent de croître en taille à mesure que plus d'états sont ajoutés au jeu.
- Pour savoir si un système peut traiter des entités présentes dans le jeu, ils ont besoin d'un moyen de surveiller d'autres états d'entité / système non liés (le système responsable des dégâts doit savoir si une armure a été appliquée ou non). Cela embrouille les systèmes avec de multiples responsabilités, ou crée le besoin de systèmes supplémentaires sans autre but que d'analyser la collection d'entités après chaque cycle de traitement et de communiquer avec un ensemble d'auditeurs en leur disant quand il est possible de faire quelque chose.
Les deux points ci-dessus supposent que les systèmes fonctionnent sur le même ensemble d'entités, qui finissent par changer d'état en utilisant des indicateurs dans leurs composants.
Une autre façon de le résoudre serait d'ajouter / supprimer des composants (ou de créer des entités entièrement nouvelles) à la suite d'un travail de systèmes unique pour faire progresser l'état des jeux. Cela signifie que chaque fois qu'un système possède une entité correspondante, il sait qu'il est autorisé à la traiter.
Cela rend cependant les systèmes responsables du déclenchement des systèmes ultérieurs, ce qui rend difficile de raisonner sur le comportement des programmes car les bogues n'apparaîtront pas comme le résultat d'une seule interaction système. L'ajout de nouveaux systèmes devient également plus difficile car ils ne peuvent pas être mis en œuvre sans savoir exactement comment ils affectent les autres systèmes (et les systèmes précédents pourraient devoir être modifiés pour déclencher les états qui intéressent le nouveau système), ce qui va un peu à l'encontre de l'objectif d'avoir des systèmes séparés avec une seule tâche.
Est-ce quelque chose avec lequel je devrai vivre? Chaque exemple ECS que j'ai vu a été en temps réel, et il est vraiment facile de voir comment cette boucle d'une itération par jeu fonctionne dans de tels cas. Et j'en ai toujours besoin pour le rendu, cela semble vraiment inapproprié pour les systèmes qui interrompent la plupart des aspects de lui-même chaque fois que quelque chose se produit.
Existe-t-il un modèle de conception pour faire avancer l'état du jeu qui convient à cela, ou devrais-je simplement déplacer toute la logique hors de la boucle et la déclencher à la place uniquement lorsque cela est nécessaire?