Partage
  • Partager sur Facebook
  • Partager sur Twitter

Créer des variables personnage1, personnage2 ...

Le tout avec une boucle ?

Sujet résolu
    19 mars 2008 à 15:17:49

    Bonjour à tous :)

    Je suis conscient que ma question va paraitre débile, voire à déjà été posée plusieurs fois, mais une recherche ne m'a pas permis de trouver la solution dans un autre sujet, c'est pourquoi je m'addresse une nouvelle fois à vous :p


    Voilà le bout de code qui me tracasse :

    JeuDeRole.cpp


    1. // ...
    2. void JeuDeRole::creerPersonnages()
    3. {
    4.     cout << "Combien de joueurs ? " << endl;
    5.     int nbJoueurs;
    6.     string nombreJoueurs;
    7.     getline (cin, nombreJoueurs);
    8.     stringstream(nombreJoueurs) >> nbJoueurs;
    9.     string tableauDeNoms[nbJoueurs];
    10.     for (int i=1; i<=nbJoueurs; i++)
    11.     {
    12.         cout << "Combattant " << i << " :";
    13.         cout << endl << "Quel est le nom de votre personnage ? ";
    14.         getline(cin, tableauDeNoms[i]);
    15.         cout << endl << endl;
    16.     Personnage personnage1(tableauDeNoms[i]);
    17. }


    Mon problème arrive à la ligne 17, lorsque je souhaite créer mon objet personnage de type Personnage. J'aimerais que le premier joueur s'appelle personnage1, le 2ème personnage2, etc. Mais mes faibles connaissances en C++ font que je n'arrive pas à trouver le bon code à écrire.

    Merci beaucoup pour vos éclaircissements qui vont me faire comprendre beaucoup de choses :D

    • Partager sur Facebook
    • Partager sur Twitter
      19 mars 2008 à 15:38:31

      En gros, tu veux associer un nom à un personnage ?
      Et outre cet aspect, tu veux pouvoir itérer sur chaque perso, par exemple dans une boucle de saisie, de combat... ?

      Une solution (tatsaaamm !) la STL :)
      Utilise une map, elle te permettra d'associer un nom à chaque de tes persos (comme ça, tu pourras même mettre le nom du joueur, ou ce qui t'arrange...)
      1. #include <map>
      2. // ...
      3. void JeuDeRole::creerPersonnages( map<string, Pesonnage*> & persos)
      4. {
      5.     cout << "Combien de joueurs ? " << endl;
      6.     int nbJoueurs;
      7.     string nombreJoueurs;
      8.     getline (cin, nombreJoueurs);
      9.     stringstream(nombreJoueurs) >> nbJoueurs;
      10.     string tableauDeNoms[nbJoueurs];
      11.     for (int i=1; i<=nbJoueurs; i++)
      12.     {
      13.         stringstream nom_perso("");
      14.         cout << "Combattant " << i << " :";
      15.         cout << endl << "Quel est le nom de votre personnage ? ";
      16.         getline(cin, tableauDeNoms[i]);
      17.         cout << endl << endl;
      18.         nom_perso << "personnage" << i;
      19.         persos[ nom_perso.str() ] = new Personnage(tableauDeNoms[i]);
      20. }
      21. ...
      22. // Ensuite, tu accedes a tes persos en faisant :
      23. persos["personnage1"]->action(...);
      24. // Attention a bien liberer la memoire, vu qu'elle est allouee dynamiquement !
      25. while ( !persos.empty() )
      26. {
      27.     delete persos.begin()->second;
      28.     // En fait, cela te renvoie une paire<cle, valeur> : la cle est donnee par first, la valeur par... second.
      29.     persos.erase(persos.begin());
      30. }
      31. // autre methode :
      32. for ( map<string, Personnage *>::iterator perso = persos.begin(); perso != persos.end(); ++perso)
      33.     delete perso->second; // Un iterateur marche comme un pointeur, d'ou la fleche.
      • Partager sur Facebook
      • Partager sur Twitter
      Anonyme
        19 mars 2008 à 15:48:59

        erf... Comment dire... MERCI Groscask !!!!!

        Là j'ai saisi l'ensemble, vais étudier plus en détail le code et réviser certaines notions du C++ :p

        Encore merci :D
        • Partager sur Facebook
        • Partager sur Twitter
          19 mars 2008 à 16:10:56

          Le faire une map dans ce cas là ca risque pas de poser des problèmes si il veut donner le même nom à plusieurs personnages ??
          • Partager sur Facebook
          • Partager sur Twitter
          Anonyme
            19 mars 2008 à 16:18:08

            Citation : Herumor

            Le faire une map dans ce cas là ca risque pas de poser des problèmes si il veut donner le même nom à plusieurs personnages ??

            Si la clef est la même il aura quelques problèmes, mais si les valeurs sont les même il n'y a pas de problème. Les lignes 19 et 20 ne permettent pas d'utiliser deux fois le même nom comme i ne fait que de grandir.

            Mais au fait, il n'est pas obligé d'utiliser des pointeurs sur Personnage. Une map<std::string, Personnage> fonctionnerais aussi. Et la libération serait faite automatiquement. Ou simplement via la std::map::clear. Non?
            • Partager sur Facebook
            • Partager sur Twitter
              19 mars 2008 à 16:35:53

              Le souci avec ça, c'est la création du Personnage :/
              Et ensuite, ça risque d'être un peu embêtant parfois, quand ça devient de plus en plus complexe : les maps sont un conteneur que l'on ne maîtrise pas de but en blanc.

              Et je parle pas mal par expérience pour le coup ^^'.
              Après, il peut toujours essayer... (y'en a qui ont eu des problèmes...)
              • Partager sur Facebook
              • Partager sur Twitter
                19 mars 2008 à 16:52:13

                Citation : hiura

                Mais au fait, il n'est pas obligé d'utiliser des pointeurs sur Personnage. Une map<std::string, Personnage> fonctionnerais aussi. Et la libération serait faite automatiquement. Ou simplement via la std::map::clear. Non?



                en effet, mais dans ce cas il perd les benefices du polymorphisme (bon je sais pas s'il en fait)

                et pour la liberation -> http://cpp.developpez.com/faq/cpp/?page=STL#STL_delete_sequence
                • Partager sur Facebook
                • Partager sur Twitter
                Anonyme
                  19 mars 2008 à 17:45:13

                  Citation : Chlab_lak

                  en effet, mais dans ce cas il perd les bénéfices du polymorphisme (bon je sais pas s'il en fait)

                  Je n'avais pas pensé à ça. C'est donc mieux avec des pointeurs.
                  • Partager sur Facebook
                  • Partager sur Twitter
                    19 mars 2008 à 17:48:52

                    Et puis je ne vois pas comment un personnage pourrait être résumé à une valeur copiable. C'est au contraire une entité qui ne doit pas être copiable => pointeur, voire mieux pointeurs intelligents dans un premier temps
                    • Partager sur Facebook
                    • Partager sur Twitter
                    C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                      19 mars 2008 à 18:00:02

                      Je vous donnerais le code de mon projet une fois les erreurs corrigées, vos critiques sur ma conception objet me seront d'autant plus utiles :)

                      Là je bloque sur un problème, et j'aimerais savoir s'il est possible de récupérer le type de mon objet.

                      En gros, J'aimerais savoir si mon personnage est de type Guerrier ou Magicien : s'il est de type Magicien, alors je lui augmente son mana...

                      Merci :)
                      • Partager sur Facebook
                      • Partager sur Twitter
                        19 mars 2008 à 18:02:59

                        Citation : Fandekasp

                        Là je bloque sur un problème, et j'aimerais savoir s'il est possible de récupérer le type de mon objet.

                        En gros, J'aimerais savoir si mon personnage est de type Guerrier ou Magicien : s'il est de type Magicien, alors je lui augmente son mana...



                        cf FAQ de developpez, mais ca me semble etre une mauvaise conception
                        • Partager sur Facebook
                        • Partager sur Twitter
                          19 mars 2008 à 18:09:46

                          oui je pense aussi :/

                          Merci pour le lien, je vais travailler dessus
                          • Partager sur Facebook
                          • Partager sur Twitter
                            19 mars 2008 à 19:07:46

                            Oui. Et que faire du biclassage qui peut apparaitre lors d'une montée de niveau ?
                            • Partager sur Facebook
                            • Partager sur Twitter
                            C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                              19 mars 2008 à 21:19:09

                              Citation : Fandekasp

                              Je vous donnerais le code de mon projet une fois les erreurs corrigées, vos critiques sur ma conception objet me seront d'autant plus utiles :)

                              Là je bloque sur un problème, et j'aimerais savoir s'il est possible de récupérer le type de mon objet.

                              En gros, J'aimerais savoir si mon personnage est de type Guerrier ou Magicien : s'il est de type Magicien, alors je lui augmente son mana...

                              Merci :)



                              Pour te tirer de ton pétrin, il faut utiliser le polymorphisme. Pour faire simple, on va considérer seulement deux classes de personnages: les guerriers et les magiciens. Pour simplifier encore on va dire que le minimum pour définir un personnage est une caractéristique de force, une caractéristique d'intelligence et un niveau. Les guerriers ont une caractéristique supplémentaire, l'endurance, et les magiciens ont une caractéristique supplémentaire, le mana. L'idée est de spécialiser la classe CPersonnage en deux branches distinctes avec un fond commun qui possède le minimum nécéssaire à la définition d'un personnage, plus les caractéristiques qui sont propres à la classe de personnage (ici l'endurance et le mana). On va donc définir une classe CPersonnage qui ne sera pas instantiable (classe abstraite) et deux classes dérivées CMagicien et CGuerrier. La Classe personnage définira un constructeur générique (permettant d'initialiser un personnage de n'importe quelle classe) qui sera spécialisé par les constructeurs des classes dérivées, les guerriers et les magiciens n'ayant pas les mêmes caractéristiques en force et en intelligence, les constructeurs des classes dérivées appelleront le constructeur de personnange avec des valeurs de force et d'intelligence différentes.

                              Pour traiter les actions communes à tous les personnages (obtenir le niveau du personnage par exemple) on utilisera la fonction ad-hoc de la classe de base.

                              Pour spécialiser certaines classes de personnages (obtenir le mana d'un personnage par exemple) on utilisera une fonction virtuelle simple, les classes de personnage qui nécessitent un traitement particulier surchargeront cette fonction, les autres utiliseront la fonction de la classe de base.

                              Pour définir des traitements qui seront toujours spécifiques à chaque classe de personnage (par exemple gagner un niveau), on utilisera une fonction virtuelle pure.

                              Dans le programme on utilisera un pointeur sur un objet personnage, mais lors de la création on créera un objet de la bonne classe. Le polymorphisme du C++ fera en sorte que la fonction qui va bien soit appelée.

                              Voici un petit exemple qui met en oeuvre ce que je viens d'exposer.

                              1. #include<iostream>
                              2. #include<string>
                              3. #include<map>
                              4. using namespace std;
                              5. class CPersonnage
                              6. {
                              7. private:
                              8.     // Constructeur de copie en private pour empecher le compilateur d'en générer un
                              9.     CPersonnage(const CPersonnage & p){};
                              10.     // Operateur d'affectation en private pour empecher le compilateur d'en générer un
                              11.     CPersonnage & operator = (const CPersonnage & p){return * this;}
                              12. protected:
                              13.     int m_nInt;     // l'intelligence du personnage
                              14.     int m_nFor;     // la force du personnage
                              15.     int m_nNiveau;  // le niveau du personnage
                              16. public:
                              17.     // Le constructeur de la classe qui permet de générer un personnage  de niveau 0
                              18.     // avec des valeurs de force et d'intelligence quelconques
                              19.     CPersonnage(int nInt,int nFor):m_nInt(nInt),m_nFor(nFor),m_nNiveau(0){};
                              20.     // Le destrcuteur doit être virtuel pour permettre la destruction
                              21.     // dans les classes dérivées
                              22.     virtual ~CPersonnage(){};
                              23.     // Une fonction virtuelle pure qui devra être implémentée par toutes
                              24.     // les classes dérivée
                              25.     virtual void GagnerNiveau() = 0;
                              26.     // Une fonction virtuelle qui devra être implémentée sur les classes
                              27.     // qui ont de la magie, les autres utiliseront la fonction de base
                              28.     virtual int GetMana() const {return 0;}
                              29.     // les fonction communes à tous les personnages
                              30.     int GetInt() const {return m_nInt;}
                              31.     int GetFor() const {return m_nFor;}
                              32.     int GetNiveau() const {return m_nNiveau;}
                              33. };
                              34. class CMagicien : public CPersonnage
                              35. {
                              36.     int m_nMana;
                              37. public:
                              38.     // JE DECIDE que les magiciens de niveau 0 auront 5 en intelligence,
                              39.     // 2 en force et 10 points de mana
                              40.     CMagicien():CPersonnage(5,2),m_nMana(10){};
                              41.     ~CMagicien(){};
                              42.     // Quand un magicien monte en niveau, son mana  et son intelligence augmentent
                              43.     void GagnerNiveau(){
                              44.         m_nMana += 10;
                              45.         m_nInt++;
                              46.         m_nLevel++;
                              47.         cout << "Magicien " << m_nNiveau << " mana = " << m_nMana
                              48.         << " int " << m_nInt << " for " << m_nFor << endl;
                              49.         }
                              50.     int GetMana() const {return m_nMana;}
                              51. };
                              52. class CGuerrier : public CPersonnage
                              53. {
                              54.     int m_nEndu;
                              55. public:
                              56.     // JE DECIDE que les guerriers de niveau 0 auront 2 en intelligence,
                              57.     // 5 en force et 10 points d'endurance
                              58.     CGuerrier():CPersonnage(2,5),m_nEndu(10){};
                              59.     ~CGuerrier(){};
                              60.     // Quand un guerrier monte en niveau, son endurance et sa force augmentent
                              61.     void GagnerNiveau(){
                              62.         m_nEndu += 10;
                              63.         m_nFor++;
                              64.         m_nLevel++;
                              65.         cout << "Guerrier " << m_nNiveau << " endu = " << m_nEndu
                              66.         << " int " << m_nInt << " for " << m_nFor << endl;
                              67.         }
                              68. };
                              69. int main()
                              70. {
                              71.     map<string,CPersonnage *> ListePerso;
                              72.     CPersonnage * pPersonnage;
                              73.     ListePerso["toto le magicien"] = new CMagicien;
                              74.     ListePerso["billou le guerrier"] = new CGuerrier;
                              75.     ListePerso["toto le magicien"]->GagnerNiveau();
                              76.     ListePerso["billou le guerrier"]->GagnerNiveau();
                              77.     cout << "Mana de toto le magicien " << ListePerso["toto le magicien"]->GetMana() << endl;
                              78.     cout << "Mana de billou le guerrier " << ListePerso["billou le guerrier"]->GetMana() << endl;
                              79.     CGuerrier unGuerrier; // Créer un guerrier sans nom de niveau 0 (un PNJ ?)
                              80.     // CGuerrier copie(unGuerrier);     // <-- Erreur: le constructeur de copie de CPesonnage est privé donc inutilisable
                              81.     // CGuerrier unAutreGuerrier = unGuerrier;// <-- Erreur aussi: l'operateur d'assignation est privé donc inutilisable
                              82.     // CPersonnage unPersonnage;        // <-- Erreur: on ne peut pas instancier une classe abstraite
                              83.     while ( !ListePerso.empty() )
                              84.     {
                              85.         delete ListePerso.begin()->second;
                              86.         ListePerso.erase(ListePerso.begin());
                              87.     }
                              88.     return 0;
                              89. }


                              Edit: pour permettre des personnages multi-classés il faudra affiner le modèle :p
                              • Partager sur Facebook
                              • Partager sur Twitter
                              Mettre à jour le MinGW Gcc sur Code::Blocks. Du code qui n'existe pas ne contient pas de bug
                                19 mars 2008 à 21:46:20

                                Et bien... merci beaucoup d'avoir passé tout ce temps pour m'expliquer cela, c'est parfaitement clair :)

                                Est-ce que le C devant chaque méthode est une convention comme mettre un m_ devant les attributs de classe ?

                                Je vais continuer un peu plus tard ce projet, mais dès que j'ai fini, je vous donnerais le code :)
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  19 mars 2008 à 22:33:04

                                  Oui c'est une convention d'écriture, le fait de préfixer le nom d'une classe d'un C ne lui donne pas de pouvoir spécial ;) , il en va de même des attributs de classe que je préfixe de m_. C'est une vielle habitude pour rappeler à ma mémoire défaillante, que le trucs qui commencent par un C sont des classes, et que les trucs qui commencent par un m_ sont des attributs, que ceux qui commencent par m_n sont des attributs entiers... Par cette astuce, je ne me perds jamais dans mes programmes, et comme mes collègues de travail utilisent la même astuce que moi, on arrive toujours à se retrouver dans les programmes des collègues. Je peux ainsi debugger le programme d'un collègue, et il peut débugger mes programmes, ça évite le mauvais coup de téléphone pendant les vacances ;)
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                  Mettre à jour le MinGW Gcc sur Code::Blocks. Du code qui n'existe pas ne contient pas de bug
                                    20 mars 2008 à 0:05:59

                                    Ok, ben je tacherais d'appliquer cette règle, ça me servira surement dans le futur :)

                                    Encore merci !
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      20 mars 2008 à 0:20:55

                                      <HS>
                                      C'est une convention que j'ai fini par laisser tombé. Aujourd'hui je ne garde qu'une simple capitalisation, et c'est plus par obligation que pour autre chose.

                                      La syntaxe du C++ est telle que l'on a vite fait d'identifier un type sur une ligne -- et si ce n'est pas le cas, c'est que la ligne est trop compliquée.

                                      En revanche, les m_, je garde.
                                      </>
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                      C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.

                                      Créer des variables personnage1, personnage2 ...

                                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                      • Editeur
                                      • Markdown