Des conseils sur mon programme, SVP

Des conseils sur mon programme, SVP - C++ - Programmation

Marsh Posté le 02-06-2004 à 18:08:48    

Alors voilà, je suis en train de coder un "jeu" utilisant OpenGL, mais je me pose pas mal de questions metaphysiques sur ma façon de procéder. Je précise pour commencer que je n'ai jamais eu de cours de C++, donc je prierais par avance Taz d'éviter de se foutre de ma gueule si j'ai fais des trucs pas catholiques, je commence mes premiers vrais cours d'info l'année prochaine. Mais bref, voilà ma question :
 
J'ai créé une librairie pour gérer tout ce qui est affichage OpenGL : le principe est que lorsque mon programme veut créer un objet 3D, il demande à cette librairie un pointeur sur un objet de classe GL_Node. De cette classe sont dérivées tous les types d'objets gérés par mon programme : GL_Face, GL_Object (plusieurs faces), GL_Group (plusieurs objets), GL_Sprite, etc... Pour savoir quel objet ma librairie doit créer, je lui passe un pointeur NULL du type qui va bien (par exemple GL_Face) qui est récupérer par un fonction template qui va créer le bon objet :

Code :
  1. template<class T> T *NewNode(T *type) {
  2.    GL_Node *tmp=new T;
  3.    nodes.add(tmp);
  4.    return tmp;
  5. };


cet objet est à la fois stocké dans l'objet 'nodes' qui contient tous les objets 3D créés, et renvoyé au programme principal (sous forme de pointeur), pour qu'il puisse le modifier. ensuite, dans mon programme principal, j'ai juste à appeler une fonction Draw() et la librairie s'occupe d'afficher tous les objets déjà créés. Le tout simplifie pas mal mon programme principal, puisqu'il n'y a plus rien à gérer au niveau de l'affichage : il suffit de créer un objet, il sera dessiner tout seul au bon moment. Mais le tout est assez complexe, et il m'est arrivé d'avoir des gros soucis dans un programme précédent fonctionnant sur le même principe : le programme portait sur des vaisseaux spatiaux qui contiennent chacun un certain nombre d'équipement, eux même contenant d'autres équipements (exemple : le vaisseau possède une tourelle sur laquelle sont montés des cannons), le tout avec des classes dérivées dans tous les sens, et au moment de détruire un vaisseau, certains objets 3D étaient détruis, mais le programme cherchait encore à les dessiner, d'où problème... bref, ma nouvelle version du programme a l'air de mieux fonctionner pour le moment, mais je sais pas ce que ça va donner quand j'aurais plus avancé... donc si quelqu'un peut me dire si ma méthode semble bien, ou pas, et s'il y a mieux ou plus simple... merci d'avance (et merci déjà d'avoir tout lu  :p ) et désolé si j'ai pas été clair  :whistle:

Reply

Marsh Posté le 02-06-2004 à 18:08:48   

Reply

Marsh Posté le 02-06-2004 à 18:36:10    

ben il faut que mon programme récupère le pointeur sur l'objet créé, pour pouvoir le modifier. bon, je met un bout de code (inventé pour l'occasion) qui aurait pu être dans mon programme principal :

Code :
  1. GL_Object *obj=NewNode((GL_Object *)NULL); //créer un objet de type GL_Object
  2. // modification de l'objet (ajout de faces, translations, rotations, etc...
  3. Draw(); //affiche l'objet qui a été créé, à partir de sa référence dans 'nodes'


 
donc ta fonction, dans laquelle tu n'as fais que retirer le renvois de l'adresse de l'objet créé, ne convient pas dans mon cas...


Message édité par yawen le 02-06-2004 à 18:37:18
Reply

Marsh Posté le 02-06-2004 à 18:41:21    

ah non, désolé, je viens de voir ce que tu voulais dire... effectivement, ça pourrais marcher, mais ce serais plutot
 

Code :
  1. template<typename T>
  2.   void NewNode( T*& node ) { 
  3.        node = new T;
  4.      nodes.add( node ); };


