IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Conception de classe RPG


Sujet :

C++

  1. #1
    Membre confirmé
    Homme Profil pro
    Développeur du dimanche
    Inscrit en
    Février 2013
    Messages
    154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur du dimanche

    Informations forums :
    Inscription : Février 2013
    Messages : 154
    Par défaut Conception de classe RPG
    Bonjour,

    Sans plus attendre, voici mon bout de code (et oui, je suis un mec comme ça moi) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    #include <iostream>
    #include <vector>
     
    enum
    {
        CRUSHING,
        SLASHING
    };
     
    int dice(int sides)
    {
        return (rand() % sides + 1);
    }
     
    struct Weapon
    {
        int damageType;
     
        virtual int damage() = 0;
    };
     
    struct HAMM01 : Weapon
    {
        HAMM01()
        {
            damageType = CRUSHING;
        }
     
        int damage()
        {
            return dice(4) + dice(4);
        }
    };
     
    struct SW1H01 : Weapon
    {
        SW1H01()
        {
            damageType = SLASHING;
        }
     
        int damage()
        {
            return dice(6);
        }
    };
     
     
     
     
     
     
    int main()
    {
        srand(time(0));
     
        std::vector<Weapon*> weapons;
     
        weapons.push_back(new HAMM01);
        weapons.push_back(new SW1H01);
     
        std::cout<<weapons[0]->damage();
     
        return 0;
    }
    L'idée est simple : on a un marteau, qui inflige 2 dés 4 points de dégât contondant, et une épée, qui inflige 1 dé 6 points de dégât tranchant. Le but du jeu, c'est de coder la chose le plus proprement possible, et le plus lisiblement possible surtout. J'ai choisi l'héritage parce que les armes peuvent avoir des effets très différents de l'une à l'autre, et j'ai pensé que pour garder la plus grande souplesse possible dans mon code, le plus simple était encore d'écrire la fonction damage() à la main, pour chaque arme. Ça ne parait pas justifié dans mon exemple, ici, un vector stockant les jets de dé aurait amplement suffi. Mais imaginez qu'à chaque coup porté, la cible ait 5% de chance d'être aveugle pendant 3 rouds.. On ne s'en sort plus.
    Ce code est à peu près cohérent, je pense, mais quelque chose m'embête : on a donc une structure par arme, et je ne trouve pas ça très "propre" : le bon sens voudrait qu'on ait une structure la plus souple possible (appelons la "Arme", qu'on crée une première instance de cette structure appelée "marteau", une deuxième, "épée", et qu'on précise, pour chaque instance, les modalités du combat (toi tu infliges 2 dés 4, toi 1 dé 6). Mais là je me mords la queue : et si une arme rend l'ennemi aveugle pendant.. Bref.
    Une alternative envisageable serait de créer effectivement cette structure Arme, et que l'un de ses membres soit un pointeur sur une fonction, dans ce cas il faudrait créer plein de fonctions de dommage (dommage1(), dommage2(), etc) et, une fois que l'on a créé les instances de la classe, faire pointer ces pointeurs sur la bonne fonction. Par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Arme marteau;
    marteau.damageFunction = damageFunction1;
    marteau.damageType = CRUSHING;
     
    Arme épée;
    épée.damageFunction = damageFunction2;
    épée.damageType = SLASHING;
    Mais la lisibilité du code n'est pas terrible, on se retrouve avec plein de fonctions de dommage en tête de mon fichier, sans trop savoir à quoi ça correspond ni à quelle arme cette fonction de dommage est associée. Alors qu'avec mon code qui utilise le polymorphisme, c'est clair tout de suite.

    Bref, je suis un peu torturé par tout ça, si un expert passe par là et qu'il a un conseil à me donner, je prends !

    Cordialement,

  2. #2
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 759
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 759
    Par défaut
    La question a été posée ... en Java Édit: Conseils conception logiciel

    L'intervenant comme toi voulait faire du polymorphisme/ héritage pour un jeu mais ne voulait pas passer par des traits ou autres [j'ai vu passé le terme de mixin mais pas sûr de sa définition].

    La raison aussi été la même: pleins de classes à coder/ maintenir. Il a tout à fait raison, mais on peut passer des valeurs par défaut en C++

    La solution: une classe générique avec un parser de fichier XML/ CSV/ json/ autre [même peut-être à tester base de données] qui contient toutes les valeurs.
    Un exemple en XML
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <root>
      <weapon name="HAMM01" damage="CRUSHING">
        <damage nb="2">
          <dice>4</dice>
          <dice>4</dice>
        </damage>
      </weapon>
      <weapon name="SW1H01" damage="SLASHING">
        <damage nb="1">
          <dice>6</dice>
        </damage>
      </weapon>
    </root>
    J'ai oublié de dire que les experts du forum avait opté pour cette solution parce qu'il n'y avait que des attributs, et en petit nombre.

  3. #3
    Membre confirmé
    Homme Profil pro
    Développeur du dimanche
    Inscrit en
    Février 2013
    Messages
    154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur du dimanche

    Informations forums :
    Inscription : Février 2013
    Messages : 154
    Par défaut
    Je viens de regarder la discussion dont tu as envoyé le lien, je ne suis pas très habitué (pas du tout même) à utiliser des fichiers externes pour la création de mes classes. Il me vient déjà une question : imaginons que je crée une arme dont les dégâts seraient doublés lorsqu'elle est utilisée contre une certaine classe. Genre "super épée de la mort anti paladin". Ce comportement est quelque chose de très original, un comportement qui, à mon avis (mais je peux me tromper), ne peut pas être géré par des fichiers XML, CSV, ou properties.. Si ?
    Mais tant qu'à faire appel à des fichiers externes, je me suis à un moment posé la question de savoir si l'utilisation d'un langage de script ne pouvait pas être utile. Jusqu'à présent, je me suis débrouillé sans, mais peut être que c'est le moment de m'y pencher d'un peu plus près. Je pensais notamment au Lua, très facile à comprendre. J'aimerais avoir ton avis.

    Cordialement,

  4. #4
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 759
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 759
    Par défaut
    C'est un travail pour le patron de conception ("design pattern") Visiteur/ Visitor
    Le lien qui va bien

    En gros, tu as chargé une liste de tout ce qui peut être touché par une attaque (dont ta "super épée de la mort anti paladin")
    Et tu vas coder
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Damage_Visitor
    {
        void visit(Game_Object obj);
    };
     
     
    class Mega_Sword_Damage_Visitor: public Damage_Visitor {
        void visit(Paladin obj);
    };
    Après on peut faire plusieurs fichiers externes (si c'est la solution retenue) dont un "damages" qui contient les dégâts spécifiques

    Sinon je ne connais pas LUA

  5. #5
    Membre confirmé
    Homme Profil pro
    Développeur du dimanche
    Inscrit en
    Février 2013
    Messages
    154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur du dimanche

    Informations forums :
    Inscription : Février 2013
    Messages : 154
    Par défaut
    Merci pour le lien, jvais regarder tout ça

    Cordialement,

  6. #6
    Membre Expert Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Par défaut
    Salut,

    Je comprend ton problème et je pense qu'on peut commencer par déplacer le problème. En effet tu peux créer une unique classe Arme qui possède un type de dégat et le montant des dégats. Comme tu l'as dit, ça pose problème vu que les armes peuvent avoir différent effets bien distincts les unes des autres. Dans ce cas, en découpant mieux, tu peux créer une classe Effect et chaque effets d'une arme héritera de cette classe, ainsi tu améliores la compositionabilité en gardant un nombre de classes réduits (plus 1 classe/arme mais 1 classe/effet). Ça donne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    class Hero; // Représente un personnage héro.
    class Effect
    {
      virtual act(Hero) = 0;
      virtual ~Effect();
    };
     
    class BlindEffect : public Effect
    {
    private:
      double duration;
      double blindness;
     
    public:
      BlindEffect(double, double);
      virtual act(Hero h);
      virtual ~BlindEffect();
    };
     
    class WeakenEffect : public Effect
    {
    private:
      double duration;
      double slowdown;
     
    public:
      WeakenEffect(double, double);
      virtual act(Hero h);
      virtual ~WeakenEffect();
    };
     
    class Weapon
    {
      double damage;
      DamageKind kind;
      std::vector<std::unique_ptr<Effect>> effects;
     
    public:
      Weapon(double, DamageKind);
      void addEffect(std::unique_ptr<Effect>&& effect);
    };
     
    // Création d'une épée qui ralenti :
    Weapon sword(2, SLASHING);
    std::unique_ptr<Effect> weaken(new WeakenEffect(0.7, 50));
    sword.addEffect(std::move(weaken));
    Ce qui est bien c'est que tu peux ré-utiliser tes effets pour autres choses que les armes (l'environnement) et que tu as une combinaison infinie d'armes. Tu peux aussi ajouter des effets temporaires aux armes (bonus).

  7. #7
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 759
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 759
    Par défaut
    Cette histoire de trait, mixin me chiffonne parce que ce n'est pas l'idée que je me faisais du concept: un "sucre syntaxique" du langage qui permet de rajouter des méthodes à une classe en sachant que la majorité de ces dit-langages n'ont pas l'héritage multiple

    Et j'ai trouvé: Présentation des classes de Traits et de Politiques en C++

    Les traits en C++ utilisent massivement les templates pour adapter le comportement d'une fonction/ procédure/ méthode en fonction du type de l'objet.

    @Trademark tu utilises la notion de rvalue reference qui est du c++11 et est assez difficile à appréhender pour un néophyte.
    Mais peut-être que MrPchoun s'y connait

  8. #8
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    En général, devant un tel type de problème, je me contente d'avoir une arme ayant des attributs tels que "noire", "coupante", "maudite", et je laisse une fonction/classe dédiée calculer les dégâts, en fonction de la cible.

    Ca revient soit au visitor soit au décorator, selon la manière de faire.

  9. #9
    Membre confirmé
    Homme Profil pro
    Développeur du dimanche
    Inscrit en
    Février 2013
    Messages
    154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur du dimanche

    Informations forums :
    Inscription : Février 2013
    Messages : 154
    Par défaut
    Salut les jeunes, merci pour vos réponses. La solution de Trademark me plait beaucoup, j'avoue que je n'y avais pas pensé. Je vais creuser cette histoire de rvalue reference, en effet, je ne connais pas (faut dire que je suis passé au C++11 depuis deux ou trois mois à peine). Mais l'initialisation de la classe me plait, c'est propre, net, et clair (avec ça, s'il rougit pas, Trademark )

    @foetus (et je réponds aussi à leternel) : du coup je suis allé chercher en quoi consistait le visitor pattern, et.. J'ai pas compris En fait je ne comprends pas comment, avec ce schéma, on peut ajouter des méthodes à une classe. J'ai désespérément cherché une explication simple, mais j'ai pas trouvé. Même en UML, je pige pas le principe.. Mais cela dit, j'ai trouvé des implémentations simples en C++, mais je trouve que le code est pas évident au premier regard, alors que celui de Trademark l'est un peu plus (évidement, les design pattern c'est pas de ton niveau MrPchoun, retourne chez ta maman )

    Cordialement,

  10. #10
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 759
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 759
    Par défaut
    Citation Envoyé par MrPchoun Voir le message
    @foetus (et je réponds aussi à leternel) : du coup je suis allé chercher en quoi consistait le visitor pattern, et.. J'ai pas compris En fait je ne comprends pas comment, avec ce schéma, on peut ajouter des méthodes à une classe
    Tu te fourvoies

    Source Wiki:
    le patron de conception comportemental visiteur est une manière de séparer un algorithme d'une structure de données.
    En gros c'est pour appliquer un traitement en parcourant un ensemble d'objets.
    Le visiteur va demander à un objet accept(me).
    Cet objet visité peut éventuellement envoyer cet appel à un ensemble d'objets qui le compose mais surtout, ensuite dire visit(me)

    Le meilleur exemple c'est le sorcier qui crée un nuage "mortel" dans un champ de bataille.
    Le nuage "mortel" est le visiteur qui va visiter tous les personnages ou autres touchés et ainsi le nuage "mortel" pourra adapter les dommages en fonction que le personnage touché est une protection plus ou moins efficace.


    Et le décorateur/ décorator, c'est pour faire un traitement de façon transparente avant un autre traitement.
    Par exemple un coup d’épée, cela fait mal.
    Mais avec ta "super épée de la mort anti paladin", tu auras un coup d'épée normal décoré d'un effet plus "tranchant"

  11. #11
    Membre confirmé
    Homme Profil pro
    Développeur du dimanche
    Inscrit en
    Février 2013
    Messages
    154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur du dimanche

    Informations forums :
    Inscription : Février 2013
    Messages : 154
    Par défaut
    Alors je vais poser plein de questions débiles..

    1) "Tranchant", ici, c'est donc un decorator ?
    2) Oui mais pourquoi tu me parles de decorator, là on parlait de visitor là nous
    3)
    Cet objet visité peut éventuellement envoyer cet appel à un ensemble d'objets qui le compose et ensuite dire visit(me)Et le décorateur/ décorator, c'est pour faire un traitement de façon transparente avant un autre traitement.
    L'objet visité, ici, c'est l'épée ? Ou la classe Weapon ?

    Sorry for noobing

    Cordialement,

    EDIT : ah, merci pour l'exemple avec le nuage, ça commence à prendre du sens Du coup là, l'épée devient le visiteur, elle va visiter la cible, et si la cible est paladin, elle va doubler les dégats ? Et du coup, ce n'est que si la cible est un paladin qu'elle va dire visit me ?

  12. #12
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Je ne suis pas convaincu par le visiteur ici. Ne serait-ce que parce que je ne suis pas convaincu de l'existence d'une classe Paladin (qui serait aussi mauvaise qu'une classe "EpéeA2MainsTueuseDeMoustiques").

    Je pense que le mieux est de décomposer le calcul de dégâts en paramètres orthogonaux (par exemple dégâts de base, facteurs liés à la cible, facteurs liés à la combinaison type de dégâts/type d'armure, facteurs situationnels (une épée absorbant le sang qui marche mieux dans le désert)...) que sais-je encore) en nombre fini et identique d'une arme à l'autre.

    Ensuite, on va piocher parmi ces paramètres un pour chaque type : par exemple, une épée de base 2d6, *2 contre les cibles alignées avec le bien (il va te falloir une classe liée à la cible vérifiant l'alignement de la cible), faisant des dégâts de type tranchant, et dégâts *2 quand utilisée la nuit (il va te falloir une classe liée à l'environnement testant à quelle heure on est)).
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  13. #13
    Membre Expert Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Par défaut
    Je vois que ça part dans une discussion orienté design-pattern, alors je préfère te prévenir avant que tu fasses l'erreur. Il ne faut pas que tu essayes d'intégrer un design pattern, il faut juste que tu fasses ton design normalement et tu tomberas naturellement sur des problèmes qui seront résolu grâce à certain pattern. Évidemment ça aide de les connaitre avant

    Pour ce qui est du visiteur, ça permet d'ajouter des traitements algorithmiques sur des structures de données (organisé en hiérarchie — avec une classe de base) sans avoir à ajouter de nouvelles méthodes dans les classes pré-existante. Par exemple si tu voulais que l'algorithme qui calcul les attaques ne soient pas une méthode de la classe Weapon, tu peux créer une classe annexe qui, pour chaque armes, calculera les dégats. Ainsi tu ne modifies pas les classes armes existantes pour ajouter une méthode. Tu peux ajouter d'autres traitement comme par exemple le calcul de la valeur d'une arme, etc. Note que ces traitements sont principalement algorithmique.

  14. #14
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 759
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 759
    Par défaut
    Citation Envoyé par MrPchoun Voir le message
    Alors je vais poser plein de questions débiles..
    Non c'est normal

    Je rejoins Trademark: ce ne sont que des exemples, et cela va dépendre de comment tu vas coder/ concevoir ton jeu en fonction de tes besoins.
    Les patrons de conception, vont venir naturellement.
    Tu peux partir sur une solution simple comme celle de JolyLoic (qui consiste à rajouter des tests et des attributs de classes de type booléen/ enum).

    Et ensuite arriver sur la solution de Trademark sur ce post
    Et regardes pour ce bon de code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Weapon sword(2, SLASHING);
    sword.addEffect(WeakenEffect(0.7, 50));
    Au lieu de le coder "en dur", tu peux aller chercher les valeurs de manière externe (dans un fichier par exemple).
    Il n'y a peu qu'une seule façon de code

  15. #15
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Citation Envoyé par foetus Voir le message
    Tu peux partir sur une solution simple comme celle de JolyLoic (qui consiste à rajouter des tests et des attributs de classes de type booléen/ enum).
    Ma solution n'était pas si simple, c'était plus une décomposition en axes orthogonaux, chaque axe étant implémenté par exemple à l'aide du pattern strategy. Par exemple, l'axe dépendance à la cible est implémenté par une stratégie qui prend en argument uniquement la cible du coup. Parmi les classes dérivée de la stratégie, on peut en imaginer une qui regarde si la cible possède un alignement (arme maudite), une autre qui regarde si la cible est liée à un élément (arme de feu), une qui regarde la taille de la cible par rapport à un seuil (arme contre les géants), un qui regarde si la cible a tué quelqu'un récemment (arme de vengeance)...
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  16. #16
    Membre très actif

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Ma solution n'était pas si simple, c'était plus une décomposition en axes orthogonaux, chaque axe étant implémenté par exemple à l'aide du pattern strategy. Par exemple, l'axe dépendance à la cible est implémenté par une stratégie qui prend en argument uniquement la cible du coup. Parmi les classes dérivée de la stratégie, on peut en imaginer une qui regarde si la cible possède un alignement (arme maudite), une autre qui regarde si la cible est liée à un élément (arme de feu), une qui regarde la taille de la cible par rapport à un seuil (arme contre les géants), un qui regarde si la cible a tué quelqu'un récemment (arme de vengeance)...
    J'adore la solution de Trademark (vu que j'aurais surement fait la même chose), mais ton idée me semble tout aussi intéressante, même si j'ai un peu de mal à visualiser. Est-ce qu'il n'y a pas moyen de coupler la vision de Trademark qui est plus "conceptuelle (assembliste ? je ne sais pas trop comment appeler ça)" avec ta vision plus "comportementale" ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    class Strategy
    {};
     
    class VaporiserEpeeAvecInsecticide : public Strategy
    {};
     
    class Weapon 
    {};
     
    class ArmeADeuxMainTueuseDeMoustique : public Weapon
    {
    public :
       ArmeADeuxMainTueuseDeMoustique() { mesComportements.push_back(VaporiserEpeeAvecInsecticide()); }
    private :
        vector<Strategy> mesComportements;
        vector<Effect> mesEffets; //je sais pas si cela ferait office de doublon ou de complément....
    }

    Qu'est-ce que vous en dites ?

  17. #17
    Membre Expert Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Par défaut
    J'ai du mal à voir comment ma solution est compatible avec le pattern strategy. Ce que je n'ai pas exposé c'est comment on va appliquer un effet au personnage (implémenté dans la méthode virtuelle act(Hero)). À mon avis c'est à ce moment que le pattern visitor entrera en jeu et on obtiendra quelque chose comme :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    class AliveEntityVisitor;
    class AliveEntity
    {
    public:
      virtual accept(std::unique_ptr<AliveEntityVisitor>& visitor) = 0;
    };
     
    template <class ConcreteAliveEntity>
    class AliveEntityCRTP : public AliveEntity
    {
    public:
      virtual accept(std::unique_ptr<AliveEntityVisitor> & visitor)
      {
        visitor->visit(*static_cast<ConcreteAliveEntity*>(this));
      }
    };
     
    class GiantMonster : public AliveEntityCRTP<GiantMonster>
    {
    };
     
    class Hero : public AliveEntityCRTP<Hero>
    {
    };
    Je fais ça bien au risque de perdre l'OP, mais je compte sur lui pour poser les questions qu'il voudra ;-) Pour le moment ce que j'ai écrit n'a qu'un seul but, c'est de pouvoir dispatcher les types de monstres pour leur appliquer des effets. Si on définit le visiteur il sera implémenté comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    class AliveEntityVisitor
    {
    public:
      virtual visit(Hero &hero) = 0;
      virtual visit(GiantMonster &giant) = 0;
    };
    Chaque effet sera donc implémenté sous la forme d'un visiteur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    class BlindEffect : public AliveEntityVisitor
    {
    public:
      virtual visit(Hero &hero);
      virtual visit(GiantMonster &giant);
    };
    Et donc appliquer l'effet voulu en fonction du personnage (monstre ou héro) et de leurs propres caractéristiques. Le gros désavantage du visiteur ainsi utilisé c'est que à chaque fois que tu voudras ajouter un nouveau monstre tu devras modifier tous les effets existants. Reste à définir les caractéristiques d'un personnage, ce qui ne sera pas du gâteau non plus :-)

    (Vu que ma solution précédente semblait plaire, j'ai édité pour ajouter les destructeurs virtuels et les pointeurs (via unique_ptr)).

  18. #18
    Membre très actif

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Par défaut
    Par contre, pour le coup je n'aime pas du tout cette approche

    Comme tu le dis, c'est pas terrible vis-à-vis de l'OCP. Ce qui me gêne en plus dans cette approche , c'est que la notion de visiteur est tellement loin du concept des monstres, des épées, des effets, ... c'est là généralement là que je trouve que les développeurs se perdent dans la technique et oublient de rester proches du concept. La compréhension du code devient très difficile, et je suis sûr qu'il y a moyen de faire la même chose, sans perdre en lisibilité.

    Tu parles d'appliquer un effet à un personnage, mais je ne comprends pas si tu parle des effets des épées, où si tu veux dire 'comment le personnage va subir ces effets ?'.

    Si tu parles de comment les personnages vont subir les effets, je resterai sur le même principe que pour l'épée : le personnage peut subir (il a) des effets, le personnage est immunisé contre des effets, etc..

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class Hero : public Entity
    {
       vector<Effect> mesImmunites;  
    public : 
       bool estImmuniseContre(Effect e); //return mesImunnites.contains(e);
    };
     
    //ailleurs...
    if (!Hero.estImmuniseContre(Hermoroides())
       //acheter de la pommade

  19. #19
    Membre Expert Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Par défaut
    Mouai, je suis aussi convaincu par ta solution que par la mienne, mais bon je pense qu'on s'emporte un peu :p La solution dépend entièrement du niveau de complexité que le jeu possède et des interactions entre les différents composants. Notre problème c'est qu'on essaye de résonner sur une solution générique et forcément c'est bien trop compliqué Enfin, si ça peut inspirer MrPchoun, je serai déjà content

  20. #20
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 759
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 759
    Par défaut
    Il me semble qu'il faut utiliser une usine virtuelle/ Abstract Factory

    Et, à brûle-pourpoint, je dirais: Un personnage est caractérisé par une protection, une arme, un ensemble de caractéristiques [...]
    Une arme par un effet et un matériau [...]
    Ainsi de suite...


    @JolyLoic La patron de conception Stratégie/ Strategy se rapproche plus de ce que je pensais lorsque je parlais des traits

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Conception de classes
    Par Seth77 dans le forum Général Dotnet
    Réponses: 8
    Dernier message: 15/01/2007, 15h57
  2. [POO] conception des classes
    Par poukill dans le forum C++
    Réponses: 229
    Dernier message: 19/07/2006, 08h28
  3. [conception] reprise classes mal pensées
    Par in dans le forum Général Java
    Réponses: 8
    Dernier message: 05/06/2006, 13h45
  4. Conception de classe
    Par Azharis dans le forum C++
    Réponses: 9
    Dernier message: 17/12/2005, 10h15
  5. probleme de conception de classe
    Par NhyMbuS dans le forum C++
    Réponses: 2
    Dernier message: 08/05/2005, 17h10

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo