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

Projets Discussion :

Remake Zelda sur GBC


Sujet :

Projets

  1. #201
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 919
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 919
    Points : 220 492
    Points
    220 492
    Billets dans le blog
    127
    Par défaut
    Review du code:

    main.cpp:
    Les new ne sont pas protéges ( if ( ptr == NULL ) goFail(); )
    Mais il est possible que vous comptiez sur l'exception (std::bad_alloc) ...
    D'ailleurs je me demande comment que l'on gère correctement le cas :p

    Logger.h:
    Le logger est en Singleton ... bon, c'est de ma faute je crois

    Link.h
    J'aime pas beaucoup le code dans les .h (et même lorsque c'est un template ). Faites donc un .cpp

    Ce genre d'include #include "../core/input/inputManager.h" n'est pas très sain, car si on déplace un fichier, on casse tout les autres. Bon, ok, je le faisais avant, un prof me l'a fait remarqué, et depuis j'ai arrêté.
    La solution:
    Rajoutez un dossier de recherche pour les includes au compilateur (option -I de gcc/g++), et d'enlever les chemins relatifs en partant toujours de la base des fichiers sources (soit 'src' dans votre projet) (Donc c'est le dossier 'src' qui sera rajouter dans les répertoires d'include du compilo ).

    AL_Keyboard.cpp:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    if (key[KEY_L])
     
        {
     
            buttonPressed |= InputManager::INPUT_SELECT;
     
        }
    La définition de la touche est trop statique (Ok, je n'ai pas de solution appliqué pour cela).
    Il faut une classe intermédiaire, avec un dictionnaire (std::map) pour lier les touches réelles aux actions. Un truc du genre .

    (Note: Il manquerai pas un peu de commentaires ?)

    AL_GameEngine.cpp:
    Les fonctions tick1 / tick2 ne sont pas assez explicites

    Game.h:
    Est ce que le jeu doit avoir un pointeur sur le héros ... je doute légèrement.
    En fait, à un certain moment, je pensais que si on avait un jeu à personnage, les personnages devaient tous hérités d'une même classe et d'être contenu dans une liste dans le Game.h par exemple. Ainsi, on pouvait parcourir la liste pour faire tout les draws et updates nécessaire.
    Le problème qui arrive dans ce cas, c'est que l'on ne peut pas toujours récupéré facilement un élément de cette liste (genre le héros, pour connaitre s'il a la bonne arme, ou je ne sais quoi).
    J'ai aussi vu une architecture légèrement plus avancé avec une std::map ou le héro avait une clé unique, ce qui faisait qu'il était facilement récupérable si besoin...

    Il n'y a pas une solution unique, bien sur

    Game.cpp:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    BITMAP* c = create_bitmap(32,32);
     
        clear_to_color(c, makecol(255,0,0)); // couleur rouge
     
        AL_Sprite* s = new AL_Sprite(c, pos, size);
     
     
     
        l = new Link(s);
    Je me demande pourquoi Link n'est pas capable de connaitre son sprite lui même ... Mais si vous le faites, d'un autre coté, vous allez franchir le cap de la responsabilité unique, et si vous voulez le respecter, il faudra alors faire un LinkLoader

    Voilà à peu près (le reste, il vient un peu de moi )

  2. #202
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 617
    Points
    15 617
    Par défaut
    Les new ne sont pas protéges ( if ( ptr == NULL ) goFail(); )
    Mais il est possible que vous comptiez sur l'exception (std::bad_alloc) ...
    D'ailleurs je me demande comment que l'on gère correctement le cas :p
    Il faut catcher l'exception
    http://www.cplusplus.com/reference/std/new/bad_alloc/
    Par contre, sauf erreur de ma part, en cas d'erreur d'allocation, ptr ne sera pas forcement null Je crois que la valeur est indéterminée en cas de bad_alloc (je m'avance peut être un peu sur ce coup là mais il me semble que la norme ne garantie pas la valeur de ptr). Il faut explicitement mettre ptr à null dans le catch.

    Mais il faut quand même protéger les pointeurs avec le code donné par LittleWhite puisqu'un pointeur peut être null (si cela n'a pas de sens qu'un pointeur soit null, alors c'est une référence).

    Ou encore mieux, utiliser des pointeurs intelligent (boost::scoped_ptr, boost::shared_ptr, boost::scoped_array, boost::shared_array, boost::make_shared).

    Le logger est en Singleton ... bon, c'est de ma faute je crois
    Pour une fois, non (si c'est bien une classe permettant de faire des log)
    Un logger doit effectivement être unique et accessible partout dans le code. Donc c'est bien un singleton et ce n'est pas un faille de conception (il faut bien que ce design pattern ait une réelle utilité parfois )

    Pourtant, cela me chagrine que pour chaque comportement, il faille faire une nouvelle classe.
    Dans OpenAWars, j'ai utilisé un système de flags ... j'avouerai que c'est largement moins beau. La gestion est géré dans une fonction, qui analyse les flags pour donner le comportement voulu. Ainsi, il est facile de créer de nouvelle unité avec des comportements qui pourrait être le mixe entre plusieurs comportements.
    Le problème est que dans ce cas, tu te retrouves avec une fonction "dispatcher" qui traite tous avec des séries de if/switch monstrueux. C'est moins claire à la lecture qu'un belle arborescence de classes de types :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    + strategies
       + moving
          + walking
          + flying
          + swimming
       + interacting
          + catching
          + hitting
          + pushing
    etc.
    Un autre problème est la difficulté de la modification : dans le cas d'une fonction de dispatch, il faut trouver la ligne de code correspondant à ce que l'on souhaite, ce qui peut être compliqué. Avec des stratégies, il suffit d'ajouter une nouvelle classe dérivée et redéfinir les fonctions.

    Le dernier point est que ce n'est pas très dynamique : si on veut ajouter un comportement, on doit modifier fortement le code existant. Et pas possible d'avoir une structure modulaire avec plugin/lis dynamiques.
    Ce point peut être amélioré en utilisant un design pattern chaîne de responsabilités par exemple. Couplé avec les pattern stratégie et fabrique, on peut avoir du code très joli.

    En fait, ces problèmes viennent du fait que cette fonction de dispatch ne respecte pas le principe open-close (cf blog d'Emmanuel Deloget)

  3. #203
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 617
    Points
    15 617
    Par défaut
    Citation Envoyé par gbdivers Voir le message
    Voila pour les bases mais on peut compliquer encore plus...
    Juste pour lancer la réflexion, une remarque sur la limite du code que j'ai donné

    Ce code permet d'avoir un comportement déterminé dynamiquement. C'est très bien et mieux structuré.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class WalkMoveStrategy : public MoveStrategy
    {
       virtual bool isValidMoving(Position from, Position to) //vérifie si un mouvement est valide
       {
          foreach_position(from, to)
             if (sol[position] == "eau") return false; // on marche pas sur l'eau
       }
     
       virtual void move(Position from, Position to) {} // effectue le déplacement
    };
    Par contre, cela implique plusieurs chose :
    - les MoveStrategy doivent connaître la classe Sol (qui gère la map correspondant à l'environnement sur lequel se déplace le personnage). Ce couplage (fort) est-il indispensable ?
    - les types de sol pris en charge sont statique : on se retrouve avec des séries de if/switch et il est nécessaire de modifier le code existant pour ajouter un nouveau type de sol. Est-il possible de gérer dynamiquement la liste des types de sols ?
    - avec une structure en if/switch pour les sols et les mouvements, seules les cas connus sont traités. C'est à dire qu'il faut que chaque mouvement prenne en charge chaque type de sol. Si on ajoute un nouveau type de mouvement par exemple, il faut lui faire traiter tous les types de sols. Est-il possible d'éviter à devoir définir tous les couples de valeurs (sol, mouvement) ? ce qui peut devenir très lourd si on beaucoup de sols et mouvement.


    Question à 1000 points : pourquoi s'embêter avec tous ça ?
    Début de réponse : la plus grosse partie de conception de jeu n'est pas (et ne doit pas être ) le codage mais le game design et le graphisme.
    Si les types pris en charge sont statique, cela veut dire que si un des game desginers vous dit qu'il veut ajouter une nouvelle map (un monde sous-marin par exemple) qui n'était pas pris en charge avant, il faut modifier le code existant, ce qui peut être problématique (perte de temps, dispersion des ressources de dev ou refus des demandes des game designers)
    Si les types sont dynamiques, il suffit aux designers d'ajouter dans leurs scripts les nouveaux types de sols et de comportement et le tour est joué. On gagne en temps de développement et en réactivité.

    Bon courage pour la suite (je ferais probablement un jour une review du code )

  4. #204
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 919
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 919
    Points : 220 492
    Points
    220 492
    Billets dans le blog
    127
    Par défaut
    Citation Envoyé par gbdivers Voir le message
    Il faut catcher l'exception
    http://www.cplusplus.com/reference/std/new/bad_alloc/
    Par contre, sauf erreur de ma part, en cas d'erreur d'allocation, ptr ne sera pas forcement null Je crois que la valeur est indéterminée en cas de bad_alloc (je m'avance peut être un peu sur ce coup là mais il me semble que la norme ne garantie pas la valeur de ptr). Il faut explicitement mettre ptr à null dans le catch.
    Dans Visual Studio 2008, ce comportement est paramétrable (j'avais vu ça, lorsque je glandouillais sur OpenAWars). On peut choisir d'avoir, soit l'exception, soit le pointeur à NULL.
    Moi, venant d'un monde C, je dirais qu'il faut vérifier si ce n'est pas à NULL

    Pour une fois, non (si c'est bien une classe permettant de faire des log)
    Un logger doit effectivement être unique et accessible partout dans le code. Donc c'est bien un singleton et ce n'est pas un faille de conception (il faut bien que ce design pattern ait une réelle utilité parfois )
    Cela dépend vraiment de ce que l'on veut. Le dernier Logger que j'ai crée (pour le défi Qt) on peut avoir plusieurs instances, pour logger dans plusieurs fichiers, ou même faire un peu plus.

  5. #205
    Expert confirmé
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Points : 4 388
    Points
    4 388
    Par défaut
    Citation Envoyé par gbdivers Voir le message
    Conceptuellement, c'est la même chose => même classe
    Ce sont des maps, qui contiennent des objets. La seule différence sont les objets qui sont dans les maps extérieures et intérieures mais aucune raison de créer 2 classes différentes.
    D'accord
    Mais si je veux gérer l'ouverture des portes à clés dans un donjon comment je fais ? Cette gestion n'existe pas dans les zones extérieures...
    Donc pour moi, il me faudrait quand même une classe par type de monde qui encapsulerait la zone courante (ou alors toutes les zones je ne sais pas ce qui est mieux) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    Class IWorld
    {
    protected:
          /* std::vector<Area*> areas; // la liste de toutes les zones */
          Area* currentArea; // la ozne courante (ou l'on se trouve)
          int x,y; // coordonnées de la zone ou l'on se trouve
    public: 
          virtual int update() = 0; // gestion du monde
          virtual void draw() = 0; // affichage
    }
     
    Class Dungeon : public IWorld
    {
    }
     
    Class OverWorld : public IWorld
    {
    }
    Ca se trouve je suis complètement à côté de la plaque

    Citation Envoyé par gbdivers Voir le message
    Ce que tu veux faire, c'est une classe (par exemple "Personnage") dont une partie du comportement (le déplacement par exemple) est définit en dehors de la classe.
    Oui c'est ca Et je compte le gérer dynamiquement donc vu que je vais tenter d'implémenter un pattern stratégie pour la gestion des personnages.
    Citation Envoyé par gbdivers Voir le message
    Par contre, cela implique plusieurs chose :
    - les MoveStrategy doivent connaître la classe Sol (qui gère la map correspondant à l'environnement sur lequel se déplace le personnage). Ce couplage (fort) est-il indispensable ?
    - les types de sol pris en charge sont statique : on se retrouve avec des séries de if/switch et il est nécessaire de modifier le code existant pour ajouter un nouveau type de sol. Est-il possible de gérer dynamiquement la liste des types de sols ?
    - avec une structure en if/switch pour les sols et les mouvements, seules les cas connus sont traités. C'est à dire qu'il faut que chaque mouvement prenne en charge chaque type de sol. Si on ajoute un nouveau type de mouvement par exemple, il faut lui faire traiter tous les types de sols. Est-il possible d'éviter à devoir définir tous les couples de valeurs (sol, mouvement) ? ce qui peut devenir très lourd si on beaucoup de sols et mouvement.
    Si on créé un fichier avec comme structure un id correspondant au type de sol et un id correspondant au déplacement associé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    TYPE_EAU FlyMoveStrategie
    TYPE_MUR NoMoveStrategy
    TYPE_SOL WalkMoveStrategy FlyMoveStrategie
    Ensuite on couple ca à une fabrique d'objets de type MoveStrategie ? (je dis ca mais je ne sais pas si c'est possible )

    Par contre, sur le sol, on peut à la fois voler et marcher dessus, comment implémenter ca avec les stratégies ?
    Citation Envoyé par gbdivers Voir le message
    Bon courage pour la suite (je ferais probablement un jour une review du code )
    J'attends avec impatience
    Attends la prochaine version, j'aurais corrigé les remarques de LittleWHite

    Sinon pour LittleWhite, je n'avais pas encore blindé le code c'est pour ca que je n'ai pas mis des assert() et des if (ptr == NULL) mais je vais le faire
    Je ne suis pas trop try/catch, je préfère les bonnes vielles vérifications comme en C ^^

    Pour te pointeur sur Hero, oui tu as raison c'est une référence qu'il faut plutôt. Et si j'ai tout codé dans le .h c'est parce que j'avais la flème de faire un .cpp


    Citation Envoyé par littleWhite
    Ce genre d'include #include "../core/input/inputManager.h" n'est pas très sain, car si on déplace un fichier, on casse tout les autres. Bon, ok, je le faisais avant, un prof me l'a fait remarqué, et depuis j'ai arrêté.
    La solution:
    Rajoutez un dossier de recherche pour les includes au compilateur (option -I de gcc/g++), et d'enlever les chemins relatifs en partant toujours de la base des fichiers sources (soit 'src' dans votre projet) (Donc c'est le dossier 'src' qui sera rajouter dans les répertoires d'include du compilo ).
    Donc si je comprends bien, je rajoute la directive : -I "./src" et je remplace #include "../core/input/inputManager.h" en #include "./core/input/inputManager.h" ?

    Question débile : Pour moi un pointeur et une référence c'est pareil, j'ai du mal à saisir la différence même si j'ai compris qu'une référence ne peut pas être NULL alors qu'un pointeur si, fondamentalement, je ne sais quand je dois utiliser un pointeur et quand je dois utiliser une référence (je sais qu'il y a une entrée dans la FAQ mais ca ne m'a pas aidé.). De même, je pense que la référence est plus performante dans le passage de paramètre que le pointeur... Voilà ^^

    Merci à vous

  6. #206
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 919
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 919
    Points : 220 492
    Points
    220 492
    Billets dans le blog
    127
    Par défaut
    Citation Envoyé par Aspic Voir le message
    Donc si je comprends bien, je rajoute la directive : -I "./src" et je remplace #include "../core/input/inputManager.h" en #include "./core/input/inputManager.h" ?

    Merci à vous
    Oui mais plus:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #include "core/input/inputManager.h"
    Ne nous encombrons pas avec les './'

    Et c'est que j'ai l'habitude de blinder le code à l'écriture

    EDIT:
    Pour la stratégie Voler / Marcher avec le type du sol. En fait, seule la stratégie Marcher regarde qu'elle est le type du sol, pour faire ce qui doit être fait (interdire le mouvement si eau).
    La stratégie de vol, ne regardera même pas le sol à cause du vertige (donc retourne toujours true pour indiquer la possibilité du mouvement)

  7. #207
    Membre habitué
    Inscrit en
    Avril 2011
    Messages
    59
    Détails du profil
    Informations forums :
    Inscription : Avril 2011
    Messages : 59
    Points : 154
    Points
    154
    Par défaut
    Citation Envoyé par Aspic Voir le message
    D'accord
    Mais si je veux gérer l'ouverture des portes à clés dans un donjon comment je fais ? Cette gestion n'existe pas dans les zones extérieures...
    Donc pour moi, il me faudrait quand même une classe par type de monde qui encapsulerait la zone courante (ou alors toutes les zones je ne sais pas ce qui est mieux) :
    Je ne vois pas trop en quoi la gestion des clefs te gène. Au pire en extérieur c'est un mécanisme de gameplay dont tu ne te servira pas.
    Extérieur ou dongeon c'est kifkif niveau gestion, il y a juste le tileset qui change, non?

  8. #208
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 617
    Points
    15 617
    Par défaut
    Citation Envoyé par Aspic
    D'accord
    Mais si je veux gérer l'ouverture des portes à clés dans un donjon comment je fais ? Cette gestion n'existe pas dans les zones extérieures...
    Donc pour moi, il me faudrait quand même une classe par type de monde qui encapsulerait la zone courante (ou alors toutes les zones je ne sais pas ce qui est mieux)
    Citation Envoyé par Anything
    Je ne vois pas trop en quoi la gestion des clefs te gène. Au pire en extérieur c'est un mécanisme de gameplay dont tu ne te servira pas.
    Extérieur ou dongeon c'est kifkif niveau gestion, il y a juste le tileset qui change, non?
    +1

    Qu'est ce qui distingue que l'on est dans un donjon, dans une maison ou dehors ? C'est uniquement les images qui sont affichées. Du point de vue du code, il n'y a pas de différence. C'est le game design qui fait la différence.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    Class IWorld
    {
    protected:
          /* std::vector<Area*> areas; // la liste de toutes les zones */
          Area* currentArea; // la ozne courante (ou l'on se trouve)
          int x,y; // coordonnées de la zone ou l'on se trouve
    public: 
          virtual int update() = 0; // gestion du monde
          virtual void draw() = 0; // affichage
    }
     
    Class Dungeon : public IWorld
    {
    }
     
    Class OverWorld : public IWorld
    {
    }
    Donc non
    Que veux tu mettre dans les classes Dungeon et OverWorld ? Sachant que tout ce qui sera spécifique de Dungeon et OverWorld devra être testé dans les classes utilisatrices.
    Je m'explique. Imagine que tu as ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Dungeon : public IWorld
    {
       bool uneFonction();
    }
     
    class OverWorld : public IWorld
    {
       int uneAutreFonction();
    }
    Et une classe donc le comportement dépende du type de monde. Cela veut dire que dans le code, il faut tester le type de monde :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class Personnage
    {
       void f(IWorld* w)
       {
          Dungeon* d = dynamic_cast<Dungeon*>(w);
          if (d) { /* on est dans un donjon */ }
          OverWorld * ow = dynamic_cast<OverWorld *>(w);
          if (ow) { /* on est dehors */ }
       }
    };
    Le problème est que tu réalises un couplage fort entre les classes et qu'il faut modifier le code si tu modifies les types de monde. La présence de dynamic_cast est très symptomatique d'un problème de conception.

    Par contre, il faut mettre un identifiant de zone dans IWorld pour que les clés d'un donjons ne fonctionne pas dans un autre donjon.


    Citation Envoyé par Aspic
    Si on créé un fichier avec comme structure un id correspondant au type de sol et un id correspondant au déplacement associé
    C'est une possibilité. Mais c'est statique donc peu évolutif. A voir en détail.

    Citation Envoyé par Aspic
    Ensuite on couple ca à une fabrique d'objets de type MoveStrategie ?
    Oui, ça me semble être la bonne approche.

    Citation Envoyé par Aspic
    Par contre, sur le sol, on peut à la fois voler et marcher dessus, comment implémenter ca avec les stratégies ?
    Citation Envoyé par LittleWhite
    Pour la stratégie Voler / Marcher avec le type du sol. En fait, seule la stratégie Marcher regarde qu'elle est le type du sol, pour faire ce qui doit être fait (interdire le mouvement si eau).
    La stratégie de vol, ne regardera même pas le sol à cause du vertige (donc retourne toujours true pour indiquer la possibilité du mouvement)
    Pour répondre à l'envers :
    @LittleWhite : si tu fais ça, c'est comme si tu considères qu'il n'y a que 2 états : prendre en compte le sol ou non. Donc pas de comportement adapté en fonction du sol (marcher plus lentement dans la neige par exemple) ou du type de mouvement (le mage qui marche sur l'eau).
    @Aspic : l'idée est que même si plusieurs types de mouvement sont possible, 1 seul est active à la fois. Et certain évènements peuvent changer le type de mouvement. Par exemple :
    - lancer un sort de lévitation active le FlyMoveStrategy
    - utiliser le grappin sur un monstre volant le fait passer de FlyMoveStrategy à WalkMoveStrategy
    - réussir la quête "obtenir la bénédiction des dieux" permet d'activer le WalkInTempleMoveStrategy
    - etc.
    On en arrive à un concept très important pour les jeux : la machine à états. Cela permet d'avoir des états liés à un personnage et des transitions permettant de passer d'un état à un autre. Par exemple, tu peux avoir les états :
    - assis
    - debout
    - en déplacement
    - en combat
    et les transtions :
    - se lever
    - s'assoir
    - sortir son épée
    etc.

    Je te conseille de te renseigner sur ça, c'est très utile

    Bon courage


    PS : Bosser sur la conception n'est pas une perte de temps. Au contraire. Ça en fait gagner lorsque les besoins fonctionnels évoluent (ce qui est toujours le cas sur des projets conséquent, comme un jeu par exemple). Ça fait gagner du temps sur la codage (puisqu'en général, les programmes bien conçus fait la même chose que les programmes mal conçus, mais avec moins de lignes). Et surtout ça fait gagner du temps sur la recherche et la correction de bugs (et comme tout le monde le sait, ça n'arrive jamais d'avoir des bugs dans du code )

  9. #209
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 919
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 919
    Points : 220 492
    Points
    220 492
    Billets dans le blog
    127
    Par défaut
    @LittleWhite : si tu fais ça, c'est comme si tu considères qu'il n'y a que 2 états : prendre en compte le sol ou non. Donc pas de comportement adapté en fonction du sol (marcher plus lentement dans la neige par exemple) ou du type de mouvement (le mage qui marche sur l'eau).
    Bah, deux états, et tout les autres que l'on intégrera selon le besoin.
    En fait, j'essayais de répondre à une question de Aspic, mais peut être que je n'avais pas compris la question.

  10. #210
    Membre chevronné
    Avatar de lagwag
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2009
    Messages
    694
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Septembre 2009
    Messages : 694
    Points : 1 880
    Points
    1 880
    Par défaut
    Citation Envoyé par LittleWhite Voir le message
    Les new ne sont pas protéges ( if ( ptr == NULL ) goFail(); )
    Mais il est possible que vous comptiez sur l'exception (std::bad_alloc) ...
    D'ailleurs je me demande comment que l'on gère correctement le cas :p
    le truc qui n'arrive jamais ... et si ca arrive, l'app crashera de toute facon

  11. #211
    Expert confirmé
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Points : 4 388
    Points
    4 388
    Par défaut
    Citation Envoyé par gbdivers Voir le message
    +1

    Qu'est ce qui distingue que l'on est dans un donjon, dans une maison ou dehors ? C'est uniquement les images qui sont affichées. Du point de vue du code, il n'y a pas de différence. C'est le game design qui fait la différence.
    Je suis d'accord mais dans ce cas avec une seule classe qui gère tous les types de monde, je vais avoir quelque chose du genre :
    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
     
    Class World
    {
    private:
          /* std::vector<Area*> areas; // la liste de toutes les zones */
          Area* currentArea; // la ozne courante (ou l'on se trouve)
          int x,y; // coordonnées de la zone ou l'on se trouve
          int id; // identifiant du monde
          int nbKeys; // nb de clés pour les donjons
          int currentLevel; // étage courant (pour un donjon)
          bool bossDead; // si le boss du donjon est mort ou pas
    public: 
          int update() = 0; // gestion du monde
          void draw() = 0; // affichage
     
          void gererLeBoss();
          void gererLesCles();
          .....
    }
    Je me retrouve avec des attributs et fonctions qui ne servent pas dans le cas d'un monde extérieur...

    C'est là où j'ai du mal à comprendre la conception des zones.

    De plus, dans mon ancienne version de Zelda, j'avais un ID par "Grande Zone" et chaque Grande Zone avait plusieurs Zone (une Zone étant un écran dans Zelda). Par exemple dans Plaine, j'avais 6 Zones. Dans Citadelle, j'avais 4 Zones. Dans le Donjon1, j'avais 20 Zones sur 3 étages... Pour ne pas ralentir le jeu, j'ai décidé de charger en mémoire uniquement la "Grande Zone" courante (Plaine, Citadelle ou Donjon1).
    Mais si j'utilise qu'une seule classe qui possèdent toutes les zones, je ne vais quand même pas charger 500 Zones de tout le jeu en entier dès le démarrage, je vais avoir 1 Go de RAM monté... ^^ lol

    Désolé si j'ai du mal à comprendre, je suis pas à l'aise en conception, je pense que ca se voit mais j'aime apprendre ^^

  12. #212
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 617
    Points
    15 617
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    Class World
    {
    private:
          /* std::vector<Area*> areas; // la liste de toutes les zones */
          Area* currentArea; // la ozne courante (ou l'on se trouve)
          int x,y; // coordonnées de la zone ou l'on se trouve
          int id; // identifiant du monde
          int nbKeys; // nb de clés pour les donjons
          int currentLevel; // étage courant (pour un donjon)
          bool bossDead; // si le boss du donjon est mort ou pas
    public: 
          int update() = 0; // gestion du monde
          void draw() = 0; // affichage
     
          void gererLeBoss();
          void gererLesCles();
          .....
    }

    Là, tu te retrouves en quelque sorte avec une gold class qui fait tout... Tu exploses le principes de responsabilité unique
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    /* std::vector<Area*> areas; // la liste de toutes les zones */
    Pourquoi conserver une liste des Area ? Elle te sert où et pourquoi faire ? Ça ne serait pas plus simple d'avoir que la map active et un gestionnaire qui a pour responsabilité de charger les maps à la demande et les mettre en cache si nécessaire ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Area* currentArea; // la ozne courante (ou l'on se trouve)
    C'est quoi la différence entre Area et World ? Quels sont leurs responsabilités respectives ? Les noms ne sont probablement pas assez informatif.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int x,y; // coordonnées de la zone ou l'on se trouve
    C'est quoi ? C'est pas les coordonnées du personnage plutôt ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int id; // identifiant du monde
    Ok

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int nbKeys; // nb de clés pour les donjons
    Pourquoi les clés sont un élément de world et pas un item porté par le personnage (comme n'importe quel objet : arme, armure, potions, etc.) ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int currentLevel; // étage courant (pour un donjon)
    Pourquoi un indicateur de level ? Ne pourrais tu pas avoir une map par level simplement ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    bool bossDead; // si le boss du donjon est mort ou pas
    Mouais, une variable pour ça... est-ce vraiment utile ? A priori, non si tu utilises des machines à états
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int update() = 0; // gestion du monde
    void draw() = 0; // affichage
    void gererLeBoss();
    void gererLesCles();
    Ouch, le nombre de responsabilité


    Mais si j'utilise qu'une seule classe qui possèdent toutes les zones, je ne vais quand même pas charger 500 Zones de tout le jeu en entier dès le démarrage, je vais avoir 1 Go de RAM monté... ^^ lol
    Sur une map comme celle de Zelda - A link to the past (qui est quand même un très grosse map), l'image fait 4096*4096 pixels et les tiles font (en gros) 16*16 pixels donc la map est représentée par une tilemap de 256*256. En supposant que les tiles sont codés par un entier "standard" (32 bits, soit plus de 4 milliards de tiles différents possible, ce qui est pas mal non plus) alors la map complète représente... 256 ko en mémoire. Bref rien du tout !

    Ce qui est lourd, de n'est pas les tilemaps mais les images représentant les tiles.
    Par contre, cela ne veut pas dire qu'il faut quand même charger toutes les maps. Mais il faut relativiser.


    Bref, pour en revenir à ta problématique : te prend pas trop la tête. Essaies quand même d'avancer dans le jeu sinon ça te découragera trop.
    Au pire, tu recommenceras ton jeu plusieurs fois

  13. #213
    Expert confirmé
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Points : 4 388
    Points
    4 388
    Par défaut
    Citation Envoyé par gbdivers Voir le message
    Bref, pour en revenir à ta problématique : te prend pas trop la tête. Essaies quand même d'avancer dans le jeu sinon ça te découragera trop.
    Au pire, tu recommenceras ton jeu plusieurs fois
    Le jeu est déjà fini :
    http://www.tutoworld.com/temp/zelda_demo_finale.zip

    Justement, je le recommence pour la conception mais je ne compte pas le refaire X fois, j'ai très peu de temps pour mes loisirs

    Mais oui, je suis un peu démotivé, ca me déprime de ne rien comprendre, je sais pas ca à l'air super compliqué tout ca !

  14. #214
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 617
    Points
    15 617
    Par défaut
    Mais oui, je suis un peu démotivé, ca me déprime de ne rien comprendre, je sais pas ca à l'air super compliqué tout ca !
    Aie. Faut surtout pas.
    Il faut bien comprend que ce qu'on te racontes sont des concepts un peu plus compliqué à comprendre (dans le sens où ce n'est pas du codage pur mais de la conception) et que ça prend du temps et du travail pour maîtriser (regarde OpenAWars de LittleWhite, il a travailler sur l'architecture pendant au moins 6 mois).

    Il faut procéder par étape (et vérifier que le programme fonctionne à chaque étape) :

    1. continuer à développer le jeu. C'est le plus important : l'intérêt d'une bonne conception est de faciliter l'évolution d'un jeu. Donc fais évoluer ton programme et tu verras les problèmes rencontrés par ton code et les problèmes de conception. Ça permet de mieux comprendre les avantages de la conception.

    Donc tu peux :
    * ajouter des maps
    * ajouter des armes qui ont des effets particuliers (grappin, boomerang, etc.)
    * ajouter des objets/sorts/capacités qui offres des fonctionnalités particulières au personnage (voler, devenir invisible, téléportation, nager sous l'eau, etc.)
    * facilite la vie des game designers : éditeur de maps, éditeur de script (en te posant la question "quelles fonctionnalités ne peut-on pas utiliser par script ?")
    * multijoueur
    * etc.

    2. bosser sur les principes de la POO : Liskov, SRP, OCP, etc. A faire par étape aussi : tu lis le blog d'Emmanuel Deloget sur les 5 principes (lire les articles "Valider et corriger une architecture objet" et les articles correspondant au 6 principes expliqués) puis tu prends 1 principe à la fois et tu vérifies toutes tes classes pour voir si elles respectent ce principe.

    2. bosser sur les design pattern : strategie, factory, etc. Idem que précédemment : lis les articles de David Come et les articles de Wikipédia puis prend un design pattern à la fois et regarde toutes tes classes pour vérifier si tu peux appliquer le design pattern

    4. tu recommences au point n°1

    Il est possible qu'il faille faire le point 3 avant le 2, je sais pas trop. De toute façon, il faut faire plusieurs itérations.


    Amuse toi bien quand même.

  15. #215
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 919
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 919
    Points : 220 492
    Points
    220 492
    Billets dans le blog
    127
    Par défaut
    Je ne suis pas contre ce que dit gbdivers, mais par contre, je trouve aussi que tout cela est très compliqué et aussi très pénible.

    Dans le sens, nous voulons coder des jeux et voir qu'ils fonctionnent assez tot (tout de même). Et que la partie programmation, nous intéresse surement plus que la partie conception (qui est longue, où l'on ne voit pas le résultat immédiat ...)

    Par contre, je dirai que la conception est importante. Dans OpenAWars, je regrette un peu d'avoir négliger ce point, car lorsque j'ai vu mon code, j'ai crié devant le fait que je ne pouvais plus avancer mon jeu sans enclencher dix milles problèmes et chercher cent milles workaround (contournements). Cela est source de bugs, donc cela n'est pas cool.

    Et puis, la partie scripting est super intéressante, car avec un peu d'imagination, on pourrait utiliser votre moteur de zelda pour en faire un zelda2, ou même complêtement changer le concept (c'est ce que j'espère atteindre, un jour avec OpenAWars).

    Après, pourquoi faire un beau design? Moi, OpenAWars est en ligne (le code et tout), si un gars comme vous veut le réutiliser (au moins le NEngine) alors ce code doit être propre est réutilisable (et extensible). Là entre le principe de responsabilité unique (car je ne connais presque lui), qui permet de faire le code très dynamique.

    Maintenant, je dirai, selon ce que vous voulez vraiment faire, il va falloir s'orienter sur beaucoup de travail sur le design, ou alors un full raw coding (si je puis dire) ou rien ne sera réutilisable.
    (Disons que moi, je commence à en avoir marre de faire mille fois le même code )

    Donc, pour conclure, je vous propose un marché (dans les deux cas, nous voulons voir un jeu fini est complet ).
    Si vous voulez travailler les design pattern / les bons principes de la programmation objets et vous améliorez sur ces points, suivez surtout les conseils de gbdivers, que les miens.
    Si vous voulez faire un jeu, jouable rapidement, mais qui se cantonne à une reprise de Zelda sans plus, (et que la partie design vous intéresse peu) alors, go, codez nous le jeu complet.
    Mais vous allez voir que pour la deuxième partie, le jeu complet sera un peu difficile à atteindre à cause du manque de design

    Dans les deux cas, j'espère voir un jeu complet et dans les deux cas, je vous supporterai (et j'imagine que gbdivers aussi )


    EDIT:
    Le C++ est un langage plutôt très complet et difficile, surtout lorsque l'on fait de l'orienté objet (soit, code dynamique, réutilisable, extensible). Mais on peut l'utiliser aussi comme le C, et faire un peu n'importe quoi (le jeu d'un jour, que l'on ne retouche pas)

  16. #216
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 617
    Points
    15 617
    Par défaut
    Dans le sens, nous voulons coder des jeux et voir qu'ils fonctionnent assez tot (tout de même). Et que la partie programmation, nous intéresse surement plus que la partie conception (qui est longue, où l'on ne voit pas le résultat immédiat ...)
    Je pars du principe que vous êtes étudiant et que le but est aussi d'apprendre

  17. #217
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 919
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 919
    Points : 220 492
    Points
    220 492
    Billets dans le blog
    127
    Par défaut
    Citation Envoyé par gbdivers Voir le message
    Je pars du principe que vous êtes étudiant et que le but est aussi d'apprendre
    Juste le fait de programmer permet d'apprendre. Car c'est en programmant que l'on devient programmeur.

  18. #218
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Je pense qu'on est tous d'accord. Ta première ébauche sera dégueulasse, c'est normale. Ensuite, tu la retravaille ou tu recommences mais au final tu auras un truc meilleur.

    Un code d'un projet long terme est une chose vivante, il y a des parties qui ne sont pas revisitées et qui tombe dans l'oubli ou des parties qui évolue énormément. On apprend un nouveau concept et une partie du code en bénéficie mais le reste n'est plus cohérent, au fur et à mesure, on le met à jour, etc.

    Il faut que cela reste intéressant, que cela t'amuse et que tu apprennes à tous les jours !

    Bon courage et ne perd pas espoir,
    Jc

  19. #219
    Expert confirmé
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Points : 4 388
    Points
    4 388
    Par défaut
    Merci à tous pour vos encouragements

    Je vais tenter d'implémenter quelque chose et me lancer, on verra ce que ca donne.

    Pour en revenir à ce que disait gbdivers sur la God Class (je sais enfin ce que c'est grâce aux articles d'Emmanuel ^^), j'ai compris pourquoi ca n'allait pas.

    En fait, voilà ce que je comptais faire pour la gestion des zones :

    1) La classe World représente tout l'univers du jeu. Pour Zelda A link to the past, c'est la carte :
    http://www.open-mouthed.com/images/1296404313.png

    2) La classe GroupAreas représente plusieurs zones d'un même univers (plaine, désert, foret...)

    3) La classe Area ne représente qu'une Zone, c'est à dire une tilemap de 256*256 pixels.

    En code ca donnerais quelque chose du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
     
    class Area
    {
    std::vector < Object* > objets; // les objets présents sur la zone 
    int width; // longueur (256px dans A link to the Past)
    int height; // largeur (256px dans A link to the Past)
    };
     
    class GroupArea
    {
    std::vector < Area* > areas; // la liste des zones
    int nbAreas; // le nombre de zones 
    int width; // taille du groupe
    int height;
     
    void makeTransition(); // procédure faisant la transition entre deux Zones (le scroll dans un Zelda)
     
    };
     
    class World
    {
    std::map< std::string, GroupArea* > areas; // la liste sous forme clé/valeur des types de zones de l'univers.
    // Exemple : plaine, foret, desert, montagne...
     
    void changeGroupArea(); // procédure permettant de changer de Groupe de Zones.
    // Exemple passer de la plainte à la forêt.
    };
    Voilà, je ne sais pas pourquoi mais je sens encore que mon implémentation est foireuse

    D'ailleurs si je rentre dans un Donjon, je ne sais pas si cette conception est applicable

  20. #220
    Membre chevronné
    Avatar de lagwag
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2009
    Messages
    694
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Septembre 2009
    Messages : 694
    Points : 1 880
    Points
    1 880
    Par défaut
    tu devrais differencier les variables locales et les variables membres de tes classes contrairement aux structures... choisis ce que tu veux comme prefixe mais choisis en un... "m_" par exemple... et la lettre p pour les pointeurs... c'est pas grand chose mais c'est la base pour s'y retrouver et arriver à structurer correctement son code

    int nbAreas n'est pas utile, tu as le vector qui t'indique deja le nbre.

    je n'utilise jamais la STL... utiliser des map ca devient vite l'enfer... quelques conseils au passage: ne pas utilser les smart pointeurs (j'en utilise jamais et mes apps ne crash pas plus que celles des autres), limiter les singleton et l'utilisation abusive des templates, utiliser protected au lieu de private qui s'avere sans interet sauf pour les variables tres "sensibles"...

Discussions similaires

  1. [Projet terminé] mon remake de Crazy Cars sur PC et Megadrive
    Par barbarian.1987 dans le forum Projets
    Réponses: 2
    Dernier message: 31/07/2014, 18h36
  2. Documentation gratuite sur l'API Windows, COM, DCOM, OLE, etc.
    Par Community Management dans le forum Windows
    Réponses: 1
    Dernier message: 16/11/2006, 16h28
  3. [Kylix] Kylix embarqué sur PDA ?
    Par Anonymous dans le forum NoSQL
    Réponses: 10
    Dernier message: 29/11/2002, 14h59
  4. Réponses: 4
    Dernier message: 27/03/2002, 12h03
  5. F.A.Q, Doc, cours, tutoriels sur JBuilder
    Par Ricky81 dans le forum JBuilder
    Réponses: 0
    Dernier message: 14/03/2002, 16h28

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