il faut que ce soit une référence sur un pointeur, pour que la valeur du pointeur soit réellement modifiée... mais sinon, c pas con... mais dans le fond, ça change pas grand chose... moi je demandais surtout si le principe était correct, pas forcément dans les détails...

Reply

Marsh Posté le 02-06-2004 à 18:45:12    

Exact, je suis allé un peu vite ;) Comment gères tu le retrait des objets dans ta liste nodes ?


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 02-06-2004 à 18:46:04    

éh, c quoi ça, tu as retiré ton message ? (si c'est possible ?)

Reply

Marsh Posté le 02-06-2004 à 18:55:09    

alors je donne la classe à partir de laquelle je fais mon objet 'nodes' :

Code :
  1. template <class T> class ContainerP { //objects handled by class HandleC must be destroyed before this is destroyed (in order to ensure that no one has an invalid reference)
  2. public:
  3. template <class T1> int NewH(T1 *t);
  4. void DeleteH(int i);
  5. int Enlarge();
  6. T** node;
  7. int size;
  8. bool *h;
  9. public:
  10. void Delete(int i);
  11. int GetFreeNode();
  12. template <class T1> T1* New(T1 *t);
  13. T* operator[](int i);
  14. void Init(int n);
  15. void InitAndConstruct(int n);
  16. void CleanUp();
  17. int GetIndex(T *t);
  18. int Rsize;
  19. int nNodes;
  20. void operator=(ContainerP<T> &c) {assert(NULL);};
  21. ContainerP() {node=NULL;nNodes=0;size=0;Rsize=MAIN_DefaultRsize;h=NULL;};
  22. ContainerP(ContainerP<T> &c) {assert(NULL);};
  23. ~ContainerP() {CleanUp();};
  24. };


 
je met pas les définitions de toutes les fonctions, c'est un peu long... le principe de cette classe, c'est qu'elle stocke les objets par un tableau de pointeurs sur les objets. Le tableau est redimensionné si besoin (i.e. un nouveau tableau est créé et l'ancien est copié dedans, puis effacé). C'est pour ça que je stocke tout dedans avec des pointeurs : même si je déplace les poiteurs, l'objet lui même n'est pas déplacé. de plus ça permet de stocké des objets de types différents, mais dérivés d'une même classe de base. enfin, l'histoire du HandleC, c'est une autre classe :
 

Code :
  1. template <class T,class T1> class HandleC {
  2. ContainerP<T1> *owner;
  3. T *p;
  4. int index;
  5. public:
  6. void Delete() {if(!p) return;assert(owner);assert(index>=0);owner->DeleteH(index);p=NULL;index=-1;owner=NULL;};
  7. void New(ContainerP<T1> *_owner) {Delete();assert(_owner);owner=_owner;index=owner->NewH((T*)NULL);assert(index>=0);p=(T*)owner->node[index];assert(p);};
  8. operator T*() {return p;};
  9. T* operator->() {assert(p);return p;};
  10. HandleC() {p=NULL;index=-1;owner=NULL;};
  11. ~HandleC() {Delete();};
  12. };


 
cette classe permet de faire des trucs comme ça :
 

Code :
  1. class bidon {
  2. public:
  3. HandleC<GL_Node,GL_Object> obj;
  4. //contructeurs et destructeurs...
  5. };
  6. bidon bidon1;
  7. bidon1.obj.New(&nodes);


 
ensuite, quand l'objet bidon1 sera détruit, ça va appeler le destructeur de l'objet 'HandleC obj' qu'il contient, et donc libérer la mémoire comme il faut, et mettre à jour le tableau de 'nodes'...


Message édité par yawen le 02-06-2004 à 18:55:58
Reply

Marsh Posté le 02-06-2004 à 19:03:59    

Est ce que l'utilisation d'une liste (std::liste<GL_Node*> ) ne permetrait pas deja de simplifier un peu ta classe container. D'ailleurs, si elle n'a qu'une seule instance, tu pourrais en faire un singleton pour le style.


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 02-06-2004 à 19:04:32    

