IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Question conception d'un jeu 2d en C++


Sujet :

C++

  1. #21
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    Citation Envoyé par marcolo21 Voir le message
    P
    Donc en gros les 4 classes sont pareil, ils ne contiennent que des fonctions virtuel (virtuel pure ?). Je peux donc faire un copier coller et changer le nom pour crées les 4 classes.
    Pour ce qui est des trois classes de bases (Player, MovingObject et NonMovableObject), oui (en veillant à le placer dans des fichiers séparés, de manière à ne pas imposer la connaissance des deux autres lorsque tu a besoin d'une classe de base particulière )

    Par contre, pour les classes dérivées (Gamer ( = toi), Ennemy ( == un "mechant" personnage), Bullet ( == un boulet de canon, héritant de ... MovingObject) ou Interruptor (== un interrupteur, héritant de NonMovableObject), seule les fonctions virtuelles ( doCollide( ... ) ) devront être déclarées et définies.
    Ok tu doit parler de ce code:

    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
     
    class CollisionDetector
    {
         public:
            /* j'aime les template pour éviter de devoir réécrire
             * vingt fois la même chose :D
             template <typename FirstType, SecondType>
             static void detect(FirstType * one, SecondType * second)
             {
                 /*logique de détection de collision */
                /* logique de sélection de priorité */
               sendCollision(mostPriorItem, secondPriorItem);
             }
        private:
              template <typename FirstType, SecondType>
             void sendCollision(FirstType * mostPriorItem, SecondType * secondPriorItem)
             {
                 Colllision * col = CollisionFactory::createCollection(mostPriorItem, secondPRior);
                 col->transmit();
             }
    };
    Oui, c'est bien de lui que je parle :d

    Je remarque que tu utilise une Factory. Je ne sais pas exactement ce que c'est (j'avais trouver un lien sur developpez qui l'expliquait un peu), aurais-tu quelque lien qui explique comment c'est fait et à quoi cela sert ?
    L'idée d'une factory (d'une fabrique, en francais) est de déléguer et de centraliser en un point unique la création d'objets polymorphes ( comme les différents types de collisions) de manière à éviter autant que possible que d'autres objets n'aillent les créer de manière anarchique.

    Il faut comprendre que le gros de la gestion de la collision sera déjà dévolu au CollisionDetector (c'est lui qui devra la détruire quand elle sera devenue inutile, c'est lui qui décidera de quant en créer une, et c'est lui enfin qui invoquera la fonction collide des deux éléments qui sont rentrés en collision).

    Cela fait déjà beaucoup pour une seule classe, d'autant plus qu'il doit donc avoir une connaissance de l'ensemble des éléments (quels qu'en soient le type) qui sont affichés, afin de pouvoir, justement, calculer si collision il y a

    Le but de la fabrique est de prendre en charge le choix du type de collision à créer et la création effective.

    Il faut comprendre aussi que, comme nous sommes dans une logique d'héritage (que ce soit pour les collisions ou pour les autres hiérarchies) à but polymorphe (l'idée est de pouvoir gérer les différents éléments de chaque hiérarchie en les faisant passer comme étant du type de leur classe de base, sans avoir à s'inquiéter de leur type réel), tous les types que tu pourrais créer au départ de ces classes de base on une sémantique d'entité (cf la FAQ pour plus d'infos sur ce qu'on entend par là ) et qu'il ne devraient donc pas être susceptibles d'être copiés ni affecté (seule l'utilisation de références et de pointeurs sur les objets existants devrait être admise ailleurs qu'au sein de la fabrique.

    Le gros avantage de travailler de la sorte, c'est que, si un jour tu souhaites rajouter un type (on a parlé des "FlyingEnnemy" et des "FlyingObject" ), le seul endroit que tu devras modifier (ou peu s'en faut) sera... la fabrique (de MovableObject ou de Player, ici), parce que c'est le seul endroit où l'on aura effectivement besoin de connaitre le type réel (partout ailleurs, les objets seront traités comme des "Player" ou comme des MovableObject, sans s'inquiéter de savoir si ce sont des boulet de canon, des oiseaux ou des dragons )
    De plus, est-ce que c'est la fonction qui teste s'il y a une collision qui doit appeler la fonction sendCollision ?
    Ouupss, j'ai oublié de fermer mes commentaires je vais corriger mon code


    Pour l'instant je crois que je vais y allez avec l'enumeration, faute de meilleur idée. Si tu a une meilleur idée, n'hésite pas à la poster.



    Alors, je dois crée une fonction pour chaque réaction ? Exemple: Ennemis.ReactJumping(), Ennemis.ReactAttacking(), etc. ???
    Qu'est-ce que je passerai en paramètre à cette fonction ?

    c'est une fonction statique (car elle doit etre accessible sans qu'il n'existe forcément d'instance particulière de CollisionDetector), que j'ai rendue template pour m'éviter d'avoir à réécrire le code pour l'ensemble des possibilités (après tout, ce qui importe, c'est que deux "choses" entre en collision ) et que je remets ici:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    template <typename FirstType, SecondType>
             static void detect(FirstType * one, SecondType * second)
             {
                 /*logique de détection de collision */
                /* logique de sélection de priorité */
               sendCollision(mostPriorItem, secondPriorItem);
             }
    En faite je parlai plus dans le sens de si je suis dans la classe personnage et que je suis dans la fonction :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     virtual void doCollide(CollisionPlayerMovingObject &)
    Si l'objet reçu en paramètre est un MovingObject, Comment savoir!!! tout ce que tu as à faire, c'est réagir à la touch si ce MovingObject est un ennemi et pouvoir utiliser les fonctions spécifiques au ennemis par exemple ? Puisque si je comprend bien les seuls fonctions que MovingObject a son les DoColide, donc s'ils sont des Ennemis, je n'ai pas accès au fonction des ennemis.
    C'est ma faute, je me suis arrêté à l'aspect "collision", mais, en gros, tu peux avoir (à peu près) cinq grosse réactions face à un objet mobile:
    • essayer de le retenir
    • essayer de grimper dessus
    • essayer de l'agripper
    • essayer de sauter au dessus
    • essayer de passer en dessous

    Mais ces réactions seront commandées par... la touche enfoncée au moment de la collision ,en ce qui te concerne du moins, par une logique et des algorithmes adaptés pour les autres types, voire, avoir des réactions tout à fait différentes (un objet immobile a peu de chance d'essayer de te sauter dessus )

    Comme nous sommes dans un système d'interaction, un objet mobile va... réagir à chacune de ces tentative (grâce à des fonctions comme Climbed, jumpedOver, catched() ou passedUnder, par exemple)

    Ces fonctions suivraient le même principe que collide et doCollide() (comprend : invoqueraient une fonction virtuelle privée à redéfinir si la réaction "par défaut" ne convient pas).

    Tu n'aurais donc même pas à savoir que l'objet mobile que tu essaye d'attraper est un ennemi... sa réaction lorsque tu tenteras de le faire te le fera bien sentir (parce que, pas de bol, essayer d'attraper un ennemi à mains nues fera que cet ennemi te tuera, ou qu'il ne réagira pas à cette tentative, mais que sa réaction à une collision avec toi (qui arrivera juste après) le fera )

    L'idée de base est, vraiment, de faire en sorte que chaque type d'objet ne connaisse qu'un minimum de types différents et aussi génériques que possible (les classes de base de nos quatre hiérarchies expliquées dans ma première intervention + les différents type réels de collision).

    C'est le polymorphisme en réaction à une tentative donnée de ta part (ou en réaction à la collision avec toi) qui te permettra de faire qu'un objet immobile commence à descendre (parce que ton poids le pousse vers le bas), éclate (parce que tu lui a donné un coup de tête) te tue (parce que tu es face à un ennemi avec des picots) ou que justement cet ennemi meure (parce qu'il sera entré en collision avec... une carapace de tortue que tu lui auras jeté)
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  2. #22
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Mai 2010
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Mai 2010
    Messages : 69
    Par défaut
    Citation Envoyé par koala01 Voir le message
    L'idée d'une factory (d'une fabrique, en français) est de déléguer et de centraliser en un point unique la création d'objets polymorphes ( comme les différents types de collisions) de manière à éviter autant que possible que d'autres objets n'aillent les créer de manière anarchique.
    Ok merci je vais essayer de me renseigner sur la factory pour voir comment cela marche

    Citation Envoyé par koala01 Voir le message
    Il faut comprendre que le gros de la gestion de la collision sera déjà dévolu au CollisionDetector (c'est lui qui devra la détruire quand elle sera devenue inutile, c'est lui qui décidera de quant en créer une, et c'est lui enfin qui invoquera la fonction collide des deux éléments qui sont rentrés en collision).

    Cela fait déjà beaucoup pour une seule classe, d'autant plus qu'il doit donc avoir une connaissance de l'ensemble des éléments (quels qu'en soient le type) qui sont affichés, afin de pouvoir, justement, calculer si collision il y a
    Alors 2 question me vienne a l'esprit en lisant cela.

    Comment faire pour que le collisionDetector connaisse tous l’environnement ?

    Quel est la manière d'appeler la fonction detect ?

    comme sa ? :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CollisionDetector::Detect<Player,MovableObject>(Gamer,Enemi);
    (Va vraiment falloir que je me renseigne mieux sur les templates)


    Citation Envoyé par koala01 Voir le message
    Il faut comprendre aussi que, comme nous sommes dans une logique d'héritage (que ce soit pour les collisions ou pour les autres hiérarchies) à but polymorphe (l'idée est de pouvoir gérer les différents éléments de chaque hiérarchie en les faisant passer comme étant du type de leur classe de base, sans avoir à s'inquiéter de leur type réel), tous les types que tu pourrais créer au départ de ces classes de base on une sémantique d'entité (cf la FAQ pour plus d'infos sur ce qu'on entend par là ) et qu'il ne devraient donc pas être susceptibles d'être copiés ni affecté (seule l'utilisation de références et de pointeurs sur les objets existants devrait être admise ailleurs qu'au sein de la fabrique.
    Donc partout dans mon programme quand je me crée des ennemis par exemple je doit utilisé la fabrique ?

    Je pensais me créer un classe level qui contiendrai un vector avec les ennemis, les blocks, les items, etc du niveau. Il faudra donc que j'utilise la fabrique pour crée toute c'est objet lors de mon load du level ?

    Citation Envoyé par koala01 Voir le message
    Le gros avantage de travailler de la sorte, c'est que, si un jour tu souhaites rajouter un type (on a parlé des "FlyingEnnemy" et des "FlyingObject" ), le seul endroit que tu devras modifier (ou peu s'en faut) sera... la fabrique (de MovableObject ou de Player, ici), parce que c'est le seul endroit où l'on aura effectivement besoin de connaitre le type réel (partout ailleurs, les objets seront traités comme des "Player" ou comme des MovableObject, sans s'inquiéter de savoir si ce sont des boulet de canon, des oiseaux ou des dragons )
    Le seul problème que je vois avec cette façon de faire est que justement à partir de la classe player, je n’aie pas accès au même donnée que la classe Gamer ( comme les positions, le status, les attaques, etc). A moins que je ne comprend pas quelque chose ? Pourrais-tu me donner un exemple de ce à quoi la classe player pourrait ressembler au finale ( avec tous ce dont tu a en tête), car j'ai de la difficulté a m'imaginer. (Peut-être que je t'en demande trop )


    Citation Envoyé par koala01 Voir le message
    C'est ma faute, je me suis arrêté à l'aspect "collision", mais, en gros, tu peux avoir (à peu près) cinq grosse réactions face à un objet mobile:
    • essayer de le retenir
    • essayer de grimper dessus
    • essayer de l'agripper
    • essayer de sauter au dessus
    • essayer de passer en dessous

    Mais ces réactions seront commandées par... la touche enfoncée au moment de la collision ,en ce qui te concerne du moins, par une logique et des algorithmes adaptés pour les autres types, voire, avoir des réactions tout à fait différentes (un objet immobile a peu de chance d'essayer de te sauter dessus )

    Comme nous sommes dans un système d'interaction, un objet mobile va... réagir à chacune de ces tentative (grâce à des fonctions comme Climbed, jumpedOver, catched() ou passedUnder, par exemple)

    Ces fonctions suivraient le même principe que collide et doCollide() (comprend : invoqueraient une fonction virtuelle privée à redéfinir si la réaction "par défaut" ne convient pas).

    Tu n'aurais donc même pas à savoir que l'objet mobile que tu essaye d'attraper est un ennemi... sa réaction lorsque tu tenteras de le faire te le fera bien sentir (parce que, pas de bol, essayer d'attraper un ennemi à mains nues fera que cet ennemi te tuera, ou qu'il ne réagira pas à cette tentative, mais que sa réaction à une collision avec toi (qui arrivera juste après) le fera )
    Donc si je comprend bien ton raisonement la classe MovingObjet aurait des méthode du style climbed , jumpover, etc. Qui représenterai toute les actions possible d'un movingObject et donc elle ne se limiterai pas seulement au colision mais a tous ce qui rassemble un MovingObjet et donc toute les possibilités d'action qu'un MovingObject peut faire. Est-ce exact ?


    Finalement, dernière petite chose, lorsqu'un personnage avance et qu'il frappe par exemple un mur, il faut une fonctions qui le face reculer collé au mur ( pour pas qu'il entrecroise le mur ). Je met cette fonction à quel endroit ? Dans le CollisionDetector ?


    Merci beaucoup de prendre le temps de m'aider, ce n'est pas tous les personnes qui aurait le courage de bien m'expliquer le tous comme tu le fait.

    ps: Je sèche toujours pour ce qui est du sens de la collision (dessous, dessus, droite, gauche)

    ps2: Je vais essayer de modifier mon schéma de classe en suivant tes interventions et je le posterai ici pour avoir un avis sur ma conception

  3. #23
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    Je vais, si tu le permet, t'expliquer (je ne te donnerai pas tous les codes, mais les explications devraient te mettre sur la voie de ce qu'il faut faire ) comment je gérerais ce projet si c'était à moi de le faire...

    Dans le code que je mettrai, j'écrirai énormément de commentaires. Ils sont presque plus importants que le code lui-même car ils ont pour but de te faire comprendre la raison pour laquelle je fais les choses de cette manière

    Cela devrait répondre à quelques unes de tes questions (et sans doute à d'autres auxquelles tu n'as pas encore pensé ), puis je répondrai à celles qui restent

    Je créerais une classe Game qui serait le point "d'entrée du programme", qui présenterait comme interface une unique fonction publique "run".

    Elle serait sans doute utilisée par la fonction main sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int main()
    {
        Game g;
        return g.run();
    }
    (on voit rarement une fonction main aussi petite )

    Cette classe déléguerait à un certain nombre de classes les différents aspects qui sortent du cadre du niveau, tels que:
    1. la gestion du menu principal (déléguée à une classe "HeadMenu" :-D )
    2. la gestion des meilleurs scores (déléguée à une classe "HightScores" )
    3. la gestion du niveau de jeu (déléguée à une classe Level)
    4. la gestion des options de jeu (déléguée à une classe OptionManager)
    5. la gestion du chargement et de la sauvegarde d'une partie en cours (déléguée à une classe "GamePersistance", si pas à une classe GameSaver et un autre GameLoader )
    6. Le chargement d'un niveau (délégué à une classe LevelLoader)
    7. j'en oublie peut etre, mais les principaux sont là
    Le fait de déléguer toutes ces taches à des classes particulières va, tu vas le remarquer, te permettre d'avoir une classe Game qui, au final, ne fait plus grand chose :

    Elle ressemblerait sans doute à quelque chose comme
    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    /* une énumération pour que les choses soient plus parlantes :D */
    enum MenuChoice
    {
        choiceNoChoice,
        choiceNewGame,
        choiceLoadGame,
        choiceSaveGame,
        choiceOptions,
        choiceTopScores,
        choiceExit,
        choiceCount
    };
    class Game
    {
        public:
        void run()
        {
            MenuChoice choice= choiceNoChoice;
           do
           {
                Menu menu;
                choice=menu.sow();
                switch (choice)
                {
                    case noChoice: // ca ne devrait pas arriver, mais sait on jamais
                                  // :D
                        break,
                    case NewGame:
                        lives_ = 5;
                        level_ = 1;
                        gold_ = 0;
                        play();
                        break;
                     case choiceLoadGame:
                        loadGame();
                        play();
                        break;
                     case saveGame:
                        GameSaver saver;
                        saver.save(level_, lives_, gold_);
                     case choiceOptions:
                        OptionManager man;
                        man.setUp();
                        break;
                     case choiceTopScores:
                        topScores(0);
                     case choiceExit:
                        break;
                     default :
                         assert(!"You never should come here !!!"); 
                }
            } while(choice != choiceExit);
        }
        /* les autres fonctions peuvent être privées, car elles ne doivent etre
         * appelées que par run :D
         */
        private:
        /* mais n'oublions pas les membres de Game... les valeurs qui doivent
         * passer d'un niveau à un autre :D
         */
        int lives_;
        int level_;
        int gold_;
        /* la fonction play va s'occuper de déléguer au LevelLoader le fait 
         * de charger le niveau ad-hoc puis de demander au niveau de s'exécuter
         */
       void play()
       {
            LevelLoader loader;
            /* la fonction "play" du niveau peut nous renvoyer trois valeurs 
             * différentes (qui prendrait bien place dans une énumération
             * "LevelResult" :D)
             *    levelFinished (on est arrivé au bout :D )
             *    levelDie (on est mort en cours de route )
             *    levelAbord (on a décidé d'abandonner )
             *
             * il y a, à vrai dire, au moins une autre valeur intéressante à placer 
             * dans l'énumération : levelNoResult (pour pouvoir initialiser
             * les variables avec une valeur neutre )
             *
             */
           /* on ne peut continuer, de toutes manières, que si le joueur a
            * encore un nombre de vies suffisant (au moins une)
            * et s'il n'a pas décidé d'abandonner :D, mais, tant que l'on n'est
            * pas dans un de ces cas, on continue à jouer :D
            */
           LevelResult result = levelNoResult;
           do
           {
                loader.load(level_, lives_,gold_);
                Level & level = loader.level();
                result = level.play(); // c'est la fonction qui prend en charge
                                     // l'ensemble de l'exécution du niveau ;)
                switch (result)
                {
                    case levelFinished :
                        ++level_;
                        lives_= level.lives();
                        gold_ = level.gold();
                        break
                   case levelDie:
                        gold_=level.gold();
                        break;
                   case levelAbord:
                         break;
                    default:
                        assert(!"You should never come here");
                }
           }while(live >0 && result!= levelAbord);
           topScores(gold_); // permet de gérer le score par rapport 
                              // aux meileurs scores actuels :D
       }
       void loadGame()
       {
            GameLoader loader();
            loader.load();
            lives_ = loader.lives();
            level_ = loader.level();
            gold_ = loader.gold();
       }
       void topScores(int score)
       {
           TopManager manager;
           manager.show(score);
       }
    };
    Tu auras remarqué que, du simple fait que j'ai correctement partagé les responsabilités, j'obtiens des fonctions particulièrement simples à implémenter

    La classe Menu ne sera pas beaucoup plus compliquée: elle sera composée essentiellement d'une fonction show() renvoyant une valeur énumérée de type MenuChoice qu'elle aura obtenu d'une autre classe ( que l'on pourrait appeler "GraphicalMenu" )ayant pour responsabilité d'afficher le menu et de gérer l'aspect "visuel" de celui-ci (y compris le clique sur les différents éléments )

    Il en va de même des classes GameLoader et GameSaver, qui n'auront elle aussi qu'une fonction publique(respectivement load et save), qui s'occuperont respectivement de charger et de sauvegarder l'état actuel de la partie et qui délégueront l'affichage du choix du fichier à une classe particulière (que nous pourrions appeler respectivement GraphicalGameLoader et GraphicalGameSaver)

    La classe LevelLoader, par contre, sera sans doute un peu plus compliquée...

    Elle a en effet la lourde responsabilité de s'assurer que l'ensemble du niveau sera correctement chargé!

    Cela ne veut pas seulement dire remplir ne niveau avec les éléments de décors et les ennemis, mais cela signifie aussi veiller à ce que les fonds sonores (musique et effets spéciaux) ou les images, par exemples, soient correctement chargées!

    Elle pourra s'appuyer dans cette tâche sur plusieurs classes particulières, parmi lesquelles nous pourrions citer: Les fabrique de personnages, d'objets mobiles et d'objets immobile, ou encore les gestionnaires de sons et d'images.

    Son role sera "simplement" de lire un (ou plusieurs) fichiers et de déterminer en fonction de ce qu'elle lit à quel gestionnaire ou à quelle fabrique elle doit s'adresser pour prendre en charge les informations qu'elle vient de recevoir.

    Elle disposerait en outre d'un membre de type Level auquel on accéderait (sous la forme d'une référence) grâce à la fonction membre... level().

    J'imagine déjà les points d'interrogations qui tournent autour de ta tête en lisant cela, parce que tu te demande très certainement comment tout cela va fonctionner

    Le fait est que tu ne dois, à un moment donné, n'avoir qu'une seule instance de ta classe Level et que le meilleur moyen de s'assurer que ce sera le cas, c'est encore de veiller à n'en créer qu'une seule instance

    De plus, il faut s'assurer que l'ensemble du niveau sera correctement détruit, et, comme le niveau est un membre (pas un pointeur, un membre tout à fait ordinaire ) de LevelLoader, il le sera détruit en même temps que... l'instance de LevelLoader qui le contient, c'est à dire, lorsque nous quitterons la portée dans laquelle nous avons créé notre instance de LevelLoader, à savoir... quand nous sortirons de la fonction play()

    Tu n'auras même plus à envisager le recours à un singleton ou à un pattern monostate pour certains éléments, avec le risque toujours latent) qu'il faut veiller à les vider à certains moments sous peine de voir certaines ressources du niveau précédent s'inviter dans le niveau en cours et le poluer car les dites ressources seront correctement détruite "en meme temps que tout le reste"

    Nous en arrivons maintenant à notre fameuse classe "Level", qui sera le "coeur du système" (ou peu s'en faut)

    Ce sera aussi une classe un peu plus complexe, mais nous allons essayer de la garder aussi simple que possible, et, pour cela, elle pourra faire appel à un certain nombre d'autres classes telles que:
    • des gestionnaires de ressources (sonores et graphiques) !!!ce seront des membres de la classe, surtout pas des singletons ou des monostate!!!
    • des "utilisateurs" de ressource (les classes qui jouent les musiques et les effets spéciaux, les classes responsable de l'affichage, ... )
    • les gestionnaires d'éléments de jeu (de NonMovableObject, de MovableObject et de Player, pour reprendre les termes utilisés dans mes interventions précédentes) Ce seront également des membres de la classe, en aucun cas des singleton ou des monostates
    • Le fameux CollectionDetector, qui devra détecter les collisions
    • Quelques classes "secondaires" qui permettront, par exemple, de trier les éléments en fonction de leur proximité (il ne sert à rien de vérifier si un objet risque d'entrer en collision avec la dernière marche tout au bout du niveau si on n'est pas "à vue" de celle-ci )
    • une ou plusieurs classes qui géreront les mouvements des objets "susceptibles de bouger" (ceux qui sont "à vue" et qui... ont la capacité de bouger: les MovingObject et les Player, essentiellement )
    • j'en oublie peut etre, mais les principaux sont là
    Il devrait ressembler à quelque chose de fort proche de
    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    class Level
    {
        public:
            /* on n'y coupe pas, c'est ce qui le caractérise en premier :D */
            Level(int lev, int liv, int go):alive_(true), finished_(false),
                   aborded(false);
                   level_(lev),lives_(liv),gold_(go){}
            /* les fonctions qui seront appelées par Game */
            LevelResult play()
            {
                /* nous sommes dans la boucle principale du niveau...
                 * nous resteront dedans tant que l'objet représentant
                 * le joueur ne nous a pas signalé sa mort ou son arrivée
                 * à la fin du niveau et tant que le gestionnaire d'événements
                 * ne nous a pas signalé l'abandon du joueur :D
                 */
                 while (alive_ && ! finished_ && ! aborded_)
                 {
                     // cette partie, je te la laisse :D
                 }
                 if(aborded_)
                     return levelAbord;
                 if( ! alive)
                     return levelDie;
                 return levelFinished;
            }
            int gold() const{return gold_;}
            int lives() const{return lives_;}
            /* les fonctions qui permettent "d'enregistrer" différentes ressources
             * certaines seront appelées par les fabriques, d'autres
             * seront appelées directement par LevelLoader
             */
            void registerSound(std::string const & str)
            {
                sounds_.registerItem(str);
            }
            void registerImage(std::string const & str)
            {
                images_.registerItem(str);
            }
            void registerItem(NonMovableObject * obj)
            {
                nonMovables_.registerItem(obj);
            }
            void registerItem(MovableObject * obj)
            {
                movables_.registerItem(obj);
            }
            void registerItem(Player * obj)
            {
                players_.registerItem(obj);
            }
            /* Le joueur est susceptible de lui parler directement
             */
           void gotGold(int count)
           {
               gold_ += count;
           }
           void catchLive()
           {
               ++ lives_;
           }
           void died()
           {
               --lives_;
               alive_ = false;
           }
           void finished()
           {
               finished_ = true;
           }
           /* cette fonction sera plutôt invoquée par le gestionnaire
            * dévénements (vu qu'elle implique que le joueur a cliqué
            * quelque part ou qu'il a enfoncé une touche particulière :D
            */
           void abord()
           {
               aborded_ = true,
           }
            /* a priori, s'il manque des fonctions, elles seront surement
             * privées, car je crois qu'on a tout ce qu'on peut demander
             * à notre niveau... mais j'ai peut etre oublié quelque chose :D
             */
        private:
            bool alive_;
            bool finished_;
            bool aborded_;
            /* il est quand meme sympa pour un niveau de savoir lequel c'est :D 
             */
            int level_;
            int lives_;
            int gold_;
            /* les différents gestionnaires qu'il va utiliser */
            SoundManager sounds_;
            ImageManager images_;
            NonMovableManager nonMovables_;
            MovableManager movables_;
            PlayerManager players_;
    }
    Voilà, grâce à toi, je vais encore me faire taquiner à cause de la longueur de mon poste

    Il n'y a très certainement pas toutes les classes, ni toutes les fonctions, mais tu devrait maintenant avoir une idée globale de la manière dont tout prend sa place
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #24
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Mai 2010
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Mai 2010
    Messages : 69
    Par défaut
    Bonjours tout le monde,

    J’ai fait ma conception en générale et je viens maintenant vous la montré pour avoir des avis et des idées d’amélioration.

    Je vais surtout me concentrer sur les classes de type d’objet (Player, MovableObject, ImmobileObject).

    Pour voir mon diagramme de classe pour c'est classe (il me manque encore la classe ImmobileObject) voir la pièce jointe

    Quelque point :

    J’ai ajouté les fonctions de collision tel que discuté dans le sujet.
    J’ai aussi ajouté les variables pour gérer les positions.
    J’ai aussi ajouter des fonctions de spécifique à un type ( par exemple Catched). Est-ce que c’est correct d’ajouter des fonctions spécifiques à un type ou les 3 classe doivent être strictement identique ?

    Je n’ai pas ajouter toute les fonctions spécifique a chaque type puisque je manquai d’inspiration (d’ailleurs si vous avez des choses à me proposer d’ajouter je suis preneur )

    Encore une fois tout commentaire ou amélioration sera très apprécié.


    J’aurais encore un problème que je n’arrive pas à comprend.
    Comment, vais-je faire, par exemple, pour que si un ennemis est touchée par une balle de feux, il meurt ou bien il pourrait avoir une résistance à cette boule de feu et alors ne rien faire de spécial. Comment gérer des cas spécifique comme celui-ci ?

    De plus, vous m’avez conseillée d’utiliser une fonction react qui sera utilisé lorsque par exemple un personnage saute sur un ennemi mais que celui-ci à des piquants. Cependant, ce que je ne comprends pas c’est que cette fonction react par exemple prendra un peu le rôle de la collision puisque c’est elle qui fera mal au personnage ? A moins que cette fonction ne serve seulement à ne pas faire mal au personnage ? Je ne suis pas sûr de bien expliquer la problématique.

    Et alors je me pose cette question, ou est-ce que je place l’action de blesser un autre objet (ennemis, block, etc) ?

    Ce sont là les interrogations que j’ai et qui me bloque dans l’avancement de mon projet.


    Autre point,
    Pour ce code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    static void detect(FirstType * one, SecondType * second)
             {
                 /*logique de détection de collision */
                /* logique de sélection de priorité */
               sendCollision(mostPriorItem, secondPriorItem);
             }
    Comment est-ce que cela s’appelle dans le code ?
    CollisionDetector<Player, MovableObjet>(object1, object2)

    Aussi , comme sendCollision est une fonction template, je ne devrai pas faire dans le code de detect un autre appele du type :
    sendCollision<Player, MovableObject>(mostPriorItem, secondPriorItem);
    ou il prend les memes type que ceux donner à CollisionDetector

    Mes autres diagrammes de classe sont dans le fichier Join.

    Pour c’est classe :

    StateManager :

    Je me suis fait un stateManager pour gérer les différents écrans du jeu. Cependant je pense les changer pour des singleTon puisque parfois j’ai besoin d’avoir accès à la vrai classe pour pouvoir passez un objet à cette classe (comme un choix de level par exemple)

    RessourceManager :

    Je me suis aussi fait des ressource manager eu aussi singleton, mais en ayant vu votre post je crois les changer pour qu’il soit déclaré dans une classe.

    Voilà pour ma conception et mes problèmes, si vous avez des commentaires ou suggestions ils sont les bienvenue.


    Voilà, grâce à toi, je vais encore me faire taquiner à cause de la longueur de mon poste

    Il n'y a très certainement pas toutes les classes, ni toutes les fonctions, mais tu devrait maintenant avoir une idée globale de la manière dont tout prend sa place
    Merci beaucoup de prendre tout ce temps pour m'aider, c'est vraiment très appréciée. Pour la longueur de votre poste, quand il sont aussi bien fait cela mérite plus des bravos que des taquinerie
    Fichiers attachés Fichiers attachés

  5. #25
    Responsable 2D/3D/Jeux


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

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 060
    Billets dans le blog
    142
    Par défaut
    Moi, je ne vais faire qu'un survol de ce que vous avez fait.
    Pour vos manager, on voit des singletons, si je ne me trompe pas (GetInstance()). Certains diront que le singleton est un anti pattern et qu'il ne doit pas être utilisé. Donc je vous conseille d'être extrêmement prudent.
    Et puis, un singleton hérité ... c'est violent, non ?

    Pour les Manager, il faut aller voir le dernier article d'Emmanuel Deloget

    Je ne vois pas pourquoi le Player n'est pas un MovableObject (ou du moins, un truc movable). Finalement, vous avez fait hérité les Ennemy, du Player, cela est très étrange à dire.
    Je pense qu'il manque toute une partie du coté du diagramme pour les objets. Les objets fixes ? entre autre.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  6. #26
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Mai 2010
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Mai 2010
    Messages : 69
    Par défaut
    Citation Envoyé par LittleWhite Voir le message
    Moi, je ne vais faire qu'un survol de ce que vous avez fait.
    Pour vos manager, on voit des singletons, si je ne me trompe pas (GetInstance()). Certains diront que le singleton est un anti pattern et qu'il ne doit pas être utilisé. Donc je vous conseille d'être extrêmement prudent.
    Et puis, un singleton hérité ... c'est violent, non ?

    Pour les Manager, il faut aller voir le dernier article d'Emmanuel Deloget
    En effet, comme préciser dans mon message mes manager son des singletons, mais je croit que je vais les changer pour des objet normal et les mettre en argument de mes classe. C'est juste que si 2 level utilise les même tile je ne veux pas avoir à les recharger 2 fois parce ma première instance de manager a été supprimer en même temps que mon premier level. C'est principalement pour cela que j'utilisai un singleton.

    Citation Envoyé par LittleWhite Voir le message
    Je ne vois pas pourquoi le Player n'est pas un MovableObject (ou du moins, un truc movable). Finalement, vous avez fait hérité les Ennemy, du Player, cela est très étrange à dire.
    Je pense qu'il manque toute une partie du coté du diagramme pour les objets. Les objets fixes ? entre autre.
    Je l'ai mit dans player, car koala01 l'avait fait ainsi mais je crois effectivement qu'il devrai être placer dans MovableObjet.

    Et oui je n'ai pas encore eu le temps de faire les objets fixes

    Toute remarque, suggestion, amélioration, etc sur la conception présenter dans mon précédant message seront les bienvenues.

    Si vous avez des réponses à mes question aussi, cela m'aidera grandement, car c'est plus sur cela que je bloque pour l'instant

  7. #27
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    Citation Envoyé par marcolo21 Voir le message
    En effet, comme préciser dans mon message mes manager son des singletons, mais je croit que je vais les changer pour des objet normal et les mettre en argument de mes classe. C'est juste que si 2 level utilise les même tile je ne veux pas avoir à les recharger 2 fois parce ma première instance de manager a été supprimer en même temps que mon premier level. C'est principalement pour cela que j'utilisai un singleton.
    De toutes manières, il faut te dire que tu ne chargera qu'un niveau à la fois, et qu'il est beaucoup plus risqué (parce que tu auras "oublié" de vider ton singleton) de se retrouver avec des éléments du niveau précédant dans le niveau actuel que de devoir charger deux fois une ressource quelconque...

    Lorsque tu rend simplement tes gestionnaires membres de Level, et que tu les transmets (sous la forme de référence) aux fonctions / objets qui en ont besoin, tu t'assure que tu n'auras qu'une seule instance de gestionnaire à chaque fois (parce que tu n'aura qu'un seul Level à la fois), ce qui est le principal objectif du singleton


    Je l'ai mit dans player, car koala01 l'avait fait ainsi mais je crois effectivement qu'il devrai être placer dans MovableObjet.
    J'ai, effectivement, très mal nommé cette classe (cela aurait du être proche de "PersonObject"), mais l'idée est vraiment de faire la distinction entre les objets mobiles qui ont une "volonté propre", bref, les "personnages" des objets qui n'en ont pas (de volonté propre),c'est à dire qui se "contentent" de suivre les "lois de la physique" pour leur déplacements.

    Un exemple de Personnage serait la tortue ou le "boss" en fin de niveau, alors qu'un exemple de MovableObject serait un obus ou une carapace de tortue dans laquelle tu aurais shooté.

    Le fait de ne pas considérer les personnages comme des objets mobiles (et donc de créer un type de collision supplémentaire) va t'éviter bien du soucis lorsqu'il sera question de créer tes différents visiteurs et / ou médiateurs :

    Si tu place les personnages dans les objets mobiles, ce n'est pas parce que tu sauras avoir affaire à un objet mobile que tu saura si c'est un personnage ou non!!!

    Si tu décide d'en rajouter un à ta hiérarchie, tu devra donc modifier tous tes visiteurs et médiateurs agissant sur les objets mobiles en leur rajoutant une fonction virtuelle prenant ton nouveau personnage en compte (dont certains qui, à la limite n'en ont rien à foutre du type réel de personnage sur lequel ils agissent!!! )

    Si, par contre, tu place les personnages en dehors de la hiérarchie des "objets mobiles", tu devra, certes, créer des visiteurs / médiateurs qui les prennent spécifiquement en compte, mais tu auras la facilité de pouvoir avoir d'un coté les visiteurs qui n'ont rien à foutre de savoir sur quel type de personnage ils travaillent et d'un autre ceux pour qui le fait de travailler spécifiquement sur Mario ou sur Luiggi a une importance, et tu pourras te "contenter" de ne modifier que cette deuxième catégorie si tu décide de rajouter une classe de personnage!

    (le raisonnement est identique si tu décide de rajouter un type d'objet mobile qui n'est pas personnage )

    Bref, tu gagne en flexibilité, et, bien que tu ne sois pas encore tout à fait dans le respect de OCP, tu t'en approche malgré tout d'avantage que si les personnages font partie de la hiérarchie des objet mobiles.

    De plus, on pourrait alors se demander pourquoi on ne place pas les objet non mobiles dans la même hiérarchie que les objets mobiles, et on en arriverait à créer un "god object" de type Object, regroupant aussi bien les objets immobiles que les objets mobiles (qui contiennent eux même les personnages et le reste des objets mobiles).

    C'est donc un choix délibéré que j'ai clairement expliqué dans mes premières interventions, et c'est, à mon sens, le meilleur (ou du moins le moins mauvais) que l'on puisse envisager

    Par contre, à moins que tu ne veuilles prévoir des comportements spécifiques pour Mario et pour Luiggi (et je ne parle pas "simplement" des sons ou des images à utiliser, car cela peut se gérer simplement en donnant ceux qui conviennent ) je ne suis pas sur qu'il soit vraiment utile de prévoir la distinction...

    Sinon, cela implique que si tu veux par la suite rajouter la petite amie de Mario, tu devra rajouter une classe, alors que si tu en reste à Gamer, sans précision, il te suffira de donner les sons et les images adéquates pour avoir la petite amie de Mario
    Et oui je n'ai pas encore eu le temps de faire les objets fixes

    Si vous avez des réponses à mes question aussi, cela m'aidera grandement, car c'est plus sur cela que je bloque pour l'instant
    J'avais prévu d'essayer d'y répondre hier, mais j'ai été à une conférence sans passer par chez moi, et je n'ai pas eu le courage de le faire après.

    Là, je pars au boulot, mais j'essayerai de le faire en rentrant
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  8. #28
    Expert confirmé
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 526
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 526
    Par défaut
    Citation Envoyé par LittleWhite Voir le message
    N'est ce pas un peu lourd ?

    Dans le sens, vos fonctions sont appelées même si elles ne font rien. On va avoir beaucoup d'objets actifs
    Citation Envoyé par Emmanuel Deloget Voir le message
    Pour le coup, et contrairement à mes saines et figées habitudes, je préconise le contraire : laisser émerger le design à partir des complexités du code initial.
    je suis d'accord

    Citation Envoyé par marcolo21 Voir le message
    1) Les collisions

    J’ai de la difficulté à voir comment je pourrai gérer les collisions. Je sais bien comment savoir si 2 choses ont une collision entre elles, cependant, je ne sais pas comment les faire interagir ensemble.
    Par exemple : le personnage touche un ennemi sur la tête. L’ennemi doit donc mourir, est- ce que je me crée une méthode ‘’Mort()’’ dans chaque classe ennemie que j’appelle lorsqu’il y a eu collision sur le dessus.
    De plus supposions, qu’un ennemi particulier à des piquants sur la tête. Donc quand notre personnage va sauter sur la tête de l’ennemi, il ne doit pas mourir, mais faire mal à notre personnage.
    pour les collisions sans parler de Design Patterns ni de classes d'un point de vue technique il faut tester basiquement si les rectangles dans lesquels les personnages sont contenus sont en intersection.
    Sinon le classique c'est la méthode de Pixel Detection tu compares les pixels qui se confondent mais ça risque d'être long en termes de performances.
    Si tu veux tester au niveau de la tête il faut diviser le rectangle qui contient ton personnage en sous-zones
    C'est une idée parmi d'autres....

    Citation Envoyé par marcolo21 Voir le message
    2) Les items
    Chaque item fait quelque chose de particulier à notre personnage. (Par exemple : fleur permet de lancer des boules de feux, étoile rend invincible, etc)
    Comment gérer cela dans les classes ? Des boolean qui indiquent par exemple s’il est invisible, s’il peut lancer des boules de feux?
    je pense que le mieux c'est d'avoir une classe de base CItem par exemple et de faire hériter des autres types de cette classe de base en reprenant les fonctionnalités de CItem..

    Citation Envoyé par marcolo21 Voir le message
    Cependant, j’ai quelque difficulté à voir comment l’implémenter. Pour l’instant dans mon modèle de personnage, j’ai un statut qui contient par exemple Walking, jumping, falling, etc. Qui signifie l’action que le personnage fait. Dans la vu que vais lire ce statut et afficher l’image en conséquence.
    Est-ce correct de s’y prendre ainsi? Avez-vous de meilleures solutions à proposer ?
    Je ne sais pas si ce MVC est bien adapté;
    il faut que tu gères les états dans une "machine à états" c'est un grand classique de la programmation des JV.
    Par exemple le livre de Buckland "Programmig Game AI by example" aborde ce sujet.
    Chercher dans google Finite State Machine..;
    http://en.wikipedia.org/wiki/Finite-state_machine

  9. #29
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Mai 2010
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Mai 2010
    Messages : 69
    Par défaut
    Citation Envoyé par koala01 Voir le message
    C'est donc un choix délibéré que j'ai clairement expliqué dans mes premières interventions, et c'est, à mon sens, le meilleur (ou du moins le moins mauvais) que l'on puisse envisager
    Je crois effectivement que vous semblez avoir bien réfléchit au probleme et votre approche me semble bonne et pas trop compliquer à utiliser, a par pour certain point.

    Citation Envoyé par koala01 Voir le message
    Par contre, à moins que tu ne veuilles prévoir des comportements spécifiques pour Mario et pour Luiggi (et je ne parle pas "simplement" des sons ou des images à utiliser, car cela peut se gérer simplement en donnant ceux qui conviennent ) je ne suis pas sur qu'il soit vraiment utile de prévoir la distinction...
    En faite j'aimerai ajouter aussi Wario et donc quand il attaque et tous le reste est assez différent de mario. C'est pour cela que j'ai fait différente classe

    Citation Envoyé par koala01 Voir le message
    Là, je pars au boulot, mais j'essayerai de le faire en rentrant
    Merci beaucoup, j'attend votre intervention avec impatience


    Je ne sais pas si ce MVC est bien adapté;
    il faut que tu gères les états dans une "machine à états" c'est un grand classique de la programmation des JV.
    Par exemple le livre de Buckland "Programmig Game AI by example" aborde ce sujet.
    Chercher dans google Finite State Machine..;
    http://en.wikipedia.org/wiki/Finite-state_machine
    J'ai regarder un peut sur google et cela semble beaucoup ressembler a ma classe StateManager(présenter dans ma conception dans le fichier joint de mon précédant message) pour gérer les différents écran d'un jeu.

    Cependant je ne sait pas comment je pourrais utilisé une classe semblable pour savoir qu'est-ce que j'affiche dans ma view. Pour l'instant j'ai un statue dans mon model qui est par exemple: Running, jumping, falling, walking, etc. qui représente les différentes action de mon personnage et dans ma view je fait un switch/case et j'affiche l'animation correspondante.

    Est-ce une bonne méthode selon vous ? Si non, que me proposeriez-vous ?

  10. #30
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 288
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Mat.M Voir le message
    Je ne sais pas si ce MVC est bien adapté;
    Effectivement. Après un cuisant échec, je suis aujourd'hui persuadé que le MVC n'est du tout adapté au dev d'un jeu vidéo.

    Aujourd'hui, je suis parvenu à la quasi-certitude que le meilleur modèle reste le client/serveur (même si on reste toujours en local, si la communication entre le client et serveur ne se fait pas par le biais d'un protocole réseau).
    Un bon exemple: l'architecture de quake II.

    Ensuite, attends-toi a avoir devoir gérer des états, beaucoup d'états, différents, voire antagonistes. Tu peux regarder mon article sur le D.P. State, mais sincèrement je le trouve de plus en plus médiocre. A la limite, il vaudrait mieux prendre une lib qui implémente une machine à état (au hasard, celle de boost), et de jouer avec pour bien appréhender les possibilité qu'elle offre avant de l'utiliser dans ton code. Attention, l'implémentation et l'utilisation d'une machine à été, fut-elle finie, n'est pas aussi simple qu'il n'y parait.

  11. #31
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    Citation Envoyé par r0d Voir le message
    Attention, l'implémentation et l'utilisation d'une machine à été, fut-elle finie, n'est pas aussi simple qu'il n'y parait.
    Encore moins le premier jour de l'automne

    Bon,
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  12. #32
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Mai 2010
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Mai 2010
    Messages : 69
    Par défaut
    Bonjour,

    @koala01

    J'ai toujours quelque problème à m'imaginer certaine chose, même après y avoir réfléchit.

    Je me permet de remettre les questions d'un de mes ancien poste qui ne sont pas réglée dans mon cas.

    En faite ce sont plus des situation, que j'aimerai que vous m'expliquer comment vous règleriez cela.

    Comment, vais-je faire, par exemple, pour que si un ennemis est touchée par une balle de feux, il meurt ou bien il pourrait avoir une résistance à cette boule de feu et alors ne rien faire de spécial. Comment gérer des cas spécifique comme celui-ci ?

    De plus, vous m’avez conseillée d’utiliser une fonction react(mais que passé à react ? un des 3 type d'objet?) qui sera utilisé lorsque par exemple un personnage saute sur un ennemi mais que celui-ci à des piquants. Cependant, ce que je ne comprends pas c’est que cette fonction react par exemple prendra un peu le rôle de la collision puisque c’est elle qui fera mal au personnage ? A moins que cette fonction ne serve seulement à ne pas faire mal au personnage ? Je ne suis pas sûr de bien expliquer la problématique.

    Et alors je me pose cette question, ou est-ce que je place l’action de blesser un autre objet (ennemis, block, etc) ?

    Voici une situation pour mieux comprendre:

    Prenons l'exemple de mon personnage(Mario). Il saute sur un ennemis tu la tête. Cependant, cet ennemis possède des piquants sur le dessus et donc c'est a moi de me faire mal. Comment gérer un cas spécifique comme celui-ci ?

    Finalement, auriez-vous une meilleur idée qu'un énumération pour savoir si la collision c'est passé sur le dessus, dessous, gauche, droite ??? (Ma problématique dans ce cas la va être de déterminée le sens de la collision)

    Ce sont là les interrogations que j’ai et qui me bloque dans l’avancement de mon projet. Après cela, je pourrait avancer rapidement dans mon développement.

    Merci beaucoup

    Ps: En pièce jointe les classes d'objet ( fortement inspiré ce de sujet). Bien sur rien n'est parfait encore. Le reste évoluera lorsque je programmerai.
    Images attachées Images attachées  

  13. #33
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Mai 2010
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Mai 2010
    Messages : 69
    Par défaut
    Bonjour tout le monde,

    Tout d'abord désolez de remonter ce topic, mais je suis rendu à la partie ou je dois coder les collisions et j’ai un problème.
    J’essaie de coder la class collision un très inspiré de celle présentée par Koala01.

    Voici le code :

    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    #ifndef COLLISION_H_INCLUDED
    #define COLLISION_H_INCLUDED
     
    #include "ECollisionType.h"
     
    /*#include "IntelligentObject.h"
    #include "MovableObject.h"
    #include "ImmobileObject.h"*/
     
    template <typename FirstType, typename SecondType = FirstType>
    class Collision
    {
        public:
     
            Collision(FirstType* f, SecondType* s):m_First(f), m_Second(s)
            {
            }
     
            FirstType* First()
            {
                return m_First;
            }
     
            SecondType* Second()
            {
                return m_Second;
            }
     
            CollisionType::ECollisionType CollisionTypeFirst()
            {
                return m_CollisionTypeFirst;
            }
     
            CollisionType::ECollisionType CollisionTypeSecond()
            {
                return m_CollisionTypeSecond;
            }
     
            void Transmit()
            {
                DoTransmit();
            }
     
        protected:
     
            //Virtual Function
            virtual void DoTransmit()
            {
                m_First->Collide(this);
                m_Second->Collisde(this);
            }
     
            //Member
     
            FirstType* m_First;
            SecondType* m_Second;
     
            CollisionType::ECollisionType m_CollisionTypeFirst;
            CollisionType::ECollisionType m_CollisionTypeSecond;
    };
     
     
    /*typedef Collision<IntelligentObject> CollisionTwoIntelligentObject;
    typedef Collision<IntelligentObject, MovingObject> CollisionIntelligentMovableObject;
    typedef Collision<IntelligentObject, ImmobileObject> CollisionIntelligentImmobileObject;
     
    typedef Collision<MovingObject> CollisionTwoMovableObject;
    typedef Collision<MovingObject, ImmobileObject> CollisionMovableImmobileObject;*/
     
    #endif
    La class en tant que tel ne pose pas de problème. Le problème est lorsque je veux créer ma fonction Colide comme koala avait fait dans un de ses premiers postes de la façon suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void collide(Collision * col)
            {
                doCollide( *col);
            }
    Le problème c’est que je ne peux pas me crée un pointeur de cette façon, le compilateur me demande de lui donner le type c'est-à-dire l’écrire sous cette forme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void collide(Collision<IntelligentObject>* col)
            {
                doCollide( *col);
            }
    En faisant cela, je perds toute le cotée dynamique avec les doColide.
    J’ai remarqué que Koala01 avait utilisé 2 classes pour ça (Colision et TColision). Mon problème est que dans le code qu’il a montré dans le premier message, est-ce que TColision hérite de collision. Aussi, si je passe un pointeur Colision je n’aurai pas accès aux méthodes first et second puisqu’ils sont déclarés dans TColision et non dans Colision.

    Aussi un autre problème, j’ai mes typedef dans un fichier comme montré dans le premier message:

    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
    #ifndef TYPEDEFCOLLISION_H_INCLUDED
    #define TYPEDEFCOLLISION_H_INCLUDED
     
    #include "Collision.h"
    #include "IntelligentObject.h"
    #include "MovableObject.h"
    #include "ImmobileObject.h"
     
    typedef Collision<IntelligentObject> CollisionTwoIntelligentObject;
    typedef Collision<IntelligentObject, MovingObject> CollisionIntelligentMovableObject;
    typedef Collision<IntelligentObject, ImmobileObject> CollisionIntelligentImmobileObject;
     
    typedef Collision<MovingObject> CollisionTwoMovableObject;
    typedef Collision<MovingObject, ImmobileObject> CollisionMovableImmobileObject;
     
    #endif
    Cependant je ne sais pas où les placers puisque je dois inclure tous les types d’objet pour pouvoir déclarer mes typedef, mais après quand je l’inclue par exemple dans ma classe IntelligentObject, j’ai des problèmes de compilation comme si j’aurai des inclusions multiples (malgré les ifndef dans mes fichiers).


    Auriez-vous une solution pour pouvoir régler mes 2 problèmes ? Peut-être que Koala01 s’il passe par ici pourra expliquer comment marchent ses codes.

    Merci beaucoup

  14. #34
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    Tu as oublié de faire hériter ta collision template d'un type non template "collision"...

    Il faut comprendre que tel que tu as codé collision Collision<Truc, Machin> n'a strictement rien à voir avec TCollision<Machin, Bidule> en terme de hiérarchie de classe (ce sont deux types totalement différents qui ont "simplement" une interface commune, et qui réagissent potentiellement de la même manière).

    Lorsque tu réfléchis aux différentes combinaisons possibles de collision, tu te rend compte qu'il y en a un certain nombre:
    1. joueur avec joueur
    2. joueur avec objet mobile
    3. joueur avec objet fixe
    4. objet mobile avec objet mobile
    5. objet mobile avec objet fixe
    6. (un objet fixe n'a aucune chance d'entrer en collision avec un autre objet fixe )
    L'approche Orientée Objets classique t'aurais amené à créer une classe Collision de base puis à faire hériter cinq classes (une par type de collision potentielle) et à dupliquer autant de fois le même code d'implémentation des fonctions virtuelles car la collision en elle meme réagit de manière strictement identique quelle que puisse etre le type des objets qui entre en collision: elle appelle une méthode clairement définie sur le premier objet de la collision puis appelle exactement la même méthode sur le deuxième objet de la collision.

    Or, un bon programmeur est un programmeur fainéant, qui va tout faire pour que le compilateur en fasse un maximum pour lui et pour écrire le moins de code possible, et on entre donc tout à fait dans la définition du paradigme générique :
    on ne sait pas encore quel sera le type des objets que l'on va manipuler, mais on sait par contre parfaitement la manière dont on va les manipuler.
    Or, on veut profiter du polymorphisme (au sens Orienté Objets du terme) pour n'importe quel type de collision !

    Il faut donc faire en sorte d'avoir un type de base unique pour n'importe quel type de collision susceptible d'être généré de manière automatique par le compilateur.

    Pour obtenir ce résultat, c'est tout simple : on crée une classe (non template) de base, qui implémente le NVI sous une forme proche de
    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 Collision
    {
        public:
            void collide(){doCollide();}
            virtual ~Collision(){}
            /* en C++11, on peut interdire la copie et l'affectation sous cette forme
             */
           Collision(Collision const &) = delete;
           Collision & operator = (Collision const &) = delete;
        private:
            virtual void doCollide(){/* ne fait rien à la base;}
            /* mais pour interdire la copie et l'affectation en C++ d'avant, il faut
             * déclarer le opérateur d'affectation et le constructeur par copie
             * privé et ne surtout pas les définir
             */
           Collision(Collision const &);
           Collision & operator = (Collision const &);
    };
    puis on fait hériter une classe (template) TCollision de cette classe de base, de manière à ce que quels que soient les paramètres template utilisés, la classe résultante dispose de la même classe de base, sous une forme proche de
    template <typename T1 , typename T2 /* = T1 */ >
    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 TCollision
    {
        public :
            /* simplement pour pouvoir récupérer le type des deux objets en
             * présence
             */
           typedef T1 * first_type_ptr;
           typedef T2 * second_type_ptr;
           TCollision(T1 * f, T2 s):first_(f), second_(s){}
        private:
           T1* first_;
           T2* second_;
           /* la spécialisation de NVI */
          virtual void doCollide()
          {
              first_->react(*this);
              second_->react(*this);
          }
    };
    Du coup, pour générer les cinq types de collision potentiel, "YAPUKA" définir les alias de types correspondants:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    typedef TCollision<IntelligentObject> CollisionTwoIntelligentObject;
    typedef TCollision<IntelligentObject, MovingObject> CollisionIntelligentMovableObject;
    typedef TCollision<IntelligentObject, ImmobileObject> CollisionIntelligentImmobileObject;
     
    typedef TCollision<MovingObject> CollisionTwoMovableObject;
    typedef TCollision<MovingObject, ImmobileObject> CollisionMovableImmobileObject;
    Et tout ira pour le mieux :d
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  15. #35
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Mai 2010
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Mai 2010
    Messages : 69
    Par défaut
    Bonjour Koala01,

    J'ai toujours un petit problème avec mes collisions.

    Je vous montre le code et ensuite je vais expliquer mon problème.

    Classe Collision:

    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
    #ifndef COLLISION_H_INCLUDED
    #define COLLISION_H_INCLUDED
     
    #include "ECollisionType.h"
     
    class Collision
    {
        public:
     
            void Transmit()
            {
                DoTransmit();
            }
     
        protected:
     
            //Virtual Function
            virtual void DoTransmit()
            {
            }
    };
     
     
    #endif
    Classe TCollision:

    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    #ifndef TCOLLISION_H_INCLUDED
    #define TCOLLISION_H_INCLUDED
     
    #include "Collision.h"
    #include "ECollisionType.h"
     
    template <typename FirstType, typename SecondType = FirstType>
    class TCollision : public Collision
    {
        public:
     
            TCollision(FirstType* f, SecondType* s):m_First(f), m_Second(s)
            {
            }
     
            FirstType* First()
            {
                return m_First;
            }
     
            SecondType* Second()
            {
                return m_Second;
            }
     
            CollisionType::ECollisionType CollisionTypeFirst()
            {
                return m_CollisionTypeFirst;
            }
     
            CollisionType::ECollisionType CollisionTypeSecond()
            {
                return m_CollisionTypeSecond;
            }
     
        protected:
     
            //Virtual Function
            virtual void DoTransmit()
            {
                m_First->Collide(this);
                m_Second->Collisde(this);
            }
     
            //Member
     
            FirstType* m_First;
            SecondType* m_Second;
     
            CollisionType::ECollisionType m_CollisionTypeFirst;
            CollisionType::ECollisionType m_CollisionTypeSecond;
    };
     
    #endif
    Les typedef :
    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
    #ifndef TYPEDEFCOLLISION_H_INCLUDED
    #define TYPEDEFCOLLISION_H_INCLUDED
     
    #include "TCollision.h"
    /*#include "IntelligentObject.h"
    #include "MovableObject.h"
    #include "ImmobileObject.h"*/
     
    class IntelligentObject;
    class ImmobileObject;
    class MovingObject;
     
    typedef TCollision<IntelligentObject> CollisionTwoIntelligentObject;
    typedef TCollision<IntelligentObject, MovingObject> CollisionIntelligentMovableObject;
    typedef TCollision<IntelligentObject, ImmobileObject> CollisionIntelligentImmobileObject;
     
    typedef TCollision<MovingObject> CollisionTwoMovableObject;
    typedef TCollision<MovingObject, ImmobileObject> CollisionMovableImmobileObject;
     
    #endif
    La classe IntelligentObject:

    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    #ifndef INTELLIGENTOBJECT_H_INCLUDED
    #define INTELLIGENTOBJECT_H_INCLUDED
     
    /*#include "ReactObject.h"
    #include "Collision.h"*/
     
     
    /*class CollisionTwoIntelligentObject;
    class CollisionIntelligentMovableObject;
    class CollisionIntelligentImmobileObject;*/
     
    //class CollisionTwoMovableObject;
    //class CollisionMovableImmobileObject;
     
    #include "TypeDefCollision.h"
     
    namespace IntelligentObjectType
    {
        enum EIntelligentObjectType
        {
            None,
            Character,
            Enemy,
            Count
        };
    }
     
    ///////////////////////////////////////////////////////////////////////////////////
    //Base Interface Class for every intelligent Object (Character, ennemy, etc)
    ///////////////////////////////////////////////////////////////////////////////////
     
    class IntelligentObject
    {
        public:
     
            IntelligentObject() : m_X(0), m_Y(0), m_Width(0), m_Height(0), m_Speed(0.f), m_AccelerationX(0.f), m_AccelerationY(0.f), m_Score(100), m_IsVisible(true), m_Type(IntelligentObjectType::None)
            {
            }
     
            IntelligentObject(IntelligentObjectType::EIntelligentObjectType type) : m_X(0), m_Y(0), m_Width(0), m_Height(0), m_Speed(0.f), m_AccelerationX(0.f), m_AccelerationY(0.f), m_Score(100), m_IsVisible(true), m_Type(type)
            {
            }
     
            //Pure virtual function to prevent to instanciate it
            virtual ~IntelligentObject()
            {
            }
     
            //The function that will be call by the collision system
            void Collide(Collision* col)
            {
                DoCollide(*col);
                //DoCollide(*col);
            }
            /*
            void React(ReactObject* obj)
            {
                DoReact(*obj);
            }*/
     
            void Update(float elapsedTime)
            {
                DoUpdate(elapsedTime);
            }
     
            virtual void Hurt(){}
     
     
            int GetX() const
            {
                return m_X;
            }
     
            int GetY() const
            {
                return m_Y;
            }
     
            int GetWidth() const
            {
                return m_Width;
            }
     
            int GetHeight() const
            {
                return m_Height;
            }
     
            float GetSpeed() const
            {
                return m_Speed;
            }
     
            float GetAccelerationX() const
            {
                return m_AccelerationX;
            }
     
            float GetAccelerationY() const
            {
                return m_AccelerationY;
            }
     
            int GetScore() const
            {
                return m_Score;
            }
     
            bool IsVisible() const
            {
                return m_IsVisible;
            }
     
            void SetVisible(bool visible)
            {
                m_IsVisible = visible;
            }
     
            void SetX(int x)
            {
                m_X = x;
            }
     
            void SetY(int y)
            {
                m_Y = y;
            }
     
            void SetPosition(int x, int y)
            {
                m_X = x;
                m_Y = y;
            }
     
            void SetWidth(int width)
            {
                m_Width = width;
            }
     
            void SetHeight(int height)
            {
                m_Height = height;
            }
     
            void SetSpeed(float speed)
            {
                m_Speed = speed;
            }
     
            void SetAccelerationX(float accelerationX)
            {
                m_AccelerationX = accelerationX;
            }
     
            void SetAccelerationY(float accelerationY)
            {
                m_AccelerationY = accelerationY;
            }
     
            void SetScore(int score)
            {
                m_Score = score;
            }
     
            IntelligentObjectType::EIntelligentObjectType GetType() const
            {
                return m_Type;
            }
     
        protected:
     
            //Protected function
            virtual void DoCollide(CollisionTwoIntelligentObject& col){}
            virtual void DoCollide(CollisionIntelligentMovableObject& col){}
            virtual void DoCollide(CollisionIntelligentImmobileObject& col){}
            //virtual void DoCollide(CollisionTwoMovableObject& col){}
            //virtual void DoCollide(CollisionMovableImmobileObject& col){}
            /*
            virtual void DoReact(ReactIntelligentObject& reaction){}
            virtual void DoReact(ReactMovableObject& reaction){}
            virtual void DoReact(ReactImmobileObject){}*/
     
     
            virtual void DoUpdate(float elapsedTime){}
     
     
            //Member
            int m_X;
            int m_Y;
            int m_Width;
            int m_Height;
            float m_Speed;
            float m_AccelerationX;
            float m_AccelerationY;
            int m_Score;
            bool m_IsVisible;
            IntelligentObjectType::EIntelligentObjectType m_Type;
     
    };
     
    #endif
    Petite précision :
    Dans le Fichier Typedef. J'ai mit

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class IntelligentObject;
    class ImmobileObject;
    class MovingObject;
    Car si je mettais les includes des classes direct j'avais des problèmes quand j'incluai ce fichier dans intelligentObject par exemple. Je ne sais pas si c'est correcte de faire ça ainsi.


    Mon probème ce trouve dans la fonction Colide de la classe intelligentObject.

    L'erreur que j'obtient est :
    In member function 'void IntelligentObject::Collide(Collision*)':|
    error: no matching function for call to 'IntelligentObject::DoCollide(Collision&)'|
    note: candidates are: virtual void IntelligentObject::DoCollide(CollisionTwoIntelligentObject&)|
    note: virtual void IntelligentObject::DoCollide(CollisionIntelligentMovableObject&)|
    note: virtual void IntelligentObject::DoCollide(CollisionIntelligentImmobileObject&)|
    ||=== Build finished: 1 errors, 0 warnings ===|
    Comment puis-je fait pour corriger cette erreur ?

    Merci beaucoup

  16. #36
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Mai 2010
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Mai 2010
    Messages : 69
    Par défaut
    Bonjour,

    Est-ce que je devrais utiliser les dynamic_cast pour corriger ce problème ?

    Comme ça :

    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
            void Collide(Collision* col)
            {
                CollisionTwoIntelligentObject* twoIntelligent = 0;
                CollisionIntelligentMovableObject* intelligentMovable = 0;
                CollisionIntelligentImmobileObject* intelligentImmobile = 0;
     
                if((twoIntelligent = dynamic_cast<CollisionTwoIntelligentObject*>(col)))
                {
                    DoCollide(*twoIntelligent);
                }
                else if((intelligentMovable = dynamic_cast<CollisionIntelligentMovableObject*>(col)))
                {
                    DoCollide(*intelligentMovable);
                }
                else if((intelligentImmobile = dynamic_cast<CollisionIntelligentImmobileObject*>(col)))
                {
                    DoCollide(*intelligentImmobile);
                }
     
            }
    Cependant, dynamic_cast semble toujours me retourné NULL même si l'objet est effectivement un CollisionIntelligentImmobileObject par exemple.

    merci

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


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

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 060
    Billets dans le blog
    142
    Par défaut
    En théorie, nous devons éviter les cast. Si je me rappelle bien, les dynamic_cast provoque le parcours de la table virtuelle (table d'héritage) afin de savoir si le cast est bien possible. Cela peut facilement prendre du temps et est donc à éviter dans le code critique (tel que la vérification de collision).

    Avec la fonction suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     // The function that will be call by the collision system
            void Collide(Collision* col)
            {
                DoCollide(*col);
                //DoCollide(*col);
            }
    Vous devriez être capable de l'appeler directement avec votre col, donc il ne devrait pas y avoir de cast explicite.
    Mais peut être que je me trompe...
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  18. #38
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    Rajoute un destructeur virtuel public dans la classe Collision.

    Tu en auras de toutes manières besoin, vu qu'il faudra bien détruire la collision une fois qu'elle aura rempli son office et que tu ne saura pas quel est son type réel, et j'ai pu remarquer que cela aidait bien souvent le compilateur à prendre en compte l'héritage (bien que la seule présence d'une fonction virtuelle devrait normalement suffir )

    autre chose : Que font ces deux lignes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
            CollisionType::ECollisionType m_CollisionTypeFirst;
            CollisionType::ECollisionType m_CollisionTypeSecond;
    Ce qu'il te faut, c'est un typedef public sur chaque type template, histoire de savoir quel est le type des objets qui entrent en collision :
    template <typename FirstType, typename SecondType = FirstType>
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class TCollision : public Collision
    {
        public:
        typedef FirstType first_type;
        typedef SecondType second_type;
       /* la suite
    };
    Ce qui, avec une collision de type connu te permet de faire un coll:first_type * ptr=col.getFirst();
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  19. #39
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Mai 2010
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Mai 2010
    Messages : 69
    Par défaut
    Bonjour,

    Toujours le même problème. Il ne semble pas être capable de ramener le type Collision (classe mère) en type TCollision (classe fille). Je suis un peut bloqué là.

    Je vous remet mon code:

    Classe Collision:

    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
    29
    30
    31
    #ifndef COLLISION_H_INCLUDED
    #define COLLISION_H_INCLUDED
     
    #include "ECollisionType.h"
     
    class Collision
    {
        public:
     
            void Transmit()
            {
                DoTransmit();
            }
     
            virtual ~Collision()
            {
            }
     
        protected:
     
            //Virtual Function
            virtual void DoTransmit()
            {
            }
     
            Collision(Collision const&);
            Collision& operator = (Collision const&);
    };
     
     
    #endif
    Classe TCollision:

    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    #ifndef TCOLLISION_H_INCLUDED
    #define TCOLLISION_H_INCLUDED
     
    #include "Collision.h"
    #include "ECollisionType.h"
     
    template <typename FirstType, typename SecondType = FirstType>
    class TCollision : public Collision
    {
        public:
     
            typedef FirstType First_Type;
            typedef SecondType Second_Type;
     
            TCollision(FirstType* f, SecondType* s):m_First(f), m_Second(s)
            {
            }
     
            virtual ~TCollision()
            {
            }
     
            FirstType* First()
            {
                return m_First;
            }
     
            SecondType* Second()
            {
                return m_Second;
            }
     
            CollisionType::ECollisionType CollisionTypeFirst()
            {
                return m_CollisionTypeFirst;
            }
     
            CollisionType::ECollisionType CollisionTypeSecond()
            {
                return m_CollisionTypeSecond;
            }
     
        protected:
     
            //Virtual Function
            virtual void DoTransmit()
            {
                m_First->Collide(this);
                m_Second->Collisde(this);
            }
     
            //Member
     
            FirstType* m_First;
            SecondType* m_Second;
     
            CollisionType::ECollisionType m_CollisionTypeFirst;
            CollisionType::ECollisionType m_CollisionTypeSecond;
    };
     
    #endif
    TypeDef Collision:

    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
    #ifndef TYPEDEFCOLLISION_H_INCLUDED
    #define TYPEDEFCOLLISION_H_INCLUDED
     
    #include "TCollision.h"
     
    class IntelligentObject;
    class ImmobileObject;
    class MovingObject;
     
    typedef TCollision<IntelligentObject> CollisionTwoIntelligentObject;
    typedef TCollision<IntelligentObject, MovingObject> CollisionIntelligentMovableObject;
    typedef TCollision<IntelligentObject, ImmobileObject> CollisionIntelligentImmobileObject;
     
    typedef TCollision<MovingObject> CollisionTwoMovableObject;
    typedef TCollision<MovingObject, ImmobileObject> CollisionMovableImmobileObject;
     
    #endif
    Classe intelligent Object:

    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    #ifndef INTELLIGENTOBJECT_H_INCLUDED
    #define INTELLIGENTOBJECT_H_INCLUDED
     
    #include "EObjectType.h"
     
    #include "TypeDefCollision.h"
     
    namespace IntelligentObjectType
    {
        enum EIntelligentObjectType
        {
            None,
            Character,
            Enemy,
            Count
        };
    }
     
    ///////////////////////////////////////////////////////////////////////////////////
    //Base Interface Class for every intelligent Object (Character, ennemy, etc)
    ///////////////////////////////////////////////////////////////////////////////////
     
    class IntelligentObject
    {
        public:
     
            IntelligentObject() : m_X(0), m_Y(0), m_Width(0), m_Height(0), m_Speed(0.f), m_MaxSpeed(0.f), m_AccelerationX(0.f), m_AccelerationY(0.f), m_Score(100), m_IsVisible(true), m_Type(IntelligentObjectType::None)
            {
            }
     
            IntelligentObject(IntelligentObjectType::EIntelligentObjectType type) : m_X(0), m_Y(0), m_Width(0), m_Height(0), m_Speed(0.f), m_MaxSpeed(0.f), m_AccelerationX(0.f), m_AccelerationY(0.f), m_Score(100), m_IsVisible(true), m_Type(type)
            {
            }
     
            //Pure virtual function to prevent to instanciate it
            virtual ~IntelligentObject()
            {
            }
     
            //The function that will be call by the collision system
            void Collide(Collision* col)
            {
                DoCollide(*col);
            }
            /*
            void React(ReactObject* obj)
            {
                DoReact(*obj);
            }*/
     
            void Update(float elapsedTime)
            {
                DoUpdate(elapsedTime);
            }
     
            virtual void Hurt(){}
     
     
            float GetX() const
            {
                return m_X;
            }
     
            float GetY() const
            {
                return m_Y;
            }
     
            int GetWidth() const
            {
                return m_Width;
            }
     
            int GetHeight() const
            {
                return m_Height;
            }
     
            float GetSpeed() const
            {
                return m_Speed;
            }
     
            float GetAccelerationX() const
            {
                return m_AccelerationX;
            }
     
            float GetAccelerationY() const
            {
                return m_AccelerationY;
            }
     
            int GetScore() const
            {
                return m_Score;
            }
     
            bool IsVisible() const
            {
                return m_IsVisible;
            }
     
            void SetVisible(bool visible)
            {
                m_IsVisible = visible;
            }
     
            void SetX(float x)
            {
                m_X = x;
            }
     
            void SetY(float y)
            {
                m_Y = y;
            }
     
            void SetPosition(int x, int y)
            {
                m_X = x;
                m_Y = y;
            }
     
            void SetWidth(int width)
            {
                m_Width = width;
            }
     
            void SetHeight(int height)
            {
                m_Height = height;
            }
     
            void SetSpeed(float speed)
            {
                m_Speed = speed;
            }
     
            void SetAccelerationX(float accelerationX)
            {
                m_AccelerationX = accelerationX;
            }
     
            void SetAccelerationY(float accelerationY)
            {
                m_AccelerationY = accelerationY;
            }
     
            void SetScore(int score)
            {
                m_Score = score;
            }
     
            IntelligentObjectType::EIntelligentObjectType GetType() const
            {
                return m_Type;
            }
     
            float GetMaxSpeed() const
            {
                return m_MaxSpeed;
            }
     
            void SetMaxSpeed(float speed)
            {
                m_MaxSpeed = speed;
            }
     
            BaseObjectType::EBaseObjectType GetBaseType() const
            {
                return BaseObjectType::IntelligentObjectType;
            }
     
        protected:
     
            //Protected function
            virtual void DoCollide(CollisionTwoIntelligentObject& col){}
            virtual void DoCollide(CollisionIntelligentMovableObject& col){}
            virtual void DoCollide(CollisionIntelligentImmobileObject& col){}
            //virtual void DoCollide(CollisionTwoMovableObject& col){}
            //virtual void DoCollide(CollisionMovableImmobileObject& col){}
            /*
            virtual void DoReact(ReactIntelligentObject& reaction){}
            virtual void DoReact(ReactMovableObject& reaction){}
            virtual void DoReact(ReactImmobileObject){}*/
     
     
            virtual void DoUpdate(float elapsedTime){}
     
     
            //Member
            float m_X;
            float m_Y;
            int m_Width;
            int m_Height;
            float m_Speed;
            float m_MaxSpeed;
            float m_AccelerationX;
            float m_AccelerationY;
            int m_Score;
            bool m_IsVisible;
            IntelligentObjectType::EIntelligentObjectType m_Type;
     
    };
     
    #endif

    Et l'erreur qu'il me donne toujours :

    ||=== Projet_Jeu, Debug ===|
    |In member function 'void IntelligentObject::Collide(Collision*)':|
    |60|error: no matching function for call to 'IntelligentObject::DoCollide(Collision&)'|
    |195|note: candidates are: virtual void IntelligentObject::DoCollide(CollisionTwoIntelligentObject&)|
    |196|note: virtual void IntelligentObject::DoCollide(CollisionIntelligentMovableObject&)|
    |197|note: virtual void IntelligentObject::DoCollide(CollisionIntelligentImmobileObject&)|
    ||=== Build finished: 1 errors, 0 warnings ===|
    Auriez-vous une idée ?

    autre chose : Que font ces deux lignes

    CollisionType::ECollisionType m_CollisionTypeFirst;
    CollisionType::ECollisionType m_CollisionTypeSecond;
    Ces deux lignes me servent pour savoir quel partie de l'objet à été collisionné. C'est en faite un enum ( haut, bas, gauche, droite). Comme je n'ai pas trouvé de meilleur solution, j'ai décider d'y aller ainsi.
    J'en ais de besoin puisque dans un Mario, on ne réagit pas pareil selon la place ou on a été frappé.

Discussions similaires

  1. Conception d'un jeu de tennis
    Par b Oo dans le forum Développement 2D, 3D et Jeux
    Réponses: 5
    Dernier message: 17/01/2007, 22h19
  2. Difference dates et questions conception
    Par lolo_bob2 dans le forum Modélisation
    Réponses: 2
    Dernier message: 23/11/2006, 13h23
  3. Conception d'un jeu de course
    Par zooffy dans le forum Développement 2D, 3D et Jeux
    Réponses: 5
    Dernier message: 03/11/2006, 19h29
  4. [Conception] Concevoir le jeu Pierre Feuille Ciseau
    Par websurfeur dans le forum Général Java
    Réponses: 14
    Dernier message: 17/03/2006, 19h26
  5. [VB] Aide pour la conception d'un jeu
    Par superbruno dans le forum VB 6 et antérieur
    Réponses: 12
    Dernier message: 17/01/2006, 18h01

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