Partage
  • Partager sur Facebook
  • Partager sur Twitter

Comment instancier un tableau d'objet

SDL et collisions

Sujet résolu
    22 mai 2007 à 11:49:17

    Bonjour à tous !

    J'ai déclaré un tableau d'objets avec la syntaxe suivante :
    Personnage *tabPersonnage = new Personnage[5];


    Je ne sais pas comment ranger mes objets dedans : j'ai tenté la syntaxe la :
    tabPersonnage[1] = Perso("Ressources/Images/PJ/Randi.bmp", couleurNoire, 150, 150, 'b');

    mais sans succès. Comment faut-il faire?

    De plus j'ai découvert qu'il éxistait une bibliothèque permettant de gérer les collections (#include <vector>), peut-être elle utile dans mon cas ?

    Merci d'avance pour les réponses...
    • Partager sur Facebook
    • Partager sur Twitter
      22 mai 2007 à 12:54:59

      Lors de la création du tableau, il faut bien comprendre ce que l'on fait.

      Ceci
      Personnage *tabPersonnage = new Personnage[5];

      Est égale à ceci
      Personnage *tabPersonnage;
      tablPersonne = new Personnage[5];


      Et il faut bien comprendre ces deux étapes que l'on réunit souvent en une seule.
      On crée un pointeur de Personnage.
      Il s'agit donc d'un pointeur, qui peut pointer vers UN objet personnage ou plusieurs (comme dans notre cas).
      Dans les deux cas, on crée l'objet avec NEW.
      Et donc dans les deux cas, il y a une instanciation. Même plusieurs instanciations dans le cas d'un tableau.

      De ce fait, les objets sont déjà TOUS crée.
      Ce que tu essaye de faire est donc dangeureux, car tu va créer un nouvel objet et le rentré dans le tableau alors qu'i y a déjà un objet présent.

      De plus, on travail avec des pointeurs.
      Le code suivant devrait donc compiler et fonctionner "correctement"
      Personnage *tabPersonnage = new Personnage[5];
      tabPersonnage[1] = new Perso("Ressources/Images/PJ/Randi.bmp", couleurNoire, 150, 150, 'b');


      Mais que va t'il se passer ?
      Eh bien l'ancien objet sera toujours présent dans la mémoire, mais il ne sera plus possible d'y accéder, et il ne sera donc PLUS JAMAIS possible de le supprimer. On appelle cela "une fuite mémoire".
      Et si le morceau de programme qui génère une fuite mémoire est appelé plusieurs fois... alors là c'est le drame. La RAM va se charger indéfiniment jusqu'à la surcharge et au plantage (au mieu) du programme.

      Quelle solution apporter alors ?
      Comme dans un aure post, il y a la possibilité de créer une méthode init qui prendra les paramètres du constructeur, et de laisser un constructeur par défaut.

      Personnage *tabPersonnage = new Personnage[5];
      for(int i=0; i<5; i++)
      {
           tabPersonnage[i]->init("Ressources/Images/PJ/Randi.bmp", couleurNoire, 150, 150, 'b');
      }


      Encore une chose, il ne faut pas oublier de vider le tableau quand on en a plus besoin (à la fermeture du programme le plus souvent) avec un [] apres le delete.
      delete [] tabPersonnage


      Autrement oui, il y a la possibilité d'utiliser les vector.
      Ca demande un peu d'apprentissage, mais c'est par la suite beaucoup plus facile à utiliser.
      • Partager sur Facebook
      • Partager sur Twitter
        22 mai 2007 à 13:22:14

        Pour compléter ce que Sebajuste dit à propos des vector, en c++ on évite un maximum d'utiliser des tableaux, et dans la plupart des cas il existe un conteneur qui fonctionnera très bien à la place.
        Donc renseigne toi là dessus, que ce soit un set, une map, une multimap, une list, un vector... il y en a surement un qui remplacera avantageusement le tableau dans ton programme.
        • Partager sur Facebook
        • Partager sur Twitter
          22 mai 2007 à 15:16:41

          Pour être absolument clair!

          Personnage *tabPersonnage = new Personnage[5];


          Lorsque cette ligne est exécuté, après avoir créé un espace dans la pile pour le pointeur et créé 5 espaces contigüe dans le "heap"

          Le constructeur par défaut de chaque objet créé en mémoire sera appelé( Personnage() ) Il n'est pas possible à ma connaissance d'en appeler un autre.
          • Partager sur Facebook
          • Partager sur Twitter
            22 mai 2007 à 22:55:33

            Dans l'absolu, c'est possible, mais pas en utilisant new pour allouer. Plus compliqué qu'autre chose.

            Un simple std::vector<Personnage*>, voire mieux std::vector<boost::shared_ptr<Personnage> >, voire encore mieux un boost::ptr_vector<Personnage> feront parfaitement l'affaire (Je suppose que les personnages sont plus à voir comme des entités que comme de valeurs, d'où les pointeurs)
            • 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.
              23 mai 2007 à 20:16:59

              Merci beaucoup à tous pour vos réponses !
              Je valide le topic :)

              Je vais essayer de faire cela avec la lib de vectors (en fait nous on appelle ça des collections d'objets) et si j'ai besoin d'aide, je remonterai le topic en début de page :D
              • Partager sur Facebook
              • Partager sur Twitter
                24 mai 2007 à 0:19:08

                vector n'est pas une bibliothèque. C'est juste une des diverses classes de la bibliothèque standard : un type abstrait de donnée qui stocke des données de façon contigüe (comme pour un tableau).

                "Collection", ou "conteneur" c'est la même chose.
                • 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.
                  24 mai 2007 à 22:47:05

                  Me revoilou! Bon au final j'ai changé la structure de mon programme, et je n'arrive pas à gérer les vectors!

                  J'essaye de gérer les collisions, pour cela j'ai une fonction dans ma classe de base (la classe de base s'appelle Personnage, elle est abstraite car il n'y aura jamais d'objet de type Personnage, je l'ai juste faite pour rendre plus propre le programme et éviter les doublons). J'ai 2 classes héritées de la classe Personnage : PJ et PNJ (perso joueur et perso non joueur). Il faut donc que je puisse vérifier si il y a collision entre les PJ et les PNJ (à savoir qu'un PJ peut entrer en collision avec un autre PJ ou un PNJ, et ainsi de suite)

                  Pour faire cela, je pense (vous me corrigez si je me trompe :D ) qu'il me faut deux vectors (un de type PJ et l'autre de type PNJ). Pour le moment je ne me soucis pas des PJ, je veux juste faire cela pour les autres, voici mon main :


                  int main(int argc,char** argv)
                  {
                      // déclaration des variables et initialisation... la partie d'avant ne nous intéresse pas!

                      vector<PNJ> vPnj; // je déclare ma collection de Pnj

                      // j'ai pas trouvé d'autre solution que de les construire puis les stocker
                      PNJ Pnj("Ressources/Images/PNJ/pnj1.png", couleurNoire, 400, 300, 'h');
                      PNJ Pnj2("Ressources/Images/PNJ/pnj2.png", couleurNoire, 300, 200, 'g');
                      vPnj.push_back(Pnj);
                      vPnj.push_back(Pnj2); // la ligne la pose deja problèmes, je ne sais pas pourquoi

                      while(!key[ECHAPE]) // tant que c'est différent de la touche echape
                      {
                          UpdateEvents(key); // on met à jour les evenements

                          Pnj.DeplacementPNJ(); // foncion qui gère le PNJ
                          Pnj2.DeplacementPNJ();
                          Pnj.Collage(3,4,ecran); // puis le blit a l'écran
                          Pnj2.Collage(3,4,ecran);

                           // voila on y arrive enfin!
                          for (int i = vPnj.begin (); i != vPnj.end (); i++)
                              if(vPnj[i].collisions(vPnj[i].GetPositionX(), vPnj[i].GetPositionY(), vPnj[i].GetSurface(), 3,4,
                                  vPnj[i+1].GetPositionX(), vPnj[i+1].GetPositionY(), vPnj[i+1].GetSurface(), 3, 4))
                                  MessageBox(0,"ok","ok",0);

                          SDL_Flip(ecran);
                          SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 0, 0, 0));

                          SDL_Delay(110); // met un petit temps de pause pour ralentir l'execution du programme.
                      }

                      vPnj.clear(); // on efface tout le vector

                      SDL_Quit(); // on ferme proprement la SDL
                          return EXIT_SUCCESS;
                  }


                  Je fais donc un parcours des éléments de mon vector, et je regarde si il y a collision (la fonction attends pas mal de paramètres, j'aimerai bien lui passer deux objets mais je ne sais pas comment faire, car l'objet peut-être de type PJ ou PNJ, un Personnage en clair). Bref, on donne les dimmensions de l'image pour pouvoir tester si il y a collision et si c'est le cas, j'aimerai afficher une MessageBox (oui c'est vraiment temporaire, après j'empêcherai le pnj de se déplacer.)
                  Comme ça, ca peut paraitre assez simple, pourtant ça ne marche pas du tout!

                  Voici les erreurs :
                  error: cannot convert `__gnu_cxx::__normal_iterator<PNJ*, std::vector<PNJ, std::allocator<PNJ> > >' to `int' in initialization
                  main.cpp:57: error: no match for 'operator!=' in 'i != (&vPnj)->std::vector<_Tp, _Alloc>::end [with _Tp = PNJ, _Alloc = std::allocator<PNJ>]()'
                  C:/Program Files/CodeBlocks/include/objbase.h:82: note: candidates are: BOOL operator!=(const GUID&, const GUID&)
                  Process terminated with status 1 (0 minutes, 0 seconds)


                  Pourriez vous m'indiquer comment je dois m'y prendre pour faire marcher tout cela? Merci d'avance !


                  (je met aussi le prototype de la fonction pour gérer les collisions, ca sera peut-être un peu plus parlant :)

                  bool collisions(int Xperso1, int Yperso1, SDL_Surface *Perso1, int nb_img_largeur_perso1, int nb_img_hauteur_perso1,
                                  int Xperso2, int Yperso2, SDL_Surface *Perso2, int nb_img_largeur_perso2, int nb_img_hauteur_perso2);


                  (ah oui j'ai pas précisé, j'ai trouvé que le site la qui est sympa pour l'explication des vectors : ici)
                  • Partager sur Facebook
                  • Partager sur Twitter
                    24 mai 2007 à 23:55:42

                    begin() et end() te renvoient des itérateurs qu'il te faudra déréférencer pour accéder à la donnée.
                    Si tu veux travailler avec des indices entiers, boucle de 0 à std::vector<>::size().

                    Pour mélanger PJ et PNJ, attends le tuto sur le polymorphisme (d'inclusion) -- ou prends de l'avance.

                    PS: on ne peut pas deviner quelle est la ligne #57.
                    • 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.
                      25 mai 2007 à 0:05:19

                      for (int i = vPnj.begin (); i != vPnj.end (); i++)
                      Mauvais : la méthode begin et la méthode end d'un vector renvoient un itérateur, pas un int !

                      Ca, c'est bon :
                      for (int i = 0; i < vPnj.size(); ++i)


                      EDIT : Argh, Imghs, tu m'as doublé !
                      • Partager sur Facebook
                      • Partager sur Twitter
                        25 mai 2007 à 0:10:52

                        Citation : Nilat

                        EDIT : Argh, Imghs, tu m'as doublé !


                        Hé Hé :p
                        • 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.
                          25 mai 2007 à 12:56:02

                          La ligne qui posait problème était le "for", je viens de la corriger avec ce que vous avez mis!

                          Je n'ai pas le temps d'attendre sur le tuto, je présente cette activité à l'exam mercredi prochain, ça me laisse peu de temps :D

                          Quand je met la boucle "for" et tout ce qu'elle doit faire en commentaire, le programme compile, s'exécute et se ferme immédiatement. Cela provient de la ligne :

                          vPnj.push_back(Pnj2);

                          Comment ajouter un objet à la collection ? (surtout que ça fonctionne pour le premier!)
                          • Partager sur Facebook
                          • Partager sur Twitter
                            25 mai 2007 à 13:05:36

                            Juste une question au passage, c'est au sujet de la phrase de Hasegawa :

                            Citation : Hasegawa

                            Pour compléter ce que Sebajuste dit à propos des vector, en c++ on évite un maximum d'utiliser des tableaux, et dans la plupart des cas il existe un conteneur qui fonctionnera très bien à la place.



                            Quel est le problème avec le C++ et les tableaux.......?
                            • Partager sur Facebook
                            • Partager sur Twitter
                              25 mai 2007 à 13:16:32

                              C'est juste qu'avec un tableau normal, si tu déborde ça corrompt la mémoire et finit sur des segfault (donc difficile à débuguer), alors qu'avec un vector ça lâche une exception un peu plus claire sur le sujet - enfin, à condition d'utiliser la méthode at() pour accéder, et pas l'opérateur [].
                              Ah, et aussi qu'un vector ça se redimensionne super facilement. Comme plein de bugs de merde peuvent être introduis par un mauvais code de redimensionnement de tableau, c'est vachement plus propre.
                              • Partager sur Facebook
                              • Partager sur Twitter
                                26 mai 2007 à 12:27:40

                                Allez hop je viens poser encore une petite question... Je sais qu'il n'y a plus de rapport avec le titre du topic, mais c'est pour éviter d'emcombrer le forum!

                                J'aimerai tester le type d'un objet en c++ (toujours avec les vectors).
                                J'ai un vector de type Personnage (je rappel que j'ai une classe Personnage, une PNJ et une autre PJ, toutes deux héritées de la classe Personnage), dans lequel je stocke des PJ et des PNJ. Pour l'utilisation de certaines fonction, j'ai besoin de connaitre le type mais je n'ai pas trouvé comment le tester! Comment dois-je m'y prendre?

                                J'avais pensé à un :
                                for (int i = 0; i < vPers.size(); ++i) // différence avec i++ ?
                                     if (vPers[i] == PJ)
                                          Pj.DeplacementPJ(7, key);


                                mais forcément, ça ne fonctionne pas!
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  26 mai 2007 à 13:07:20

                                  Je te renvoie à mes remarques précédentes
                                  -> vecteur de pointeurs sur des personnages
                                  -> polymorphisme (dit d'inclusion)

                                  Tu vas devoir te renseigner sur la deuxième partie, en gros : les cours qui parlent de "virtual".

                                  Tester quel est le type de l'objet pour appliquer une opération ou l'autre est une erreur de design.
                                  Débrouille-toi pour que PJ et PNJ aient les mêmes fonctions appelables depuis l'"extérieur" (monde, sorts, armes, ...). Ces fonctions, déclares-les virtual dans la classe parente. Et puis redéfinis-/supplante-les dans les deux classes filles.

                                  Bref, tu vas avoir des cours à ouvrir.
                                  • 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.

                                  Comment instancier un tableau d'objet

                                  × 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