pour répondre à ta question, les retraits sont fais de la manière suivante : l'objet considéré est détruit (avec delete), et le pointeur vers cet objet dans le tableau est remis à NULL. quand on ajoute un objet, le programme cherche le premier pointeur NULL dans le tableau, il créé l'objet (new) et met l'adresse dans le tableau. si tout les pointeurs sont déjà utilisés, le tableau est agrandit.

Reply

Marsh Posté le 02-06-2004 à 19:06:29    

euh elle n'a pas du tout qu'une seule instance, et le principe de cette classe c'est que quand je détruit un objet dedans, elle ne décale pas tous les autres, histoire de garder le maximum de performances. sinon, je sais pas ce que c'est un singleton... pour info, cette classe est aussi utilisée pour stocker les objets physiques du jeu (description solide de l'objet, pour gérer les collisions), et les effets graphiques (en gros, tout ce qui marche avec des effets de transparence)

Reply

Marsh Posté le 02-06-2004 à 19:07:07    

Lorsqu'un objet complexe crée à lui seul N objets dans ta liste, comment ca se passe lorsque ton objet complexe doit etre detruit ( comment sont retirés les N objets de la liste constituant ton objet complexe ) ? Gardes tu une trace de ces N objets dans la classe correspondant à ton objet complexe ?


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 02-06-2004 à 19:07:07   

Reply

Marsh Posté le 02-06-2004 à 19:08:33    

mais en fait, je ne sais pas comment marche std::liste<>. je connaissait std::vector<> mais ça ne corespond pas à ce que je veux, puisque quand on détruit un élément, il décale tous les autres... par exemple, s'il s'agit de la liste de tous les projectiles lancés par tous les vaisseaux, vu que ça bouge pas mal (les projectiles sont créés et détruits très vite), ça fais tout ramer...

Reply

Marsh Posté le 02-06-2004 à 19:11:27    

pfff, c galère, on se répond avec un message de retard.. hum, bref... alors pour répondre à

xterminhate a écrit :

Lorsqu'un objet complexe crée à lui seul N objets dans ta liste, comment ca se passe lorsque ton objet complexe doit etre detruit ( comment sont retirés les N objets de la liste constituant ton objet complexe ) ? Gardes tu une trace de ces N objets dans la classe correspondant à ton objet complexe ?


 
je dirais que si j'utilise la fameuse classe HandleC dans l'objet complexe, c'est le destructeur de cette classe qui se charge de demander à la classe ContainerP corespondante de détruire l'objet, et qui règle sa propre référence à NULL, histoire d'être bien sûr de pas accéder à l'objet qui vient d'être détruit. Mais ça, je ne l'ai ajouté que dans la dernière version de mon programme, justement pour règler le problème des plantages d'avant... mais je me demande quand même si y'a pas plus simple que tout ça...

Reply

Marsh Posté le 02-06-2004 à 19:14:01    

En somme, tu as autant de listes d'objets que d'objets complexes dans le jeu ?


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 02-06-2004 à 19:14:21    

ah oui, et j'ai une autre question : je voudrais mettre en private certains éléments de la classe ContainerP, mais que la classe HandleC puisse quand même (et seulement cette classe) accéder aux éléments privés de la classe ContainerP. C'est possible ?

Reply

Marsh Posté le 02-06-2004 à 19:14:52    

Du devrais faire un petit effort pour exploiter std::liste. Cela pourra sans doute te servir pour d'autres applications.


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 02-06-2004 à 19:15:37    

non non, je n'ai pas autant de listes d'objets que d'objets complexes dans le jeu ! tout est centralisé dans une seule liste (sinon ça n'a aucun intérêt).

Reply

Marsh Posté le 02-06-2004 à 19:16:04    

je peux trouver où de la doc sur std::liste ?

Reply

Marsh Posté le 02-06-2004 à 19:16:42    

Est ce que des classes héritent de HandleC ? si oui de quelle anière (public/private) ?


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 02-06-2004 à 19:17:22    

