Je suis assez nouveau dans l'idée des systèmes d'entités, après avoir lu un tas de choses (le plus utile, ce grand blog et cette réponse ).
Bien que j'aie un peu de mal à comprendre comment quelque chose d'aussi simple que de pouvoir manipuler la position d'un objet par un nombre indéfini de sources.
Autrement dit, j'ai mon entité, qui a une composante de position. J'ai alors un événement dans le jeu qui dit à cette entité de se déplacer sur une distance donnée, dans un temps donné.
Ces événements peuvent survenir à tout moment et auront des valeurs différentes pour la position et l'heure. Le résultat est qu'ils seraient combinés ensemble.
Dans une solution OO traditionnelle, j'aurais une sorte de MoveBy
classe, qui contient la distance / temps, et un tableau de ceux à l'intérieur de ma classe d'objets de jeu. Chaque image, je répéterais à travers tout MoveBy
, et l'appliquerais à la position. Si a MoveBy
a atteint son heure de fin, supprimez-le du tableau.
Avec le système d'entités, je suis un peu confus quant à la façon de reproduire ce type de comportement.
S'il n'y en avait qu'un à la fois, au lieu de pouvoir les mélanger ensemble, ce serait assez simple (je crois) et ressembler à ceci:
PositionComponent
contenant x, y
MoveByComponent
contenant x, y, time
Entity
qui a à la fois un PositionComponent
et unMoveByComponent
MoveBySystem
qui recherche une entité avec ces deux composants et ajoute la valeur de MoveByComponent
au PositionComponent
. Lorsque le time
est atteint, il supprime le composant de cette entité.
Je suis un peu confus quant à la façon dont je ferais la même chose avec de nombreux déménagements.
Mes premières pensées sont que j'aurais:
PositionComponent
, MoveByComponent
comme ci-dessus
MoveByCollectionComponent
qui contient un tableau de MoveByComponent
s
MoveByCollectionSystem
qui recherche une entité avec un PositionComponent
et un MoveByCollectionComponent
, itérant à travers le MoveByComponent
s à l'intérieur, en appliquant / supprimant si nécessaire.
Je suppose que c'est un problème plus général, d'avoir beaucoup du même composant, et de vouloir un système correspondant pour agir sur chacun. Mes entités contiennent leurs composants dans un hachage de type composant -> composant, donc strictement 1 seul composant d'un type particulier par entité.
Est-ce la bonne façon de voir les choses?
Une entité ne devrait-elle avoir à tout moment qu'un seul composant d'un type donné?
MoveBy
fonctionnalité est une sorte de vitesse? On dirait que vous êtes sur la bonne voie. Pour votre deuxième question, il existe de nombreuses implémentations différentes de systèmes d'entités / composants. Celui décrit dans ma réponse que vous avez lié n'aurait qu'un seul composant d'un type donné.move x by 10 in 2 seconds
et quemove x by -10 in 2 seconds
l'entité resterait parfaitement immobile?Réponses:
Pour votre scénario, nous ajoutons généralement trois composants à un objet de jeu:
Lorsque les objets de jeu ont besoin d'un certain type de fonctionnalité d'IA, comme se déplacer le long d'un chemin comme vous l'avez décrit, nous affectons un AIController à sa liste de composants. Les contrôleurs AIC ne sont en réalité rien de plus qu'un wrapper qui parcourt un arbre comportemental. L'arbre de comportement est l'endroit où nous concevons les fonctionnalités réelles que nous voulons que l'objet de jeu exécute, telles que:
Le sous-système AI gère les contrôleurs AIC et de sorte que le sous-système coche le contrôleur qui, à son tour, fait avancer l'arborescence des comportements. MoveToNode () examine la position / orientation actuelle, calcule un vecteur de direction et une vitesse vers laquelle vous souhaitez vous déplacer en fonction de ses arguments de constructeur et définit les valeurs sur la composante de vitesse. Le système de mouvement est chargé de lire les composants de mouvement avec des valeurs et d'appliquer la physique, mettant ainsi à jour la position / orientation en conséquence.
Le code ci-dessus déplace simplement un objet de jeu de l'emplacement d'apparition vers x, y, z dans l'espace mondial, puis attend un minimum de 30 secondes, puis déplace l'objet de jeu vers l'emplacement a, b, c, puis attend encore 30 secondes. Une fois l'attente terminée, la séquence de comportements est terminée, elle se répète donc dès le début.
Cela vous permet de définir facilement la fonctionnalité AI dont vous avez besoin, entièrement autonome dans le sous-système AI, avec un impact minimal sur votre sous-système Entity. Il vous permet également de conserver votre liste de composants système d'entité allégée sans trop de granularité.
la source
Une option consiste à ajouter des contrôleurs à votre conception. Les entités possèdent des données pour représenter la position (dans le cas de mon moteur, elles ont aussi des données qui se souviennent des positions précédentes, donc je peux connaître le vecteur vitesse et si elles sont déplacées ou téléportées), mais elles ne savent rien de la physique ou AI. Les contrôleurs déplacent des entités et vous pouvez avoir plusieurs contrôleurs affectant la même entité ou un contrôleur affectant différentes entités.
Par exemple: créez une classe Controller de base avec une méthode run (), ou si vous n'aimez pas le nom, appelez-le think (), update () ou tick (). Ensuite, vous en héritez et créez un MoveController, NPCController, PlayerInputController (pour l'entité du joueur), PhysicController; puis vous implémentez la méthode run (). Je mettrais votre MoveByComponent dans le MoveController et non dans Entity.
Ces contrôleurs peuvent être instanciés par chaque entité s'ils détiennent des données spécifiques à une entité. Ils peuvent être détruits ou réinitialisés pour une réutilisation ultérieure. Vous pouvez également utiliser un contrôleur pour déplacer un groupe d'entités, dans un jeu RTE par exemple, si vous devez déplacer différentes unités en groupe, avoir un contrôleur par chaque unité peut nuire aux performances du jeu, alors vous pouvez simplement assigner toutes les unités à un GroupController ou LegionController et laissez-le déplacer les unités dans le cadre d'un groupe organisé. Lors des combats, si le jeu autorise le comportement d'une unité individuelle, et probablement la plupart des jeux le font, vous devrez passer à un UnitController mais il est préférable de ne le faire qu'en cas de besoin plutôt que depuis le début.
Dans mon jeu en développement, j'ai un MoveController qui déplace les entités suivant un chemin, un MoveController existe pour chaque PNJ et le personnage du joueur. Parfois, un est créé pour les boîtes ou le rock que le joueur peut pousser. Le PhysicController, une seule instance, qui vérifiera les positions de toutes les entités qui lui sont affectées, si une entité entre en collision avec une autre entité affectée, la position résultante des deux est calculée (il fait en fait plus que cela, mais vous avez l'idée). Le NPCController est l'IA, une instance par NPC. Il vérifie la situation du NPC et décide où se déplacer, puis pousse le chemin vers un MoveController, qui déplace réellement le NPC. Les contrôleurs ont une priorité, donc je peux déterminer à l'avance leur ordre, le PhysicController est le dernier à s'exécuter.
Je préconise les contrôleurs, mais ce n'est pas la seule option "correcte". Par exemple, je me souviens d'une interface Entity dans le moteur Cafu qui a la méthode think () dans l'entité elle-même, l'utilisateur de la classe doit hériter d'Entity et implémenter think (), je me souviens d'une classe dérivée appelée CompanyBot (qui vient avec l'exemple jeu) qui effectuent une vérification des collisions dans cette méthode, comme on l'appelle "pensez", nous pouvons supposer que le code AI devrait également être là. Alors que le moteur NeoAxis (la dernière fois que je l'ai étudié) a l'IA et la physique séparées des entités.
Il existe un modèle de contrôleur que j'ai écouté. Peut-être que vous devriez le rechercher, et ce n'est probablement pas exactement ce dont je parle ici, mais cela semble aussi être une bonne solution.
la source