Hier, j'ai lu une présentation de GDC Canada sur le système d'entités attribut / comportement et je trouve ça plutôt bien. Cependant, je ne sais pas comment l'utiliser de manière pratique, pas seulement en théorie. Tout d'abord, je vais vous expliquer rapidement le fonctionnement de ce système.
Chaque entité de jeu (objet de jeu) est composée d' attributs (= données, accessibles par comportement, mais également par "code externe") et de comportements (= logique, qui contient OnUpdate()
et OnMessage()
). Ainsi, par exemple, dans un clone Breakout, chaque brique serait composée de (exemple!): PositionAttribute , ColorAttribute , HealthAttribute , RenderableBehaviour , HitBehaviour . Le dernier pourrait ressembler à ceci (c'est juste un exemple non fonctionnel écrit en C #):
void OnMessage(Message m)
{
if (m is CollisionMessage) // CollisionMessage is inherited from Message
{
Entity otherEntity = m.CollidedWith; // Entity CollisionMessage.CollidedWith
if (otherEntity.Type = EntityType.Ball) // Collided with ball
{
int brickHealth = GetAttribute<int>(Attribute.Health); // owner's attribute
brickHealth -= otherEntity.GetAttribute<int>(Attribute.DamageImpact);
SetAttribute<int>(Attribute.Health, brickHealth); // owner's attribute
// If health is <= 0, "destroy" the brick
if (brickHealth <= 0)
SetAttribute<bool>(Attribute.Alive, false);
}
}
else if (m is AttributeChangedMessage) // Some attribute has been changed 'externally'
{
if (m.Attribute == Attribute.Health)
{
// If health is <= 0, "destroy" the brick
if (brickHealth <= 0)
SetAttribute<bool>(Attribute.Alive, false);
}
}
}
Si ce système vous intéresse, vous pouvez en lire plus ici (.ppt).
Ma question concerne ce système, mais généralement tous les systèmes d’entités basés sur des composants. Je n'ai jamais vu comment ces solutions fonctionnent vraiment dans les vrais jeux informatiques, car je ne trouve aucun bon exemple et si j'en trouve un, ce n'est pas documenté, il n'y a pas de commentaire et je ne le comprends donc pas.
Alors, qu'est-ce que je veux demander? Comment concevoir les comportements (composants). J'ai lu ici, sur GameDev SE, que l'erreur la plus commune est de créer de nombreux composants et simplement de "transformer tout en un composant". J'ai lu qu'il est suggéré de ne pas effectuer le rendu dans un composant, mais de le faire en dehors de celui-ci (donc au lieu de RenderableBehaviour , il devrait être RenderableAttribute , et si une entité a pour valeur RenderableAttribute , alors Renderer
(classe non liée à composants, mais au moteur lui-même) devrait dessiner sur l'écran?).
Mais, qu'en est-il des comportements / composants? Disons que j'ai un niveau, et dans le niveau, il y a un Entity button
, Entity doors
et Entity player
. Lorsque le joueur entre en collision avec le bouton (c'est un bouton de plancher, qui est basculé par pression), il est enfoncé. Lorsque le bouton est enfoncé, il ouvre les portes. Eh bien, maintenant, comment le faire?
J'ai proposé quelque chose comme ceci: le joueur a CollisionBehaviour , qui vérifie si le joueur entre en collision avec quelque chose. S'il se heurte à un bouton, il envoie un CollisionMessage
à l' button
entité. Le message contiendra toutes les informations nécessaires: qui est entré en collision avec le bouton. Le bouton a ToggleableBehaviour , qui recevra CollisionMessage
. Il vérifiera avec qui il est entré en collision et si le poids de cette entité est suffisamment important pour faire basculer le bouton, le bouton devient basculé. Désormais, il définit l' attribut ToggledAttribute du bouton sur true. D'accord, mais quoi maintenant?
Le bouton doit-il envoyer un autre message à tous les autres objets pour leur dire qu'il a été basculé? Je pense que si je faisais tout ce genre de choses, j'aurais des milliers de messages et ça deviendrait assez compliqué. Alors, c’est peut-être mieux: les portes vérifient constamment si le bouton qui leur est lié est enfoncé ou non, et modifie son attribut OpenedAttribute en conséquence. Mais alors cela signifie que la OnUpdate()
méthode des portes fera constamment quelque chose (est-ce vraiment un problème?).
Et le deuxième problème: si j’ai plus de types de boutons. L'un d'eux est pressé par la pression, le second est basculé en tirant dessus, le troisième est basculé si de l'eau est versée dessus, etc. Cela signifie que je devrai avoir différents comportements, quelque chose comme ceci:
Behaviour -> ToggleableBehaviour -> ToggleOnPressureBehaviour
-> ToggleOnShotBehaviour
-> ToggleOnWaterBehaviour
Est-ce ainsi que les vrais jeux fonctionnent ou suis-je juste stupide? Peut-être que je pourrais avoir un seul comportement ToggleableBehaviour et qu'il se comportera selon le ButtonTypeAttribute . Donc si c'est un ButtonType.Pressure
, ça fait ça, si c'est un ButtonType.Shot
, ça fait autre chose ...
Alors qu'est-ce que je veux? Je voudrais vous demander si je le fais bien, ou si je suis juste stupide et je n'ai pas compris le sens des composants. Je n'ai trouvé aucun bon exemple de la manière dont les composants fonctionnent réellement dans les jeux. J'ai juste trouvé quelques tutoriels décrivant comment créer le système de composants, mais pas comment l'utiliser.