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 :

conception et programmation ECS


Sujet :

C++

  1. #1
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2014
    Messages
    521
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2014
    Messages : 521
    Points : 136
    Points
    136
    Par défaut conception et programmation ECS
    Bonjour.

    Après une discussion avec entre autre, Koala, je me suis laissé convaincre qu'il fallait repenser mon programme, et m'orienter vers le ECS, apparemment bien adapté pour le jeu vidéo ( mon projet est de faire un STR en 2D avec la SFML ).

    Avant de me lancer définitivement, j'aimerais vous exposer la façon dont je vais procéder afin de soumettre celle ci à vos critiques, pour prendre du recul et orienter au mieux mon programme dès le début.

    voici comment je compte procéder ( dans les grandes lignes ) :


    -une class Game va contenir l'Engine, les Systemes, et les Resources. Elle aura pour but de charger les niveaux, en lisant les fichiers sur le disque dur pour créer tous les systèmes et objets nécessaires à la scène.

    -une class Engine, va récupérer tous les systèmes utilisés et les updater continuellement, en veillant à lier les modules quand il le faut.

    -des class System, polymorphique, contiendront à la base un multimap avec le numéro de l'objet, et le module qu'elles manipulent. ( un Graphics, collision etc... ) . ils seraient des unique_ptr dans un vector contenue dans Game/Engine .

    -une class Data, contient les donnés fondamentales de chaque objet ( son nom, sa position, etc...), et sera utilisable dans chaque module. ( en outre, un module "Graphics", par ex, aura une référence/ptr data auquel il aura accès lors de l'update : ainsi si le module Physics bouge l'objet, le module Graphics, lors de l'update, le repositionnera automatiquement ).

    Mes interrogations sont les suivantes :

    _est-ce une bonne idée d'utiliser l'héritage pour les systèmes ( selon vous ) ? Et si oui, allier cela avec des templates serait-il chose à faire ?

    _utiliser un Data pour chaque module est-il là aussi une idée valable ?

    Il y a évidement une infinité d'autres interrogations, mais ce sont les premières qui me viennent...

    Merci si vous pouvez commenter, proposer, orienter etc...la conception

  2. #2
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2014
    Messages
    521
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2014
    Messages : 521
    Points : 136
    Points
    136
    Par défaut
    Voici la class Game, qui récupère la fenêtre et le contrôle du temps depuis le main :

    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
     
     
    class Game
    {
    public :
     
        Game( sf::RenderWindow& window , bool& time ) ;
        ~Game() ;
     
        void                                                         load() ; //lit depuis le disque dur tous les objets à construire avec build.
        void                                                         build( std::string name , float x , float y ) ; //construit un objet depuis le disque
        void                                                         play() ; //fait tourné l'engine avec ts les systèmes nécessaire
     
        std::unique_ptr < System >                                   getSystem( std::string name ) ; // construit et ajoute un system pour le niveau
     
    private :
     
        sf::RenderWindow                                              &_window ; //pour l'ajouter aux systèmes qui en auront besoin, comme Graphics
        Engine                                                        _engine ;
        Resources                                                     _resources ; // contient tout le package ( textures etc...) chargé, sinon le charge 
        std::vector < std::unique_ptr < System > >                    _system ;//la class mère de tous les systèmes.
        std::vector < Data >                                          _data ; //contient les données de base d'un objet.
        size_t                                                        _number ; //le numér implémentable de chaque objet...
        bool&                                                         _time ;//un repère de temps donné depuis le main (1/16s , pour l'animation etc...)
     
     
    };
    voici le Data, contenue donc en vector dans le Game, qui est voué à être utilisé en référence dans pas mal d'entités, ( comme ici plus loin le graphics ) :

    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 Data
    {
    public :
     
        Data( bool& time ) : _time ( time ) {}
        ~Data(){}
     
        void                                                    setNumber ( const size_t number ) { _number = number ; }
        const size_t                                            getNumber () { return _number ; }
     
        std::string                                      _name , _behavior , _state ;
        float                                            x , y , z ;
        bool                                             &_time ;
     
    private :
     
        size_t                                                  _number ;
     
    };
    et ici l'exemple de la construction d'un objet depuis le disque, systèm Graphics :

    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
     
     
    void Game::build( std::string name , float x , float y )
    {
     
            _number ++ ;
     
            ...
     
            if( flux )
            {
                Data data ( _time ) ;
                data.setNumber ( _number ) ;
                data._name = name ;
                _data.push_back ( data ) ;
                while( wordFlux !=  "end" )
                {
     
                    flux >> wordFlux ;
                        word0 = wordFlux ;
     
                    if ( word0 ==  "Graphics" )
                    {
                        std::unique_ptr < System > model = getSystem ( "Graphics" ) ;
                        std::vector < Data > :: iterator it = _data.end()-1 ;
                        Graphics graph ( *it ) ;
                        ....
                        graph.add ( word0 , _resources.getTexture ( word1 ) , int0 , int1 , int2 , int3 , int4 , condition ) ;
                        ....
                        model -> add ( _number , graph ) ;
                        _system.push_back ( std::move ( model ) ) ;
                        ...etc...pour les autres modules...
    Le système Draw, hérité de System :

    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 Draw : public System
    {
    public :
     
        Draw( sf::RenderWindow& window ) ;
        ~Draw() ;
     
        void                                                         add ( size_t number , Graphics graph ) ;
        void                                                         update() ;
     
    private :
     
        sf::RenderWindow&                                            _window ;
        std::multimap < size_t , Graphics >                          _graphics ;
     
    };
    La class Graphics ( juste pour montrer comment une entité peut contenir le data correspondant à l'objet ).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
     
    class Graphics
    {
    public :
     
        Graphics( Data& data ) ;
        ~Graphics() ;
        ....
    private :
        ....
        Data&                                               _data ;
     
    };
    et enfin l'Engine, joué depuis le Game ( pour l'instant sous sa forme minimaliste ):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
     
    void Engine::update()
    {
        for ( auto& it : _system )
        {
            it -> update() ;
        }
    }
    Voilà, ce sont les grandes lignes de mon projet en terme de programmation, qui arrive déjà à afficher une animation, à l'aide du systèm Graphics.

    Merci beaucoup si vous pouvez me dire ce que vous en pensez ( aussi même si ca vous paraît cohérent , ( ce qui serait bien la première fois pour moi )...Mais évidement surtout si vous trouvez que quelque chose cloche.

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


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

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 858
    Points : 218 578
    Points
    218 578
    Billets dans le blog
    120
    Par défaut
    Bonjour,

    Ouep, l'ECS est "sympa" mais je crois que c'est surtout un effet de mode. Il ne me semble pas que l'on puisse faire un jeu complet avec l'ECS. Enfin, c'est ce dont j'ai l'impression, je me trompe surement.
    Maintenant voyons le code et je dois dire, il y a quelque trucs qui me font peur.
    Ici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::vector < std::unique_ptr < System > >                    _system ;//la class mère de tous les systèmes.
    Le commentaire ne convient pas à ce que je vois. Le commentaire, pour moi, semble dire que je n'aurais qu'une instance de System, alors qu'ici, on a plusieurs probablement systèmes.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Resources                                                     _resources ; // contient tout le package ( textures etc...) chargé, sinon le charge 
    std::vector < Data >                                          _data ; //contient les données de base d'un objet.
    Quelle est la différence entre Data (une données) et une ressources ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Data( bool& time ) : _time ( time )
    Un temps en booléen, moi, j'ai du mal. Mais en plus, je n'ai pas du tout, compris à quoi il servait, surtout dans le constructeur.

    Une Data avec :
    C'est plus qu'une Data, genre, elle est Positionnable.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void Game::build( std::string name , float x , float y )
    Je conseille de passer les std::string en référence constante. Mais on me dit qu'en C++11, ce n'est plus vraiment d'actualité ?
    De plus la fonction "build" me semble gérer beaucoup de chargement (load).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::multimap < size_t , Graphics >                          _graphics ;
    Pour moi, Draw n'a pas besoin de contenir les Graphics. De plus, pourquoi la size est la clé (pour identifier les types ?) ?
    Pour moi, on passe une instance par une de Graphics au Drawer afin de lui demander d'afficher.


    Enfin, comme je l'ai dit, je ne suis pas convaincu de l'ECS, mais si je trouve cela cool et amusant.
    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.

  4. #4
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2014
    Messages
    521
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2014
    Messages : 521
    Points : 136
    Points
    136
    Par défaut
    Merci pour ta réponse, LittleWhite.

    je ne suis pas convaincu de l'ECS, mais si je trouve cela cool et amusant.
    Mon but n'est pas de m'amuser, mais de faire un jeu qui tienne la route.

    semble dire que je n'aurais qu'une instance de System, alors qu'ici, on a plusieurs probablement systèmes.
    Oui, le commentaire est probablement mauvais. Il y a en effet dans ce vector tous les system nécessaire au jeu dont la class mère est représenté par l'objet "System"... et cela est-il valable selon vous, en terme de conception sur ce point ?

    Quelle est la différence entre Data (une données) et une ressources ?
    C'est plus qu'une Data, genre, elle est Positionnable.
    Le data représente en fait, dans mon cas, plutôt une entité...( il faudrait peut être que je change le mot ). Chaque objet a une "Data" qui contient ses informations principales, ( nom, position, comportement etc...), le but étant de faire passer ces infos simplement d'un module à l'autre par référence. C'est également une class un peu fourre tout, pour avoir accès facilement à des informations comme le temps, qui sera utilisé dans pleins de modules. ( par exemple le Graphics, qui doit animer ses sprites toutes les 62500 microsecondes...)

    La class Resource, elle est une class unique qui contient les textures chargés, sons etc..

    De plus la fonction "build" me semble gérer beaucoup de chargement (load).
    La fonction "load" se contente de lire le fichier du niveau ex :

    personnage1 1014 , 2048
    arbre 500 512
    arbre 489 1546
    bidul 456 644
    etc...

    et utilise pour chacun des objets demandés la fonction build qui les construits, avant de les positionner avec les bonnes coordonnées ( qui vont de pair).

    Mais oui, sans doute ma fonction build risque d'être très longue...Puisque qu'elle lira à elle seule toutes les donnés constructibles du jeu ( Graphics, Physics, control, behavior etc...), contenu dans des fichiers textes individuels pour chaque objet, et pourra demander à créer tous les systèmes appropriés...

    Cela vous paraît-il gérable/cohérent ? ou dangereux et lourd ? ( si vous avez une meilleur solution, je suis toujours preneur ; )

    Pour moi, Draw n'a pas besoin de contenir les Graphics. De plus, pourquoi la size est la clé (pour identifier les types ?) ?
    Pour moi, on passe une instance par une de Graphics au Drawer afin de lui demander d'afficher.
    Dans mon cas, Draw est un System. N'est-ce pas le principe du ECS ? Le System Draw va contenir les clefs de tous les objets qui utilisent l'affichage ( des simples numéros ) auquel est associé un module, qui va lui, pouvoir afficher ce qui correspond à l'objet.
    Si un signal dit : "objet 4198456, devient rouge", alors le System Draw va s'arrêter à l'objet "4198456" et demander au module Graphics aproprié de devenir rouge...est-ce bien correct ?

    Merci pour ta réponse , ca me permet de réfléchir et prendre du recul. Déjà il faudrait surement que je transforme le nom Data en Entity, probablement....

  5. #5
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 965
    Points
    32 965
    Billets dans le blog
    4
    Par défaut
    Salut,

    avant de vouloir aller plus loin, il faudrait avoir des bases solides.

    Juste en lisant rapidement
    - const-correctness
    - copie de string dans tous les sens
    - bool& _time ;//un repère de temps donné depuis le main (1/16s , pour l'animation etc...) un bool pour un repère de temps ?!?!
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  6. #6
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2014
    Messages
    521
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2014
    Messages : 521
    Points : 136
    Points
    136
    Par défaut
    - bool& _time ;//un repère de temps donné depuis le main (1/16s , pour l'animation etc...) un bool pour un repère de temps ?!?!
    Oui. Apparemment, ca a pas l'air conventionnel. L'idée est que, toutes les 62500 microseconds ( soit 1/16 secondes ), le bool est true, et false le reste du temps. Ainsi, si le bool est true, alors, par ex, les animations peuvent être incrémentés. Le but étant d'avoir des animation qui tournent à 16 images / secondes...

    Est-ce si absurde que ca ?

    copie de string dans tous les sens
    Est-ce une mauvaise chose ? Mon projet de jeu est de faire un STR, donc il y aura de nombreux éléments. Des strings me paraissent indispensable pour bien s'organiser, non ?

    const-correctness
    Oui, là, je vais relire un peu les cours C++

  7. #7
    Responsable 2D/3D/Jeux


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

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 858
    Points : 218 578
    Points
    218 578
    Billets dans le blog
    120
    Par défaut
    Citation Envoyé par mazertys17 Voir le message
    Oui. Apparemment, ca a pas l'air conventionnel. L'idée est que, toutes les 62500 microseconds ( soit 1/16 secondes ), le bool est true, et false le reste du temps. Ainsi, si le bool est true, alors, par ex, les animations peuvent être incrémentés. Le but étant d'avoir des animation qui tournent à 16 images / secondes...

    Est-ce si absurde que ca ?
    Ahhhhhh, c'est ça votre idée. Le nom de la variable est peut être pas très bien choisi (?).
    En réalité, ce n'est pas si absurde que ça, même peut être pas du tout mais :
    • chaque animation peut avoir un temps d'animation différent ;
    • si votre jeu rame (ralentissement du PC pour X raisons, indépendante de votre code), l'update de l'instance se fera en décalage et donc, le bool a une chance d'être à false à ce moment là.
    • le point précédent est encore plus vrai en multithread.





    Est-ce une mauvaise chose ? Mon projet de jeu est de faire un STR, donc il y aura de nombreux éléments. Des strings me paraissent indispensable pour bien s'organiser, non ?
    Les string c'est "OK", mais il ne faut pas les copier dans tous les sens. J'ai connu un projet, sur ce forum, qui perdait 50 % des perfs, juste par des copies des strings dans tous les sens (à chaque appel de fonction). C'est pour ça que l'on vous dit d'utiliser des référence constante (voir FAQ C++).


    Mon but n'est pas de m'amuser, mais de faire un jeu qui tienne la route.
    Je parlais du concept de l'ECS. Pas nécessairement de votre projet et j'espère que le votre arrivera au bout

    Mais oui, sans doute ma fonction build risque d'être très longue...Puisque qu'elle lira à elle seule toutes les donnés constructibles du jeu ( Graphics, Physics, control, behavior etc...), contenu dans des fichiers textes individuels pour chaque objet, et pourra demander à créer tous les systèmes appropriés...

    Cela vous paraît-il gérable/cohérent ? ou dangereux et lourd ? ( si vous avez une meilleur solution, je suis toujours preneur ; )
    Cela ressemble à un gros switch case. Je vous conseille de voir le design pattern Factory.


    Dans votre programme "Data" me semble bien trop générique, cela englobe trop de chose (et je parlerai ici du principe de responsabilité unique).
    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.

  8. #8
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2014
    Messages
    521
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2014
    Messages : 521
    Points : 136
    Points
    136
    Par défaut
    Merci pour votre réponse.

    si votre jeu rame (ralentissement du PC pour X raisons, indépendante de votre code), l'update de l'instance se fera en décalage et donc, le bool a une chance d'être à false à ce moment là.
    Oui, bien vu...après j'ai pris le parti de calculer le temps ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
            if(elapsed.asMicroseconds() >=  62500 )
            {
                clock.restart();
                _time = true ;
            }
    Donc si le jeu rame...le _time sera forcément true à un moment donné, vu que le temps écoulé sera fatalement supérieur à 62500 microseconds...En revanche, bien sur, l'animation sera ralenti...Donc merci pour la remarque, je vais voir si je peux pas trouver quelque chose de mieux.

    Le nom de la variable est peut être pas très bien choisi (?).
    oui. Peut être que je peux utiliser quelquechose comme "_time62500mcs"

    d'utiliser des référence constante
    ( pour les string ).

    Yes, oui, merci. Je vais procéder ainsi dorénavant .

    Cela ressemble à un gros switch case. Je vous conseille de voir le design pattern Factory.
    Oui, tout à fait.
    Donc cette technique ( design pattern Factory ) serait un bonne chose à appliquer dans mon cas ?
    Ca va me faire encore un chapitre a lire

  9. #9
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 613
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 613
    Points : 30 613
    Points
    30 613
    Par défaut
    Salut,

    En fait (pour répondre à LittleWhite), la partie ECS permet de répondre à un besoin récurrent dans les jeux vidéos : le besoin de créer continuellement (bon, on se comprend sur le sens à donner à ce terme, hein) des éléments utilisant un grand nombre de composés dans un grand nombre de combinaisons et qui, avec l'approche orienté objet, finiraient par donner des hiérarchies de classes totalement incompréhensibles.

    Car l'approche "naive" serait de se dire que l'on a les sorts, divisé en "sorts offensifs", "sorts de défense" et "sorts d'amélioration", que les armes seraient séparées en "armes à une main", "arme de jet" et "armes à deux mains", et ainsi de suite. Le problème, c'est que, chaque fois que tu voudra fournir un élément supplémentaire (l'épée flamboyante du tueur de dragon), tu devras rajouter une classe à ta hiérarchie, prendre cette nouvelle classe en compte dans l'ensemble du projet et ... recompiler (quasiment) tout ton projet pour arriver à l'intégrer.

    L'approche ECS permet de partir de quelque chose ressemblant à une base de données : un "certain" nombre de tables représentant les composants de base ("caractéristique", "type d'arme", "type de dégats", "type d'élément d'inventaire", "position d'équipement", ... De cette manière, si je veux rajouter mon épée flamboyante du tueur de dragon, je crées une entité (représentée uniquement par un identifiant unique), au pire, je rajoute les enregistrements "tranchant" et "feu" dans la table "type de dégat", l'enregistrement "arme à une main magique" dans la table "type d'arme", et ainsi de suite pour terminer par un enregistrement dans une table particulière qui fera le lien entre toutes les caractéristiques spécifiques à cette arme. Pas besoin de recompiler, il n'y "a qu'à" enregistrer les modifications dans la base de données

    En s'assurant que chaque "caractéristique" soit prise en compte par un système particulier (SRP inside ) il devient très facile de gérer ces ajouts et suppressions continuels
    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

  10. #10
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Pour le nom de la variable, pense non pas à la cause, mais à ce qu'il provoque. Par exemple force_refresh.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  11. #11
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2014
    Messages
    521
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2014
    Messages : 521
    Points : 136
    Points
    136
    Par défaut
    En tout cas, tu m'a convaincu, Koala01

    Le tout maintenant est de bien mettre en place tout ca !

    J'ai du recommencer 10 fois mon programme depuis que j'apprends la programmation. Il faut que cette fois ci, ce soit la bonne !

    Donc merci infiniment à tous ceux qui m'aident dans la conception, car cette aide m'est très précieuse ! J'ai j'espère atteint un niveau suffisant pour pouvoir me lancer définitivement ( à condition de prendre mon mal en patience bien sur et de procéder pas à pas ).

    Pour le nom de la variable, pense non pas à la cause, mais à ce qu'il provoque. Par exemple force_refresh.
    oui. Donc dans mon cas :

    _time devrait être _timeIs65200mcs ?

    et pour le Data, je crois que ce serait plutôt une Entity...Qui à la limite contiendrait une Data qui elle contiendrait le "_TimeIs65200mcs", et d'autre données global du jeu..?

  12. #12
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 965
    Points
    32 965
    Billets dans le blog
    4
    Par défaut
    Euh Koala, je confonds p-e, ou alors c'est toi, mais ce dont tu parles c'est juste être "Data-driven". Non on ne va pas recompiler pour créer une épée de feu après avoir créé l'épée de glace. On a un objet épée, une datasheet correspondante et des attributs de part et d'autre.

    ECS c'est l'approche Unity, on crée une Entity, et on bind des composants : un script, une boite de collisions, ... et quand le moteur met à jour l'Entity, elle met à jour chacun de ses composants.

    J'ai du recommencer 10 fois mon programme depuis que j'apprends la programmation. Il faut que cette fois ci, ce soit la bonne !
    Tu débutes, et tu commences par un exercice des plus difficiles : un jeu-vidéo, temps réel qui plus est.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     if(elapsed.asMicroseconds() >=  62500 )
            {
                clock.restart();
                _time = true ;
            }
    C'est, euhh... nul.
    http://gafferongames.com/game-physic...your-timestep/
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  13. #13
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 613
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 613
    Points : 30 613
    Points
    30 613
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Euh Koala, je confonds p-e, ou alors c'est toi, mais ce dont tu parles c'est juste être "Data-driven". Non on ne va pas recompiler pour créer une épée de feu après avoir créé l'épée de glace. On a un objet épée, une datasheet correspondante et des attributs de part et d'autre.
    Disons plutôt que ce que j'ai expliqué, c'est le début des bases pour les composants, qui sont effectivement essentiellement "data-driven". Mais c'est peut être aussi la partie la plus difficile à appréhender si l'on est "trop formaté" par le paradigme objet

    Mais, à partir du moment où l'on arrive à comprendre qu'une entité n'est qu'un ensemble de composants (auxquels il est normalement possible d'accéder grâce à un simple identifiant unique) et qu'il suffit de modifier un composant pour modifier l'entité qui l'utilise, on arrive à comprendre le reste du principe "sans trop de problème"
    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

  14. #14
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2014
    Messages
    521
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2014
    Messages : 521
    Points : 136
    Points
    136
    Par défaut
    Toujours en partant sur ce concept Entity Composant System, svp dites moi si j'ai bien suivit :

    On a une Entity, dans mon cas, plus haut, le Data ( qui devrait donc s'appeler Entity ), qui représente un objet du jeu ( une biche, un arbre, etc...).

    On a des Components, qui sont des modules utilisés/ouPas pour une Entity ( ex un Graphics, qui l'affiche, un Physics, qui le positionne ).

    On a des System, qui sont des sortes de containers intelligents de components, qui les font tourner.


    Donc, il serait profitable que l'Entity soit accessible par la plupart des components non ?
    J'ai essayé de la mettre en référence, mais il me semble que ce n'est pas vraiment faisable dans cette utilisation...

    Et...en tournant un peu la situation dans tous les sens, un frisson d'horreur me prend, et je pense....au......au.......

    ...au shared_ptr...

    Chose que je voulais éviter puisqu'on arrête pas de dire, probablement à raison que c'est un signe de mauvaise conception.

    Pourtant, dans mon cas, l'Entity est crée dès qu'un component au moins est utilisé. En fait, elle peut exister tant qu'un des component qui lui correspond au moins tourne. La responsabilité de l'objet peut donc être partagé par plusieurs de ces components ?

    Que pensez vous donc, dans ce cas, de :

    -la cohérence en terme de nom et d'utilisation de "Entity" ( qui contiendrait donc toutes les infos importante d'un objet ).
    -son utilisation en tant que std::shared_ptr par des components ( si déjà je suis dans le juste sur le concept Entity/Component/System )
    -utilisation de Data, une class qui contient les infos technique du jeu, comme une ref sur la fenêtre, une ref sur le temps, etc...et serait contenue dans Entity, afin que les différents composants puissent y avoir acces.

    Et enfin une dernière question :

    A supposé que l'idée d'avoir une Entity qui représente l'objet contenue dans la plupart des composants soit bonne, pensez vous que, pour une question de performances, la quantité d'informations qu'elle peut contenir doit être absolument minimale ? ou au contraire, si elle en contient beaucoup, c'est pas un pb...

    Merci si vous pouvez m'aider

  15. #15
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Citation Envoyé par mazertys17 Voir le message
    Que pensez vous donc, dans ce cas, de :

    -la cohérence en terme de nom et d'utilisation de "Entity" ( qui contiendrait donc toutes les infos importante d'un objet ).
    -son utilisation en tant que std::shared_ptr par des components ( si déjà je suis dans le juste sur le concept Entity/Component/System )
    Si tu utilises un ECS c'est pour éviter 2 choses (principalement) :
    * une énorme arborescence de classes
    * une classe de base qui contienne plein de trucs utilisés par les types dérivés

    Le but est aussi de favoriser la localité des données : les positions de 2 entités seront proches en mémoire, si on utilise la position d'une entité, il est probable qu'on ai besoin de la position de l'entité suivante par la suite.

    Dans un ECS, tes entités ne devraient être rien d'autres qu'un identifiant (un int par exemple).
    Du coup, pas besoin de std::shared_ptr pour les manipuler.

    Avoir une classe du type
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    struct Entity {
        Vec2 position;
        Texture texture;
        // ...
    };
     
    // puis quelques part on stock les entités
    std::vector<Entity> entities;
    est contraire au principe d'un ECS : tu veux justement éviter d'avoir une classe de base qui contienne tout plein de bazar.

    Ça devrait plutôt ressembler à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    typedef unsigned int Entity;
     
    struct PositionComponent {
       Vec2 position;
    };
     
    struct VelocityComponent { ... };
     
    // puis on les stock, un unordered_map n'est pas forcément le plus adapté
    std::unordered_map<Entity, PositionComponent> positions;
    std::unordered_map<Entity, VelocityComponent> velocities;
     
    std::vector<Entity> entites;
    Pour savoir quels composants une entité possède, un système de mask marche bien
    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
    const unsigned nbComponents = 2;
    typedef std::bitset<nbComponents> Mask;
     
    std::unordered_map<Entity, Mask> masks;
     
    struct PositionComponent {
       static const Mask mask = 1 << 0;
       Vec2 position;
    };
     
    struct VelocityComponent { 
       static const Mask mask = 1 << 1;
       Vec2 velocity;
    };
     
    struct MoveSytem {
       static const Mask mask = PositionComponent::mask | VelocityComponent::mask;
     
       // soit tu gardes une copie ici des entités qui ont des composants position et velocity
       // soit tu les cherches à partir de ta liste d'entités.
       void update() {
          for(auto e: entities) {
             if(masks[e] & mask == mask) {
                 // l'entité possède les bons composants, elle peut être traitée par ce système.
                 PositionComponent& pos = positions[e];
                 VelocityComponent& vel = velocities[e];
                 pos += vel /* *dt */;
             }
          }
       }
    };
    Tu peux avoir une étape intermédiaire avant les systèmes aussi pour créer des sous ensembles d'entités qui seront fournis (correctement triés) aux différents systèmes.
    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
    struct MoveNode {
       static const Mask mask = PositionComponent::mask | VelocityComponent::mask;
       Entity e;
       PositionComponent pos;
       VelocityComponent vel;
    };
     
    struct MoveSytem {
       std::vector<MoveNode> moves;
     
       void update() {
          for(auto& m: moves) {
             positions[m.e] = n.pos + n.vel /* *dt */;
          }
       }
    };
     
    // un "systeme" qui va créer les nodes pour les autres systemes.
    struct MakeNode {
       std::vector<MoveNode>& moves;
     
       MakeNode(std::vector<MoveNode>& m): moves(m) { }
     
       void update() {
          moves.clean();
          for(Entity e: entities) {
             if(masks[e] & MoveNode::mask == MoveNode::mask) {
                moves.emplace_back(e, positions[e], velocities[e]);
             }
          }
       }
    };
    C'est en tout cas l'idée générale (telle que je l'ai comprise).

    edit : un article intéressent sur le sujet : http://t-machine.org/index.php/2007/...opment-part-1/

  16. #16
    Responsable 2D/3D/Jeux


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

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 858
    Points : 218 578
    Points
    218 578
    Billets dans le blog
    120
    Par défaut
    @koala01 : Oui, vous parlez d'un ECS (et encore, là, cela n'en ai pas vraiment vraiment un, je pense) au niveau élément ingame. Souvent, on parle d'un ECS, au niveau plus moteur du jeu (genre, gestion de la position, de l'affichage, des update, des comportements pour chaque update).
    Mais j'ose croire qu'il est impossible de faire un jeu complet avec des composants et un système ECS. C'est mon ressenti, mon impression et surement à cause de mon ignorance.
    Il y a des parties de l'ECS que j'aime bien. Mais à part ça...

    _time devrait être _timeIs65200mcs ?
    _time devrait être : force_refresh (proposition de leternel), ou should_update, ou ... mais de toute façon, comme le montre/indique Bousk, c'est une mauvaise façon de faire. Ou alors très étrange et prouvez-nous que cela marche.

    J'ai du recommencer 10 fois mon programme depuis que j'apprends la programmation. Il faut que cette fois ci, ce soit la bonne !
    Oui, mais le jeux vidéo, ce n'est pas le domaine le plus simple. D'ailleurs, c'est peut être même le plus dur ou du moins, le plus multidisciplinaire. Voici mes points :
    • on commence par des exercices simples pour comprendre/apprendre le langage (et sa bibliothèque standard) ;
    • on commence par des jeux simples (oui, les jeux pourris style Pong, mais on peux trouver mieux et tout aussi simple) pour apprendre à faire un jeu vidéo (boucle de jeu, affichage, ...) ;
    • on fait son projet, petit morceau par petit morceau.

    Je serai vous, pour tester l'ECS, je ne tenterai même pas de mettre ça dans mon jeu ni rien. Je tenterai de mettre ça dans un programme à part, un bac à sable, avec un main et quelques classes de base. Cela permet de tester les limitations, les contraintes, les avantages et mieux comprendre les articles que l'on lit sur Internet.

    Ah oui, pour moi, le STR n'est pas le jeu le plus simple à faire, loin de là.

    Oui, Data est une Entity ... mais cela reste trop complet, trop vague. Alors, Iradrille a donné la bonne direction. Comme dans ECS, il y a composant et entity, je pense qu'il y aura au moins deux classes : Entity, qui est une classe là, juste pour contenir des Composants \*o / Et les composants, pour moi, c'était une classe mère que l'on peux hériter.

    Si je veux un joueur, je fais une instance de Entity, auquel je lui donne les composants :
    • Positionnable (une position) ;
    • Drawable (je veux l'afficher) ;
    • PlayerControllable (c'est le joueur qui le bouge ) ;
    • ...


    Enfin, moi, c'est comme ça que je vois la chose.
    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.

  17. #17
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2014
    Messages
    521
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2014
    Messages : 521
    Points : 136
    Points
    136
    Par défaut
    Merci pour ta réponse, Iradrille.

    j'ai du mal m'exprimer, car je ne parle pas d'envoyer l'Entity dans les sytèmes, mais dans les composants ( qui en auraient besoin ), et d'où le shared_ptr.
    Un exemple pour un composant Graphics, contenu dans le SystemGraphic :

    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
     
     
    void Game::add ()//pour lexemple
    {
           _number ++ ; //number est un size_t
     
           std::shared_ptr < Entity > entity ( new Entity ( _data ) ) ;
           entity -> setNumber ( _number ) ;
           entity -> _name = "cestPourLexemple" ;
           entity -> x = 10 ;
           entity -> y = 196541 ;
           _entity.push_back( entity ) ;
     
           ...//pour l'exemple d'un Component Graphics :
     
          Graphics graph ( entity ) ;
     
          graph.setTexture ( Resources.load ( "maTexture" ) ) ; 
          graph.setShape ( "square" ); //ou que sais-je...
          etc....
     
           systemGraphic.add ( _entity -> getNumber() , graphics ) ;
     
           //ou ce qui renvient au même :
     
          systemGraphic.add ( _number , graphics ) ;
    ainsi, quand le systemGraphic update tous les graphics, la fonction "draw" de Graphics va faire appel a l'Entity simplement pour avoir ses coordonnées ( qui peuvent changer ).
    C'est en revanche bien le composant "Graphics" qui sera possesseur des textures, vertex etc...a afficher.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
     
    void SystemGraphic::update()
    {
           for ( auto& it : _graphics )
           {
                  it.second.update() ;
           }
    }

    Et là , si le SystemPhysics, qui fonctionne sur le même model, a déplacé le x de l'Entity, alors le graphics, lors de l'update, va automatiquement bouger l'image en fonction...

    Donc je ne pensais mettre dans l'Entity que les données fondamentales de l'objet, auquel certains composants auraient accès ( dsl, je m répète un peu )

    Mais très vite, quand je veux créer un composant Control, par ex, se pose le dilem, en effet, pourquoi ne pas mettre dans l'Entity aussi un sf::IntRect, qui serait la zone de selection de l'objet, par ex etc...etc.
    ..
    Et on arriverait vite a ce que tu dis, c'est a dire, surcharger l'Entity d'information. Ca reviendrait certainement au même au final de mettre directement l'Entity dans le system. Donc probablement à éviter...

    Mais que pensez vous du concept, utilisé raisonnablement, et en shared_ptr pour l'Entity

    _time devrait être : force_refresh (proposition de leternel)
    ah ? Ok , je voyais pas les choses comme ca...pourquoi force ?

    Bousk, c'est une mauvaise façon de faire. Ou alors très étrange et prouvez-nous que cela marche.
    Oui, mais le jeux vidéo, ce n'est pas le domaine le plus simple. D'ailleurs, c'est peut être même le plus dur ou du moins, le plus multidisciplinaire. Voici mes points :
    on commence par des exercices simples pour comprendre/apprendre le langage (et sa bibliothèque standard) ;
    on commence par des jeux simples (oui, les jeux pourris style Pong, mais on peux trouver mieux et tout aussi simple) pour apprendre à faire un jeu vidéo (boucle de jeu, affichage, ...) ;
    on fait son projet, petit morceau par petit morceau.
    Oui c'est sur. Mais quand je dis que j'ai recommencé 10 fois mon programme, il faut voir qu'il marchait à chaque fois. Dans mon dernier programme, par ex, je peux utiliser un Editeur pour faire des niveaux, jouer un niveau avec batiments, qui peuvent produire des unités, dont un worker qui peut a son tour créer de nouveaux batiments, qui peuvent créer d'autres unités. Une unitée qui peut également chercher des ressources automatiquement, tirer des boules de feu. Sachant que chaque élément contrôlable du jeu a ses icones, qui déclenchent les actions qu'ils peuvent faire, et une minimap fonctionne avec la vision noirci des zones non découvertes, les points lumineux pour les objets qui bougent, etc... une ia basique, qui fait interagir certains objets etc...etc...et tout ca marche ( sur mes 2 pc, et c'est moche ).

    Donc je pense que je peux y arriver. Mais plus j'avance, plus je réalise que je peux faire les choses encore mieux. ( et que c'est même probablement nécessaire, pour aller au bout ).

    Voilà pourquoi j'ai décidé de suivre les conseils de gens expérimentés, et cette fois ci, après avoir bien tourné mon GD dans tous les sens, appris la programmation ( du moins le minimum nécessaire en c++ ) et appréhendé les besoins du jeux, aussi bien dans les contraintes graphiques, que physiques, de me lancer...définitivement.

    On dit, je crois, que la programmation, c'est 90% de conception, et 10% de maintenance. Il est temps pour moi de faire une conception 100% definitive. ( bien que je ne sois pas expérimenté, j'ai constaté que faire un programme depuis un concept bien élaboré est en fait rapide. Le plus long...c'est d'élaborer ! pour ma part je sais qu'en démarrant la programmation, je pouvais passer 2 mois sur un programme que je ferais aujourd'hui en 2 jours, et qu'il serait en plus infiniment plus efficace.) C'est pour ca que je vais essayer de suivre au mieux les concepts dont vous parlez ici, a Developpez ( et vous en remercie encore infiniment ).

    Bref, dsl, je raconte ma vie, mais c'est pour dire que je n'ai clairement pas l'intention de me dégonfler.

    Si je veux un joueur, je fais une instance de Entity, auquel je lui donne les composants :
    Positionnable (une position) ;
    Drawable (je veux l'afficher) ;
    PlayerControllable (c'est le joueur qui le bouge ) ;
    ...
    Oui, en fait dans mon cas, j'ai probablement inversé Entity avec Composant. ( sauf erreur ).

  18. #18
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Citation Envoyé par LittleWhite Voir le message
    Comme dans ECS, il y a composant et entity, je pense qu'il y aura au moins deux classes : Entity, qui est une classe là, juste pour contenir des Composants \*o / Et les composants, pour moi, c'était une classe mère que l'on peux hériter.

    Si je veux un joueur, je fais une instance de Entity, auquel je lui donne les composants :
    • Positionnable (une position) ;
    • Drawable (je veux l'afficher) ;
    • PlayerControllable (c'est le joueur qui le bouge ) ;
    • ...


    Enfin, moi, c'est comme ça que je vois la chose.
    Si une entité contient (=aggrégation) des composants, et que ces composants peuvent être hérités, on se retrouve avec une approche OO "classique" et un pattern strategy. On parlerait surement plus de comportements que de composants dans ce cas
    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
    // interfaces
    struct PositionnableBehavior {};
    struct DrawableBehavior {};
    struct ControllableBehavior {};
     
    // quelques implémentations
    struct Immobile : PositionnableBehavior {}; // pour les objets fixes
    struct Mobile : PositionnableBehaviour {}; // pour les objets qui peuvent bouger
     
    struct Mesh : DrawableBehavior {};
    struct Sprite : DrawableBehavior {};
    struct Camera : DrawableBehavior {}; // ??
    struct NotDrawable : DrawableBehavior {};
     
    struct PlayerControlled : ControllableBehavior {};
    struct IAControlled : ControllableBehavior {};
     
    struct GameObject {
       PositionnableBehavior *p;
       DrawableBehavior *d;
       ControllableBehavior *c;
     
       void draw() { d->draw(); }
       void moveTo(vec2 newPosition) { p->moveTo(newPosition); }
       // ...
    };
     
    // avec une factory
    struct Factory {
       GameObject makePlayer() {
          PositionnableBehavior *p = new Mobile();
          DrawableBehavior *d = new Camera();
          ControllableBehavior *c = new PlayerControlled();
          return GameObject(p, d, c);
       }
       // ...
    };
    Un principe différent, mais valide.

    Citation Envoyé par mazertys17 Voir le message
    j'ai du mal m'exprimer, car je ne parle pas d'envoyer l'Entity dans les sytèmes, mais dans les composants ( qui en auraient besoin ), et d'où le shared_ptr.
    Dans un ECS, un "objet" est une entité + des composants.

    L'entité est un simple identifiant (tu parles de données fondamentales : fondamentalement une entité n'a besoin que d'un identifiant unique).
    Les composants sont des aspects qu'on vient greffer sur une entité. Tu prévois un composant "Graphics", pourquoi pas un autre "Position" ?

    En quoi la position est spéciale et doit être intégrée à l'entité ? (J'avoue que j'ai du mal à trouver un exemple d'entité qui n'aurait pas de position, mais ça existe surement).

  19. #19
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2014
    Messages
    521
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2014
    Messages : 521
    Points : 136
    Points
    136
    Par défaut
    Les composants sont des aspects qu'on vient greffer sur une entité. Tu prévois un composant "Graphics", pourquoi pas un autre "Position" ?
    Donc dans ce cas on aurait quelque chose comme ceci, alors :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
     
    void Game::add( float x , float y )
    {
        ....
        Position position ( x , y ) ;
        SystemPosition.add ( _number, potition ) ;
        ....
        Graphics graph ;
        graph.setTexture ( textureExemple ) ;
        graph.setPosition ( &position ) ;
        SystemGraphic.add ( _number, graph ) ;
        ....
    }
    Bon, sachant que c'est pour l'exemple, puis qu’ici la référence position n'a aucun sens...Est-ce bien l'idée ?

    En somme, cela voudrait dire que mon idée de faire une Entity fourre tout n'est pas terrible ?

    Et autre chose, est-ce une bonne idée, selon vous, d'avoir un objet "Data", qui contiendrait des références sur _force_refresh, _window etc..accessible par tous les composants ?

  20. #20
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Un composant n'a normalement pas besoin de référencer un autre composant : ce sont 2 aspects distincts qui n'ont aucun rapport entre eux.

    C'est un système qui "fera la liaison" entre les différents composants.
    Par contre un système utilise (et met à jours) des composants, mais ne les possède pas.

    Si un système gère l'affichage d'entités, alors il traitera (toutes) les entités qui possèdent à la fois un composant "Graphics" et un composant "Position" (et seulement celles là).

    Tu n'auras pas forcément un système pour chaque composant séparément (par exemple avec une position seule on peut pas faire grand chose, donc tu risques de pas avoir de système pour cet unique composant).

    Si on reprend l'exemple d'un système pour gérer les mouvements : il utilise les composants "Position" et "Velocity". "Position" est utilisé par 2 systèmes ("SystemGraphic" et "SystemMove"), ça doit donc pas être contenu par un système.

    edit :
    Citation Envoyé par mazertys17 Voir le message
    Et autre chose, est-ce une bonne idée, selon vous, d'avoir un objet "Data", qui contiendrait des références sur _force_refresh, _window etc..accessible par tous les composants ?
    Accessible par tous les composants, ça n'a pas de sens : un composant n'a pas de méthodes il ne pourra rien en faire. Si c'est accessible par tous les systèmes, pourquoi pas, s'ils en ont tous besoin.

Discussions similaires

  1. Conception et programmation orientées objet
    Par forum dans le forum Livres
    Réponses: 2
    Dernier message: 31/08/2018, 16h44
  2. Réponses: 0
    Dernier message: 15/07/2014, 21h31
  3. Réponses: 0
    Dernier message: 15/07/2014, 21h31
  4. concepts de programmation en couches
    Par solitude dans le forum Windows Forms
    Réponses: 3
    Dernier message: 07/11/2008, 14h01

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