
Envoyé par
Marxed
Bonjour

,
Depuis que je code des jeux en C++, je suis toujours confronté au même problème : à un moment ou à un autre, je dois implémenter une classe qui va représenter une grande variété d'objets différents. Disons par exemple que je code un RPG et que je code une classe LivingEntity. Cette classe doit représenter toute chose vivante au sein de mon jeu. Cette classe possède donc des attributs pour représenter les points de vie de l'entité, sa position dans le monde...
Ouh la!!!!
Tu n'as pas l'impression de donner (beaucoup) trop de responsabilité à ton entité vivante 
Car, si on prend une pierre ou un mur, c'est très clairement une entité positionnable (elle peut se positionner sur la carte, afin d'être affichée), mais on peut difficilement estimer qu'il s'agisse d'une entité vivante (elle n'a pas de point de vie) ni attaquable (elle ne subit pas de dégats) ni déplaçable (elle ne bougera jamais) ni même attaquante (elle n'attaquera jamais ton héros).
L'idéal est donc sans doute de créer un ensemble de petites interfaces de base ne donnant la possibilité de ne faire qu'une seule chose.
Tu aurais donc, de manière non exhaustive:
- PositionableEntity (permet de représenter la position de l'objet, dont hérite quasiment tout)
- LivingEntity (permet de représenter les points de vie de l'objet, son état "vivant" ou "mort", dont n'hérite que... ce qui est vivant)
- AttackableEntity (permet de représenter les objets que l'on peut attaquer, qui peuvent subir des dégats, dont n'héritent que ce qui est vivant et attaquable)
- AttackEntity (permet de représenter les objets qui peuvent attaquer, qui peuvent occasionner des dégats)
- UsableEntity (permet de représenter tout ce qui peut etre utilisé (objets d'inventaire, sort, armes, ...)
- LevelableEntity (permet de représenter tout ce qui est modifié par un niveau éventuel)
Si tu veux définir une classe concrète (par exemple un zombie), tu n'as qu'à le faire hériter de positionnable, de living, d'attackable, d'attack et de levelable, libre à toi de redéfinir les fonctions "qui vont bien" pour le zombie en question (par exemple : on pourrait dire qu'un zombie est toujours de niveau 2
)
Par contre, selon le gameplay, si tu veux créer une classe "potion", tu ne la feras sans doute hériter que de "usable"(afin de pouvoir l'utiliser), et éventuellement de "positionnable" (si elle ne rentre pas directement dans ton inventaire).
De cette manière, tu pourras "assez facilement" créer une collection d'objet "positionnable" (dont tu auras besoin pour l'affichage) et une série de collections d'objets divers en fonction des besoins de ton jeu.
Tu pourrais donc carrément envisager la création d'un groupe de cadavres putréfiés et de le placer quelque part si tel était ton plaisir 
Sauf que dans mon jeu, comme dans tout jeu qui se respecte, il n'y a pas qu'un type d'entité. Il y en a plein : Des zombies, des monstres plus ou moins variés...
A n'en pas douter 
Et une des caractéristique que je veux donner à mes entités est que, toutes les entités qui partagent le même type, doivent partager certaines caractéristiques basiques (comme des valeurs de dégats, un pointeur vers la texture à utiliser pour afficher l'entité...)
A priori, la texture d'affichage n'a strictement rien à voir avec la donnée "métier" de tes différents monstres.
Elle n'est, en effet, utile que lorsqu'il s'agit d'afficher tes objets, et ce devrait presque être (pour bien faire) un module séparé.
Rien ne t'empêche de créer un tableau mettant en relation une entité positionnable d'une part et une texture d'autre part afin de pouvoir afficher tes différents éléments, mais il n'y a strictement aucune raison de faire en sorte que tes différentes entités disposent d'une texture (essayes d'appliquer le MVC
)
Donc j'ai défini un enum EntityType qui contient quelques valeurs, comme PLAYER, ZOMBIE, DEMON..., et j'ai rajouté un attribut EntityType dans ma classe LivingEntity.
A priori, tu n'en as pas besoin!
Pour autant que, dans une situation donnée, tu dispose de l'interface "qui va bien" (par exemple: une fonction virtuelle void attack(*LivingEntity) ) et que tu la redéfinis en fonction de l'élément qui va devoir attaquer (donc, pour un zombie et pour un cadavre putréfié), il faut te dire que l'élément en question saura d'office s'il est un cadavre putréfié ou un zombie.
Tu ne devrais donc jamais avoir à transtyper un objet de type générique ("AttackEntity" par exemple) en un objet de type particulier (Zombie, par exemple) afin de lui permettre d'attaquer 
De même, si tu veux pouvoir afficher "zombie" ou "cadavre putréfié" de temps en temps, tu ne devrais pas partir sur le principe d'un pseudo RTTI (RunTime Type Information) mais plutôt sur le principe d'un visiteur 
Le problème, c'est que je ne sais pas où stocker les valeurs qui seront partagées par toutes les entités du même type. J'avais pensé à créer une structure qui contiendrait toutes ces valeurs, et à créer un tableau global de ces structures, de sorte à avoir une syntaxe de la forme :
monster[ZOMBIE] = {10, 5, "zombie.png"}
Tu les stockes "là où tu en as besoin", c'est à dire dans la classe qui les manipule.
Si les valeurs sont strictement identiques "quel que soit l'instance envisagée", tu peux envisager de les déclarer comme des membres statiques, de manière à ce que la valeur soit partagée par toutes les instances de ta classe, sans dépendre d'une instance particulière
Partager