Identification des «types» d'entité dans un système à composants d'entité

10

Si une entité n'a pas de «type» explicite (par exemple, un joueur) et est simplement une collection de composants, comment puis-je identifier les entités sur lesquelles mes systèmes devraient et ne devraient pas travailler? Par exemple, dans un jeu de Pong, la pagaie et la balle entrent en collision avec les limites de la fenêtre. Cependant, les systèmes de gestion des collisions pour chacun seront différents, donc un système ne devrait pas gérer des entités de mauvais type.

void PlayerCollisionSystem::update(std::vector<Entity *> entities) {
  typedef std::vector<Entity *>::iterator EIter;
  for (EIter i = entities.begin(); i != entities.end(); ++i) {
    Entity *player = *i; // How do I verify that the entity is a player?

    // Get relevant components.
    PositionComponent *position = player->getComponent<PositionComponent>();
    VelocityComponent *velocity = player->getComponent<VelocityComponent>();
    SpriteComponent *sprite = player->getComponent<SpriteComponent>();

    // Detect and handle player collisions using the components.
  }
}

Le joueur et le ballon partagent les mêmes types de composants pertinents pour la gestion des collisions, mais leurs implémentations de système seront différentes.

Si j'ai un conteneur de toutes les entités de jeu, comment puis-je identifier des types spécifiques d'entité sans hériter Entityou inclure une variable membre telle que std::string type, auquel cas une entité n'est plus simplement une collection de composants?

Garee
la source

Réponses:

21

La réponse de Nicol Bolas est directe, mais en vous éloignant et en regardant votre problème à distance: vous n'avez vraiment pas besoin du type d'entité.

Vous n'avez qu'à vous soucier de savoir si "l'objet a un composant X" ou non et votre problème est que vous ne vous êtes pas correctement identifié X. Si deux objets se comportent différemment, donnez-leur des composants différents ou placez simplement un indicateur booléen sur le composant pour qu'il se comporte différemment pour différentes configurations d'objets. Utilisez le système de composants pour prendre des décisions sur le comportement, pas le «type» d'entité. C'est tout l'intérêt d'utiliser des composants.

Vous êtes complètement autorisé à avoir un PaddlePhysicscomposant / système et un BallPhysicscomposant / système séparé s'ils se comportent différemment. Ou vous pouvez décomposer les composants en morceaux plus granulaires de telle sorte que vous ayez un Bouncecomposant que seul Ball a et un StopAtBoundarycomposant à la fois Ballet Paddlesi si une partie du comportement est suffisamment compliquée pour justifier le partage du code. Ou vous pouvez simplement créer un PongPhysicscomposant qui a un indicateur booléen Bouncesdéfini truepour le Ballet falsepour le Paddle. Vous pouvez même créer un WallCollisioncomposant de base , puis dériver ce composant pour obtenir un BallWallCollisionqui ajoute le comportement supplémentaire nécessaire.

Sean Middleditch
la source
4
Je pense que cela devrait être la réponse acceptée car il n'y a absolument aucune contrainte ou problème avec ECS "vanille". Le balisage des entités peut être facilement accompli en créant des composants dédiés qui servent de marqueurs. Il pourrait également s'agir simplement d'un PlayerTypeComponent factice qui ne fait rien d'utile mais sert simplement de balise.
tiguchi
19

Un système n'est utile que s'il l'est . Si un système où une entité est "simplement une collection de composants" est moins utile qu'un système où une entité est principalement une "collection de composants", alors faites-le .

Arrêtez d'essayer de créer des systèmes «purs» et concentrez-vous sur la création de bons systèmes qui font ce dont vous avez besoin. Utilisez des composants jusqu'à ce que les composants ne vous soient plus utiles. Ensuite, utilisez autre chose.

Vous avez déjà passé plus de temps à réfléchir à cela qu'il ne le mérite.

Nicol Bolas
la source
very nice +1 "Vous avez déjà passé plus de temps à y réfléchir qu'il ne le mérite"
wes
8
Je ne pense pas que ce soit une réponse du tout, le sujet du raffinement d'un ECS mérite une attention particulière, et Garee (quand il a posté cela en 2013) n'avait probablement pas passé assez de temps à y penser. L'idée que le sujet ne mérite pas plus de temps implique que les systèmes devraient être simples ou triviaux et ne méritent généralement pas notre temps. Je préférerais la réponse de Sean Middleditch car elle tente en fait de répondre à la question au lieu de la rejeter.
Gavin Williams
Très bonne réponse. Je me retrouve à devoir me le dire à l'occasion. Concentrez-vous sur l'avenir.
Dominic Bou-Samra
5

Si vous souhaitez donner aux entités un type explicite, la manière la plus simple consiste à définir une variable de type dans la classe d'entité. Ne respectez le modèle CE que tant qu'il est utile.

Sinon, le type est implicite via les attributs du composant. Par exemple, le composant physique aurait un attribut pour mobile vs stationnaire. Le système sait alors quand deux mobiles entrent en collision (balle et pagaie). De même, vous pouvez avoir des attributs pour la réponse du système de collision. Arrêtez simplement l'objet ou réfléchissez-le? L'examen des attributs devrait vous donner une idée de ce qu'est l'entité, mais cela ne devrait pas être pertinent. Les systèmes ne devraient pas avoir besoin de connaître le type d'entité avec lequel ils travaillent, ils devraient recevoir suffisamment d'informations en utilisant les composants qui leur sont fournis.

Enfin, vous pouvez ajouter un composant supplémentaire qui contient un type, mais, comme pour l'ajout d'un type à l'entité, vous finirez par écrire beaucoup de code spécifique au type, ce qui va à l'encontre de l'objectif du système EC.

MichaelHouse
la source
0

Une entité est un ensemble de composants. Vous ne pouvez pas attribuer d'étiquettes soignées à un ensemble aléatoire. Abandonner les contraintes de type est le prix de la grande flexibilité.

Bien sûr, vous pouvez avoir des classes d'entités spéciales (typées) qui imposent des restrictions sur les composants.

Idéalement, les composants sont indépendants. Ainsi, la solution à votre problème serait d'appeler la gestion des collisions sur chaque sous-composant, dans l'ordre. Dans les applications réelles, il existe des interdépendances et des problèmes de commande. Si tel est le cas, vous avez besoin d'une logique de «répartiteur» dans chaque méthode de la classe Entity.

Karl
la source