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++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2014
    Messages
    521
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2014
    Messages : 521
    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 éclairé
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2014
    Messages
    521
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2014
    Messages : 521
    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
    27 074
    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 074
    Billets dans le blog
    145
    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 éclairé
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2014
    Messages
    521
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2014
    Messages : 521
    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 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    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 éclairé
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2014
    Messages
    521
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2014
    Messages : 521
    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
    27 074
    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 074
    Billets dans le blog
    145
    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.

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