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 :

Encapsuler ou dériver ?


Sujet :

C++

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Juillet 2015
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 24
    Localisation : Belgique

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Juillet 2015
    Messages : 26
    Points : 35
    Points
    35
    Par défaut Encapsuler ou dériver ?
    Bonjour à tous,

    Au fil de mes pérégrinations programmatiques, j'ai plusieurs fois fait l'expérience d'un dilemme. Lorsque je veux créer classe en contenant une autre ainsi que d'autres données, je ne sais jamais quand ajouter ladite classe en attribut ou au contraire, quand hériter de ladite classe.
    Exemple : Admettons que je programme en 2D et que j'ai une classe Sprite qui contient l'imagine affichée ainsi que la position dudit Sprite dans le monde. Je veux créer une classe Personnage : un personnage est représenté par un sprite, mais contient d'autres informations : nom, vie, etc... ainsi qu'une flopée de méthodes qui vont avec.
    Convient-il d'avoir le Sprite en attribut, ou plutot d'hériter du Sprite ?
    Instincitvement j'utilise la solution de l'attribut, mais lorsque ledit attribut possède beaucoup de méthodes, le code s'alourdit beaucoup (Si par exemple, pour mon personnage, je dois créer une méthode afficher qui appelle la méthode afficher du Sprite). D'un autre côté, hériter de Sprite me laisse perplexe, notamment parceque le Personnage "contient" un Sprite plus qu'il n'en est un. Niveau LSP et tout ça, ça me semble bof.

    Du coup, en règle générale, comment choisir la technique utilisée ?

  2. #2
    Membre émérite
    Avatar de prgasp77
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Juin 2004
    Messages
    1 306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 306
    Points : 2 466
    Points
    2 466
    Par défaut
    Une première question que tu dois te pauser est : doit-on pouvoir utiliser un personnage comme on utilise un sprite ? Mais attention, si la réponse est "oui", il faut continuer l'investigation : ce besoin est-il réel et justifié ou est-ce un gimmick, une mauvaise conception ? C'est une idée d'entrée en matière.
    -- Yankel Scialom

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 965
    Points
    32 965
    Billets dans le blog
    4
    Par défaut
    De manière générale, si la classe de base n'a aucune fonction virtuelle, y'a peu de chance que tu doives en hériter.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Juillet 2015
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 24
    Localisation : Belgique

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Juillet 2015
    Messages : 26
    Points : 35
    Points
    35
    Par défaut
    Merci pour les réponses. Dans mon cas tout incite à encapsuler, mais je vais devoir copier quelques méthodes du Sprite pour qu'elles s'appliquent au Personnage. (En fait, mon "souci déclencheur" tenait dans le fait que je déplace mon personnage et non son sprite, qui est toujours au point 0,0 des coordonnées... du personnage. Parfait pour déplacer l'image, moins pour calculer les collisions avec les méthodes du Sprite.)
    D'un autre côté, je ne vois dans mon cas aucun inconvénient à hériter de Sprite, notamment car Personne comme Sprite héritent des meme classes abstraites d'interfaces Drawable et Transformable. Du coup, dans ce cas particulier, le Personnage est "parallèle" au Sprite qu'il contient... Ca porte à confusion

  5. #5
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Citation Envoyé par bisthebis Voir le message
    Parfait pour déplacer l'image, moins pour calculer les collisions avec les méthodes du Sprite.)
    D'un autre côté, je ne vois dans mon cas aucun inconvénient à hériter de Sprite, notamment car Personne comme Sprite héritent des meme classes abstraites d'interfaces Drawable et Transformable. Du coup, dans ce cas particulier, le Personnage est "parallèle" au Sprite qu'il contient... Ca porte à confusion
    A priori, Sprite et Collision c'est deux choses différentes, donc 2 classes, ça devrait pas être regroupé.

    Un Personnage n'à imo pas à être Drawable.

    Tu peux tout à fait exposer le Sprite pour l'affichage.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Personnage : public Transformable {
    public:
       Sprite const& sprite() const() { return m_sprite; }
     
    private:
       Sprite m_sprite;
    };
     
    // ...
    Personnage p;
    draw(p.sprite());
    Si le fait d'exposer le Sprite dérange, tu peux l'exposer via une classe utilitaire.
    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
    template <class T>
    struct DrawT : public Drawable {
       void draw(RenderTarget& rt) const {
          rt.draw(m_sprite);
       }
     
       DrawT(T const& obj): m_sprite(obj.sprite()) { };
     
    private:
       Sprite m_sprite;
    };
     
    class Personnage : public Transformable {
    public:
       DrawT<Personnage> drawer() const { return DrawT<Personnage>(*this); }
     
    private:
       friend class DrawT<Personnage>;
       Sprite const& sprite() const { return m_sprite; }
     
       Sprite m_sprite;
    };
     
    Personnage p;
    auto d = p.drawer();
     
    draw(d));

  6. #6
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Normalement, ton personnage est positionné par des coordonnées propres aux données (en metres, par exemple), et le sprite en pixels.
    Tu as probablement du écrire une fonction, quelque part dans le code graphique, qui converti ces coordonnées de jeu en coordonnées écran.

    C'est cette fonction qui te donnera les coordonnées du sprite

    Ca ne devient évident qu'en 3D, où les coordonnées du monde sont relatives à un repère stable et 3D, tandis que les coordonnées en pixels sont liées à la projection caméra.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Juillet 2015
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 24
    Localisation : Belgique

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Juillet 2015
    Messages : 26
    Points : 35
    Points
    35
    Par défaut
    Un Personnage n'à imo pas à être Drawable.

    Tu peux tout à fait exposer le Sprite pour l'affichage.
    En fait, Drawable ne possède qu'une métode virtuelle pure, draw. Mon implémentation de draw dans personnages appelle simplement la fonction draw du Sprite contenu. J'imagine que c'est fort équivalent à un accesseur du Sprite si ledit accesseur n'a pas d'autre utilité.

    Normalement, ton personnage est positionné par des coordonnées propres aux données (en metres, par exemple), et le sprite en pixels.
    Tu as probablement du écrire une fonction, quelque part dans le code graphique, qui converti ces coordonnées de jeu en coordonnées écran.

    C'est cette fonction qui te donnera les coordonnées du sprite
    Pour l'instant j'utilise comme unité de mesure le "pixel en zoom nul", mais réflexion faite je pense pertinent de changer ça. Je pense que je vais placher là-dessus

  8. #8
    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 : 49
    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
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par bisthebis Voir le message
    Du coup, en règle générale, comment choisir la technique utilisée ?
    La règle en général est le principe de substitution de Liskov (LSP, Liskov Substitution principle, nommé d'après Barbara Liskov). Pour que B dérive de A, il faut que partout où on peut utiliser un A, on puisse substituer un B et que le code soit justifié, logique et cohérent.

    On a souvent tendance à sur-utiliser l'héritage qui est la relation la plus forte qui soit entre deux classes. Du coup, si tu hésites, c'est probablement qu'il vaut mieux t'abstenir
    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.

  9. #9
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 629
    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 629
    Points : 10 554
    Points
    10 554
    Par défaut
    Si tu as 2-3 heures à perdre, il y a un livre gratuit sur le développement de jeu à l’ancienne: O'Reilly Media - iPhone Game Development.

    Bon c'est de l'Objective-C, mais c'est facile à comprendre [les premiers chapitres t'expliquent la programmation iOS 3-4-5]: le pdf et les codes sources

    Édit: Le chapitre 5 c'est pour un jeu 3D [très] [très] léger et le chapitre 3 ce sont les fondations. Donc c'est le chapitre 4 qu'il faut regarder

  10. #10
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Salut,

    De manière générale, tu dois te dire que l'héritage est la relation la plus forte qui puisse exister entre deux classes. C'est donc la relation que l'on essayera d'utiliser le moins possible.

    Si tu te pose la question de savoir s'il est préférable d'utiliser l'héritage ou la composition(/l'agrégation), on peut donc assez facilement partir du principe que la composition (ou l'agrégation) sera sans doute le meilleur choix par défaut.

    En effet, pour que tu puisse faire hériter une classe B d'une classe A, il faut que le principe de substitution de Liskov soit impérativement respecté, ainsi que l'a déjà fait savoir Loic et, pour qu'il soit respecté, il faut que tu puisse envisager d'utiliser ta classe B partout où un objet de type A aurait été attendu.

    Mais ce n'est pas tout : Si tu y réfléchis bien, absolument tout ce qui fera partie de ton jeu sera -- tot ou tard -- destiné à devoir être affiché. De là à estimer que tout ce qui fait partie de ton jeu devrait hériter d'une classe quelconque (de Sprite, par exemple), il n'y aurait qu'un pas, que tu aurais très largement tord de franchir.

    Car, si tu franchis ce pas, tu ne vas pas tarder à te retrouver avec une hiérarchie de classes monstrueuse et totalement ingérable, dans laquelle tout dérive de Sprite.

    Or, même si ton personnage, tes armes, tes potions, tes sors ou que sais-je d'autre finiront bel et bien par devoir être affichés, ce que tu attends de la part de ces différents types d'objets est et restera d'être en mesure de rendre certains services spécifiques, propres à la nature même du type en question.

    De plus, il existe un concept appelé MCV (pour Model Controler View) qui nous incite à essayer de séparer le plus possible la notion d'affichage (que l'on retrouve pour n'importe quel Sprite) du reste du code.

    De ce fait, on se fout pas mal de savoir que ton Personnage est représenté par un Sprite particulier, car, ce que l'on attend en priorité de sa part, c'est qu'il soit capable de fournir des services tels que:
    • répondre à la question "quelle est ta position"
    • répondre à la question "es-tu en vie"
    • obéir à l'ordre "déplace toi vers telle position" ou "déplace-toi de telle distance en X et telle distance en Y"
    • obéir à l'ordre "attaque tel ou tel élément"
    • obéir à l'ordre "équipes-toi de telle ou telle arme"
    • obéir à l'ordre "bois telle ou telle potion"
    • j'en passe, et sans doute de meilleures...

    Et l'idée est donc d'avoir "quelque chose" qui pourra indiquer que, pour représenter ton personnage, il faut utiliser tel sprite particulier, et le faire afficher à telle position particulière. Tu devras, pour faire simple, trouver le moyen de créer une relation "la plus légère possible" entre ton personnage et le sprite qui permet de le représenter, de manière à pouvoir demander l'affichage de ce sprite, sans avoir à s'inquiéter des autres caractéristiques de ton personnage
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  11. #11
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Juillet 2015
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 24
    Localisation : Belgique

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Juillet 2015
    Messages : 26
    Points : 35
    Points
    35
    Par défaut
    Merci foetus pour le lien, je regarderai ça en détail quand j'aurai du temps


    A la réflexion, faire tout hériter de Sprite semble en effet hasardeux, en revanche je suis instinctivement tenté de tout faire dériver de Drawable pour que chaque objet soit affichable, mais quand on pense en architecture genre MVC (j'ai lu pas mal de trucs là-dessus, mais je n'ai jamais appliqué et ma compréhension n'est que théorique) j'imagine que pouvoir faire monPersonnage.afficher() est mal. Reste que j'ai du mal à comprendre le pourquoi exact
    Est-ce une histoire de "ne remplir qu'une fonction par classe" ?

    Du coup, quelles sont les possibilités propres pour séparer ça ? Avoir le sprite en attribut ? En pointeur ? Autre chose ?
    Je vais devoir relire tout ce que je sais sur le MVC car c'est fort confus pour moi. Faut-il pour chaque objet avoir un objet vue correspondant ? Ou est-ce que la vue correspond à mon moteur graphique ? C'est assez abstrait pour moi

  12. #12
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 965
    Points
    32 965
    Billets dans le blog
    4
    Par défaut
    A moins d'avoir une classe de manager d'affichage sur lequel enregistrer chacun de tes sprites à leur création, tu ne pourras de toutes façons pas échapper à avoir un équivalent de myPerso.Draw()
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  13. #13
    Membre émérite
    Avatar de prgasp77
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Juin 2004
    Messages
    1 306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 306
    Points : 2 466
    Points
    2 466
    Par défaut
    Citation Envoyé par Bousk Voir le message
    A moins d'avoir une classe de manager d'affichage sur lequel enregistrer chacun de tes sprites à leur création, tu ne pourras de toutes façons pas échapper à avoir un équivalent de myPerso.Draw()
    Pas nécessairement, ou pas directement. Si on part du principe qu'une classe n'a qu'une responsabilité (dans le sens de fonctionnalité), on est poussé à séparer la gestion du personnage de son affichage. Une classe Person qui gère les attributs dudit personnage (position, statut, inventaire, éléments du jeu...) et une autre qui n'a pour seule charge que de le dessiner.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class PersonDrawer
    {
        Person const& _person;
    public:
        PersonDrawer() = delete;
        PersonDrawer(Person const& p) : _person(p) {}
        /** @todo : destructor, copy cstr, move cstr, operator= w/ & w/o move semantics */
     
        void Draw(Context c);
    };
    On est ici dans un patter Modèle-Vue. Il est tout à fait possible d'insérer un contrôleur et pouf ! ça fait un MVC.

    Qu'en penses-tu ?
    -- Yankel Scialom

  14. #14
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 629
    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 629
    Points : 10 554
    Points
    10 554
    Par défaut
    Le contrôleur existe déjà : c'est [en gros, et dépendant de l'implémentation] la classe "World" qui contient le plateau - "Tiles" et la liste des "Entities *" [en plus de la caméra]

    Donc, si on coupe la classe "Entity" en 2, 1 avec [seulement] le gameplay comme les points de vie et 1 autre avec [seulement] l'affichage, effectivement on a un MVC


    *: On parle d'entity parce qu'un mur doit être représenté, mais n'est pas forcément animé [pas de sprite, juste un tile suffit]

  15. #15
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Juillet 2015
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 24
    Localisation : Belgique

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Juillet 2015
    Messages : 26
    Points : 35
    Points
    35
    Par défaut
    Du coup, si je fonctionne en MVC comme vous le décrivez, comment fonctionne PersonDrawer ? Un pointeur sur le modèle pour connaitre la position etc, et une texture en attribut ?
    Enfin, en parlant de contrôleur, est-ce que ca veut dire que je dois utiliser le Drawer pour gérer les événements ?

  16. #16
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Avant toute chose, il faut bien se rendre compte que l'approche purement OO montre des faiblesses lorsqu'il s'agit de développer un jeu, à cause du nombre de combinaisons possibles et de classes que cela finira par sous entendre.

    Prenons les armes, par exemple : Si je veux créer une hache, une épée et un gourdin, je pourrais créer une classe mère Weapon dont je ferais hériter une classe Sword, une classe Axe et une classe Cudgel. Pas mal...

    Mais, par la suite, je vais sans doute vouloir avoir une claymore, une hache de guerre ou un marteau de guerre. Ce sont aussi des armes, mais ce sont des armes qui nécessitent les deux mains pour être utilisés. Je devrai donc faire la distinction entre les "petites" épées, celles qui peuvent être utilisées à une main et les grandes, celles qui nécessitent les deux mains pour les utiliser, et je devrai faire pareil pour les hache et mes gourdins.

    Puis, j'aurai besoin d'une classe pour les arcs, puis d'une autre pour les couteaux de lancé et, qui sait, une autre pour le boomerang.

    Mais ce n'est pas tout : avec l'évolution du jeu, je voudrai avoir des armes magiques, qui ajoutent des dégats magiques à ceux de la lame, puis des armes qui modifient l'une ou l'autre caractéristique du personnage, puis des armes que je peux sertir afin de les rendre magiques avec des résultat divers (certaines pierres ajoutant des degats de magie, d'autres modifiant l'une ou l'autre caractéristique du personnage qui l'utilise).

    Le tout sans oublier qu'une arme, c'est d'abord et avant tout une piece d'inventaire qui peut être équipée. On devrait donc retrouver une classe de base commune entre les armes et les pieces d'armure, afin de pouvoir mélanger les deux dans l'inventaire.

    Mais on devrait aussi trouver une classe de base commune entre les armes, les armure et les éléments que l'on peut manger ou avaler (ex : les potions), parce que ces derniers prennent aussi place dans l'inventaire. Et au final, on va se retrouver avec un "god-object" et une hiérarchie de classe totalement ingérable.

    L'idée pour un jeu est donc de partir d'une approche de type ECS (Entity Components System), qui permettra de mettre "n'importe quel composant" en relation avec "n'importe quelle entité" et de mettre en place un ensemble de "systèmes" qui s'assureront de la présence d'un composant donné pour une entité donnée et de la mise à jour en fonction des situations.

    Maintenant, pourquoi voudrait tu faire hériter tous tes objets de Drawable Peut être as-tu l'impression que les seules vues que tu auras seront des vues graphiques

    Mais, dis moi alors, est ce qu'un affichage "console" proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    nom    |  race    |   type   |niveau | vie | arme            
    ====================================================
    Henry  | goblin   | eclaireur| 3     | 15  | gourdin
    Jaques | orc      | chaman   | 15    | 150 | bâton sacré
    Victor |nain      | guerrier | 6     | 75  | marteau de guerre
    ne te semble pas être une représentation "tout aussi correcte" de tes données que ce que tu pourrais obtenir en faisant tout hériter de Drawable

    Ce sur quoi je veux attirer ton attention, c'est sur le fait que tu as forcément des données qui seront manipulée par ton jeu, mais qu'il doit toujours y avoir une distinction très claire entre les données que tu utilises et la manière dont tu les représente dans ta vue.

    Ainsi, peut être que tu pourras associer une image à "marteau de guerre", à "chaman orc" ou à "eclaireur goblin". Mais cette image n'a rien à faire au niveau de la classe personnage! Elle n'a du sens que dans le contexte d'affichage particulier dans lequel tu utilise des éléments "drawables" (et des sprites, selon toute vraisemblance).

    Du coup, tu peux t'arranger pour maintenir "quelque part" (sans doute au niveau du contexte d'afffichage) une liste des images qui te permettent de représenter les différents éléments (je simplifie, ce sont peut être des objets 3D avec squelettes, textures et tout le saint frusquin ) et, tout ce qu'il faut pouvoir faire est d'indiquer "ce qui doit être affiché" et "à quel endroit". Autrement dit, pour que l'affichage fonctionne, tout ce qu'il te faut sera un code qui pourrait ressembler à quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    view.draw(leContext, perso.id(), perso.posX(),perso.posY());
    view.draw(leContext, spell.id(), spell.poX(), spell.posY());
    vie.draw(leContext, weapon.id(), weapon.posX(), weapon.posY());
    Le respect du principe de la responsabilité unique est donc bel et bien une base saine pour arriver à séparer correctement les différents éléments, car, si tu le respecte, tu te rend compte qu'une classe Personnage, Weapon ou Spell n'a aucune raison d'avoir la responsabilité de se tracer (car on peut donner un aperçu précis de la situation d'une manière différente) et que, de leur coté, les élément "traçables" n'ont absolument aucun besoin de savoir "à quoi cela correspond" effectivement (car tout élément tracable n'est "rien d'autre qu'un image" qu'il faut afficher à une position donnée, même si c'est simplifié à l'extrême )
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  17. #17
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 965
    Points
    32 965
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par prgasp77 Voir le message
    Pas nécessairement, ou pas directement. Si on part du principe qu'une classe n'a qu'une responsabilité (dans le sens de fonctionnalité), on est poussé à séparer la gestion du personnage de son affichage. Une classe Person qui gère les attributs dudit personnage (position, statut, inventaire, éléments du jeu...) et une autre qui n'a pour seule charge que de le dessiner.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class PersonDrawer
    {
        Person const& _person;
    public:
        PersonDrawer() = delete;
        PersonDrawer(Person const& p) : _person(p) {}
        /** @todo : destructor, copy cstr, move cstr, operator= w/ & w/o move semantics */
     
        void Draw(Context c);
    };
    On est ici dans un patter Modèle-Vue. Il est tout à fait possible d'insérer un contrôleur et pouf ! ça fait un MVC.

    Qu'en penses-tu ?
    Tout cela est bien beau, mais à quel moment tu appelles ton Draw ?
    - par le personnage qui contient un Drawer ?
    - par un manager où tu as enregistré ton Drawer et qui les appelle tous ?
    Bref, tu tournes en rond.

    D'ailleurs, te fatigue pas à overengeenerer du code que de toutes façons tu jetteras dans quelques semaines/mois parce que tu auras gagné en expérience et comprendras comment faire mieux. Ou tout simplement parce que tu seras allé dans un mur avec et il te faudra (re)commencer (en partie).
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  18. #18
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Juillet 2015
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 24
    Localisation : Belgique

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Juillet 2015
    Messages : 26
    Points : 35
    Points
    35
    Par défaut
    Ce sur quoi je veux attirer ton attention, c'est sur le fait que tu as forcément des données qui seront manipulée par ton jeu, mais qu'il doit toujours y avoir une distinction très claire entre les données que tu utilises et la manière dont tu les représente dans ta vue.

    Ainsi, peut être que tu pourras associer une image à "marteau de guerre", à "chaman orc" ou à "eclaireur goblin". Mais cette image n'a rien à faire au niveau de la classe personnage! Elle n'a du sens que dans le contexte d'affichage particulier dans lequel tu utilise des éléments "drawables" (et des sprites, selon toute vraisemblance).

    Du coup, tu peux t'arranger pour maintenir "quelque part" (sans doute au niveau du contexte d'afffichage) une liste des images qui te permettent de représenter les différents éléments (je simplifie, ce sont peut être des objets 3D avec squelettes, textures et tout le saint frusquin ) et, tout ce qu'il faut pouvoir faire est d'indiquer "ce qui doit être affiché" et "à quel endroit". Autrement dit, pour que l'affichage fonctionne, tout ce qu'il te faut sera un code qui pourrait ressembler à quelque chose comme
    Je vais paraître con, mais qu'est-ce que tu appelles le contexte ? (J'imagine que dans mon jargon mental j'utilise betment un synonyme, mais... je bloque )

    Reste ma question principale : faut-il stocker la liaison entre la donnée et sa représentation par un pointeur... Ou par autre chose ?

  19. #19
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Ben, le contexte d'affichage n'est rien de plus que ce que le mot veut dire : c'est toute la mécanique qui te permet de créer une fenêtre et d'y afficher de jolies image à des positions que tu as clairement déterminées, et qui permet aussi généralement de récupérer les événements issus du clavier, de la souris ou, pourquoi pas, du joystick

    C'est donc un concept tout à fait général qui mérite d'être cité pour savoir "comment les différents éléments seront affichés dans ta fenêtre"
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

Discussions similaires

  1. Réponses: 31
    Dernier message: 30/03/2006, 16h57
  2. URGENT DRIVER ODBC
    Par Casp dans le forum Débuter
    Réponses: 3
    Dernier message: 28/04/2003, 16h24
  3. [PostgreSQL] PB de drivers JAVA
    Par koundelitch dans le forum Administration
    Réponses: 5
    Dernier message: 14/03/2003, 15h09
  4. [MFC] Utilisation Drivers
    Par LAPLACE dans le forum MFC
    Réponses: 4
    Dernier message: 21/12/2002, 10h29
  5. [MFC](encapsulation ADO) ou placer le code
    Par philippe V dans le forum MFC
    Réponses: 2
    Dernier message: 13/06/2002, 14h58

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