http://www.sgi.com/tech/stl/List.html


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 02-06-2004 à 19:19:52    

non, aucune classe n'hérite de HandleC. bon, je met un exemple, ce sera peut-être plus clair :

Code :
  1. class Vaisseau {
  2. public:
  3. HandleC <GL_Node,GL_Object> fuselage;
  4. HandleC <GL_Node,GL_Group> reacteurs;
  5. void Init();
  6. //contructeurs/destructeurs
  7. };
  8. void Vaisseau::Init() {
  9. fuselage.New(&nodes);
  10. reacteurs.New(&nodes);
  11. //charge un fichier et remplis les objets pointés par fuselage et reacteurs
  12. }


Message édité par yawen le 02-06-2004 à 19:20:34
Reply

Marsh Posté le 02-06-2004 à 19:23:18    

Declares protected: les membres dont tu veux restreindres l'accès à HandleC uniquement. (A vérifier, depuis que je code en asm et en C, je commence à oublier le C++, lol).


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 02-06-2004 à 19:24:42    

ok, merci pour le lien,  je verrais ça si je dois faire un truc du genre dans le futur, mais là je me vois mal refaire tout mon code pour utiliser std::list

Reply

Marsh Posté le 02-06-2004 à 19:26:37    

euh ouais, mais je les déclare comment protected ? faut bien que je mettre quelque part que c'est par rapport à HandleC que je veux restreindre l'accès (enfin laisser l'accès, plutot). C'est quoi la syntaxe ? (je suis un peu perdu depuis que MSDN ne veut plus marcher sur mon pc... oui, bon, je sais, utiliser VC++ c nul, mais bon, c le premier compilateur que j'ai eu entre les mains...)

Reply

Marsh Posté le 02-06-2004 à 19:27:12    

Programmes dans le but d'apprendre un maximum de chose (les listes par exemple ;)). D'ailleurs, j'ai rarement vu des projes perso se terminer !


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 02-06-2004 à 19:29:43    

A ma connaissance tu ne peux pas restreindre à un classe dérivée en particulier.

Code :
  1. class toto {
  2. public:
  3. // ici, tout le monde accède
  4. protected:
  5. // ici, les classes dérivées et les amies accèdent
  6. private:
  7. // ici, les amies accèdent
  8. }


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 02-06-2004 à 19:30:10    

En fait, mon problème (qui n'en est pas forcément un), c'est que je ne sais pas si c'est une bonne idée de vouloir tout centraliser dans un même tableau, et de surcroit d'utiliser des objets de type différents dans le même tableau... est ce que par exemple je ferais pas mieux de mettre directement  
GL_Object fuselage;  
et  
GL_Group reacteurs;  
dans ma classe vaisseau ? parce que ça compliquerais la classe vaisseau (il faudrait ajouter une fonction Draw qui appellerais les fonctions Draw de GL_Object et GL_Group) mais d'un autres coté ça simplifierais pas mal la gestion de la mémoire... dilemme... et niveau performances, je sais pas ce qui est le mieux (m'est avis que ça dois pas changer grand chose)

Reply

Marsh Posté le 02-06-2004 à 19:31:10    

ben le problème c'est que HandleC n'a aucun lien avec ContainerP, enfin aucune n'est dérivée de l'autre... c'est quoi, les classes amies ?

Reply

Marsh Posté le 02-06-2004 à 19:32:28    

Ce que tu as fais est correct. Tous tes objets dérives d'une classe (plus ou moins) abstraite n'est ce pas ?


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 02-06-2004 à 19:33:16    

Ah pardon, je croyais que HandleC dérivait de ContainerP... ca se complique un peu la ;)


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 02-06-2004 à 19:33:22    

oui, c'est exactement ça, pour le coup de la dérivation de la classe plus ou moins abstraite


Message édité par yawen le 02-06-2004 à 19:34:05
Reply

Marsh Posté le 02-06-2004 à 19:35:21    

en fait le seul lien que HandleC a avec ContainerP, c'est le pointeur ContainerP<T1> *owner; qui permet de savoir dans quel tableau est stocké l'objet

Reply

Marsh Posté le 02-06-2004 à 19:37:06    

et je voudrais justement que par l'intermédiaire de ce pointeur, il puisse demander au tableau de supprimer l'objet (quand on détruit l'instance de HandleC), mais par le biais d'une fonction spéciale (DeleteH) qu'il est le seul à pouvoir employer

Reply

Marsh Posté le 02-06-2004 à 19:42:44    

Tu as essayé de faire un diagramme de l'architecture de ton programme (classes, héritages, ...etc ?).
 
Ps: J'ai du mal a reflechir quand j'ai faim, désolé :)


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 02-06-2004 à 19:42:47    

le truc, c que dans le tableau, les objets peuvent être créés de deux moyens : par un objet HandleC, ou alors directement. et quand je détruit le tableau, je voudrais m'assurer que tous les objets créer par le biais de HandleC ont déjà été détruits (pour être sûr qu'il n'y a pas de soucis de mémoire). de plus, il ne faut pas qu'on puisse directement détruire un objet qui a été créé par le biais de HandleC, car sinon, HandleC aurait une référence sur un objet détruit... bref, mon problème est que plusieurs objets ont des pointeurs sur un même objet, et qu'il faut qu'ils soient tous synchronisés : il ne faut surtout pas que l'un d'eux pointent sur un objet détruit...

Reply

Marsh Posté le 02-06-2004 à 19:44:34    

mdr, euh ben de toute façon, moi aussi j'ai faim, et de plus ma copine (qui a finis ses partiels aujourd'hui) organise un apéro avec des potes (je viens de m'en souvenir, ou plutot elle viens de m'en souvenir en m'appelant), donc faut que j'y aille... j'ai jamais essayé de faire un diagramme, mais même si j'en fais un, j'aurais du mal à l'envoyer sur internet, nan ? bon, ben je reviens pas avant demain, alors...

Reply

Marsh Posté le 02-06-2004 à 19:45:30    

Pourquoi tu voudrais detruire ce tableau... ++


Message édité par xterminhate le 02-06-2004 à 19:46:03

---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 02-06-2004 à 19:46:13    

ben quand on quitte le programme... juste histoire de vérifier qu'il n'y a eu aucun soucis tout au long de l'éxécution...

Reply

Marsh Posté le 02-06-2004 à 19:46:37    

et bien on revient sur l'idée du singleton...


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 03-06-2004 à 09:32:31    

ouais, sauf que je ne sais toujours pas ce que c'est qu'un singleton...

Reply

Marsh Posté le 03-06-2004 à 09:51:57    

un singleton est un objet à instance unique.
Son principe repose sur le controle du nbre d'instance de la classe
en rendant private les constructeurs de la classe.
Un exemple simple :
 

Code :
  1. class Singleton
  2. {
  3.   public :
  4.    static Singleton*  GetInstance()
  5.    {
  6.        if( !Instance ) Instance = new Singleton;
  7.        return Instance;
  8.    }
  9.    static Singleton*  ReleaseInstance()
  10.    {
  11.        if( Instance ) delete Instance;
  12.    }
  13.    // D'autres méthodes non statiques
  14.    void f();
  15.    void g();
  16.    private :
  17.   Singleton() {}
  18.   Singleton( const Singleton& ) {}
  19.   ~Singleton() {}
  20.   static Singleton* Instance
  21. };
  22. Singleton* Singleton::Instance = NULL;


 
 
L'accés se fait ensuite via :
 

Code :
  1. #include "singleton.h"
  2. void toto()
  3. {
  4.      Singleton* sg = Singleton::getInstance();
  5.      sg->g();
  6. }
  7. int main( int,char**)
  8. {
  9.      Singleton* sg = Singleton::getInstance();
  10.      sg->f();
  11.     toto();
  12.  
  13.     return 0;
  14. )


Message édité par Joel F le 03-06-2004 à 10:29:45
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed