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 :

SFML / Gestion d'évènements personnalisés


Sujet :

C++

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2011
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2011
    Messages : 16
    Points : 11
    Points
    11
    Par défaut SFML / Gestion d'évènements personnalisés
    Bonjour à tous,
    Suite aux conseils de certains sur ce forum j'ai commencé à utiliser la bibliothèque SFML (très intuitive ...) pour afficher notamment un cercle et l'animer en temps réel.
    Ce que je souhaite faire maintenant c'est pouvoir animer justement ce cercle en fonction d'évènements exterieurs. (hors clavier / souris etc)
    Est-ce que quelqu'un à déjà eu à faire ce genre de chose? Je n'arrive pas trop à savoir comment m'y prendre, tout conseil est le bienvenue ...
    Merci d'avance!

  2. #2
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Bonjour,

    j'ai beaucoup sué et usé* de claviers sur cette question. Et sur la SFML entre autres.
    En fait, le principal problème est le séquenceur. Pour faire simple, le séquenceur est l'objet (ou le processus, selon comment on considère le problème) qui va stocker et exécuter les évènements. L'évenement en lui-même n'a rien de compliqué: un événement doit comporter un delai (quand doit-il être exécuté) et une fonction Execute() (D.P.command).

    Selon mon propre cheminement sur la question, et en ce qui concerne des applications graphiques sans énormes contraintes de rapidité, je suis aujourd'hui partisan d'un simple multiset:

    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
    struct MyEventType
    {
       MyEventType( int delay ) : delay_(delay) {}
       virtual ~MyEventType() {}
     
       inline const int & Delay() const { return delay_; }
       virtual void Execute() = 0;
     
    private:
       unsigned int delay_;
    };
     
    struct MyEventComp
    {
       bool operator () ( const MyEventType * left, const MyEventType * right )
       {
          return ( left->Delay() < right->Delay() );
       }
    };
     
    //! type definition for the event queue
    typedef std::multiset<MyEventType*, MyEventComp> MyEventSet;
    // Argh! Ce sont des pointeurs qui sont stockés!! Les pointeurs c'est le mal toussa... 
    // oui mais là je n'ai pas le choix puisque ce qui sera stocké seront des objets qui héritent de MyEventType (polymorphisme toussa...)
    // et non, pas de smart pointer non plus, c'est fait exprès
    L'idée du code ci-dessus est:
    . pour chaque type d'événement, on va créer une nouvelle classe/struct qui héritera de MyEventType.
    . le séquenceur possèdera une queue d'événements (MyEventSet), lesquels seront automatiquement triés lors de leur insertion grâce au foncteur MyEventComp.

    Ensuite, la façon dont les événements sont consommés par le séquenceur dépend de ton programme. Une façon classique de faire est, dans la boucle principale de l'application:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Sequencer the_sequencer; // le séquenceur
    Render the_renderer; // la classe qui s'occupe du rendu graphique
    while( !close_application )
    {
       the_sequencer.TreatEvents();
       renderer.DisplayFrame();
    }
    Le TreatEvents du séquenceur ressemblerait alors à quelque chose 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
    void Sequencer::TreatEvents()
    {
       // event_set_ est notre queue d'événements
       // 1. exécution des événements (ici c'estla fonction Execute de l'événement qui gère le délai (si delay_ == 0 alors execute, sinon delay_--;)
       std::for_each( event_set_.begin(), event_set_.end(), std::mem_fun( &SgrEvent::Execute) );
     
       // on élimine de la queue les évéments déjà exécutés
       MyEventSet::iterator it = event_set_.begin();
       while ( it != event_set_.end() )
       {
          if ( (*it)->Delay() <= 0 )
          {
             event_set_.erase( it );
             it = event_set_.begin();
          }
          else
             ++it;
       }
    }
    Bon, ce que je raconte là c'est en vrac, pour donner une idée de la solution que je propose. Si cela t'intéresse, tu pourras trouver une implémentation de cette solution ici. C'est une implémentation un peu ancienne, mais ça peut donner une idée. Aujourd'hui par exemple, je pense qu'il faut passer le contexte (le Renderer ici) à la fonction Execute() des événements.

    Cordialement.


    * l'anagramme est involontaire :^)
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2011
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2011
    Messages : 16
    Points : 11
    Points
    11
    Par défaut
    Ecoutes, merci pour cette réponse tout à fait claire!
    J'ai bien compris ta démarche.
    Par contre j'ai une remarque, quand tu dis "sans contraintes de rapidité", qu'est ce que tu entends? Est-ce que SFML n'est pas un bon choix technique pour des contraintes temps réel?
    Pour être plus clair dans ce que j'essaye de faire, je réalise un prototype qui a partir de coordonnées issues d'un moteur de reconnaissance de forme affiche cette information sous forme de cercle dans un casque à réalité virtuelle. Donc je cherche à être plus ou moins temps réel, tout en restant "prototype" dans le sens ou je n'ai pas besoin de créer l'application parfaite.
    Dans mon cas, chaque nouvelle coordonnées (mon évènement) impact l'affichage ...
    Merci encore!

  4. #4
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par Gregoire31 Voir le message
    Est-ce que SFML n'est pas un bon choix technique pour des contraintes temps réel?
    Ma foi, non, parce que Temps Réel n'a pas de sens dans ce cas. Un programme temps réel contraint, c'est un programme qui doit effectuer une opération spécifique dans un temps donné. Il lui est interdit de dépasser ce temps. Ceci dit, le temps en question peut être de l'ordre de l'heure.

    L'expression "rendu en temps réel" est galvaudée. Il faudrait dire "rendu en temps interractif" (c'est à dire à 12 Hz et plus).

    Citation Envoyé par Gregoire31 Voir le message
    Par contre j'ai une remarque, quand tu dis "sans contraintes de rapidité", qu'est ce que tu entends?
    Ce que veut dire rOd dans ce cas précis, c'est que la solution qu'il te propose est peut-être sous-optimale, mais que sa simplicité de mise en oeuvre la rend intéressante dès lors que les contrainte sur la fréquence de rendu ne sont pas trop élevée. Il ne discute pas des qualité de SFML, qui, après tout, ne reste qu'une porte d'entrée de l'affichage.
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2011
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2011
    Messages : 16
    Points : 11
    Points
    11
    Par défaut
    Ok merci, effectivement je n'utilise pas forcément les bons mots ...
    La question plus précise est donc si ma contrainte de rafraîchissement est de l'ordre de 30Hz à 50Hz, est-ce que cette solution reste "viable"?

  6. #6
    screetch
    Invité(e)
    Par défaut
    quelques remarques sur les evenements de r0d:
    - le stockage du timer devrait etre externe, pas dans la classe evenement. Plus une question de design que de performance.
    - au lieu d'un temps relatif que tu decrementes, ce devrait etre un temps absolu (pas besoin de le mettre a jour chaque frame), et tu devrais le comparer au temps absolu au lieu de le decrementer et le comparer a 0
    - si le multimap est trié selon le temps, alors seuls les n premiers événements (ceux dont le timer absolu est "dans le passé" doivent être executés. dés que tu trouves un événement s'effectuant dans le futur tu peux t'arrêter, et ce sera le premier événement a éxécuter la frame suivante.

    ca sera beaucoup plus performant

  7. #7
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par Gregoire31 Voir le message
    Ok merci, effectivement je n'utilise pas forcément les bons mots ...
    La question plus précise est donc si ma contrainte de rafraîchissement est de l'ordre de 30Hz à 50Hz, est-ce que cette solution reste "viable"?
    La réponse à la question est : mesure !

    Avant de savoir si une solution est viable, il faut l'implémenter, la tester, et mesurer ses performances. Sans mesure, comment répondre à la question ?
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2011
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2011
    Messages : 16
    Points : 11
    Points
    11
    Par défaut
    Ok je reviendrai poster un message après implémentation
    Mon problème est d'ailleurs peut être plus "simple" que je ne le pense dans le sens ou mon programme lorsqu'il se rafraichit ne doit pas exécuter l'ensemble des tâches accumulées dans le sequenceur mais seulement la dernière ...

  9. #9
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par screetch Voir le message
    quelques remarques sur les evenements de r0d:
    - le stockage du timer devrait etre externe, pas dans la classe evenement. Plus une question de design que de performance.
    Que veux-tu dire par "stockage du timer"? La queue d'événements?

    Citation Envoyé par screetch Voir le message
    - au lieu d'un temps relatif que tu decrementes, ce devrait etre un temps absolu (pas besoin de le mettre a jour chaque frame), et tu devrais le comparer au temps absolu au lieu de le decrementer et le comparer a 0

    - si le multimap est trié selon le temps, alors seuls les n premiers événements (ceux dont le timer absolu est "dans le passé" doivent être executés. dés que tu trouves un événement s'effectuant dans le futur tu peux t'arrêter, et ce sera le premier événement a éxécuter la frame suivante.
    J'avais essayé cette solution, mais j'ai trébuché sur ma paresse pendant un détail d'implémentation

    Mais en fait, ça peut dépendre aussi. Par exemple, s'il s'agit d'une petite application pas trop gourmande en événements (un jeu de dames par exemple), alors la queue d'événements sera quasiment toujours vide. Il est donc moins coûteux de décrémenter un compteur sur des événements que sur un compteur statique (car en plus il faut un système pour vérifier qu'on ne dépasse pas la valeur max du type du compteur, et une addition supplémentaire lors d'une insertion... bon, s'il y a très peu d'événements à insérer c'est pas vraiment un coût).

    M'enfin bon, c'est aussi pour ça que je disais que ma proposition n'est pas conçue pour fonctionner sur des applications qui ont de grosses exigences de framerate, comme un FPS style Counter Strike ou un RTS style Starcraft par exemple, ou il est primordial que le fps ne déscende jamais en dessous de 120, dans laquelle la gestion des événements est le noyau du logiciel.

    Mais sinon oui, mes doutes portaient sur mon code, non sur la SFML. Elle est vraiment très très rapide.
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  10. #10
    screetch
    Invité(e)
    Par défaut
    par stockage du timer je veux dire que le temps avant execution ne fait pas partie de la commande elle-même; la preuve en est que ta methode execute fait deux choses, soit elle decrémente le compteur soit elle execute. Dans ce sens je pense plutot que tu devrais avoir un multimap au lieu d'un multiset; la clé est le temps a attendre (plutot en absolu, comme ca pas besoin de la bidouiller) et ton événement n'a pas a gérer le temps lui même, cette responsabilité est reportée a ton EventManager
    Event ne sait faire que "execute", et execute ne fait qu'executer.

  11. #11
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par screetch Voir le message
    - si le multimap est trié selon le temps, alors seuls les n premiers événements (ceux dont le timer absolu est "dans le passé" doivent être executés. dés que tu trouves un événement s'effectuant dans le futur tu peux t'arrêter, et ce sera le premier événement a éxécuter la frame suivante.
    Effectivement c'est mieux comme ça. Cependant un doute subsiste: la façon dont tu présente la chose laisse à penser que tu ne libères pas les évenements qui ont été exécutés. Ce n'est pas dangereux? Si jamais on a des événements avec un peu des donénes dedans, et si on a beaucoup d'événements, on risque de faire péter la mémoire non?
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  12. #12
    screetch
    Invité(e)
    Par défaut
    je n'y ai pas pensé; pour moi c'était très clair dans ma tête mais je ne l'ai pas ecrit du tout

    je dirai que le plus effiface serait de faire une boucle
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    m_currentTime += dT; // mise a jour de l'horaire absolu
     
    std::multimap::iterator it = m_events.begin();
    while(it != end() && it->first <= m_currentTime)
      it->Execute(); // execution de toute les tâches prévues pour maintenant
    m_events.erase(begin(), it); // retire tous les événements executés; ne pas oublier le delete non plus =)
    et voila, a priori on a degagé tous les événements du passé après les avoir executés

  13. #13
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Okay merci.
    Et vois-tu un inconvénient à libérer l'événement dans la boucle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    while(it != end() && it->first <= m_currentTime)
    {
      it->second->Execute(); // execution de toute les tâches prévues pour maintenant
      delete( it->second );
    }
    m_events.erase(begin(), it); /
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  14. #14
    screetch
    Invité(e)
    Par défaut
    nope, au contraire

Discussions similaires

  1. Gestion des évènements Netscape 7.0
    Par RATHQUEBER dans le forum Autres langages pour le Web
    Réponses: 6
    Dernier message: 19/12/2005, 16h26
  2. Problème avec la gestion des événements
    Par CynO dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 17/10/2005, 10h07
  3. [JTable] gestion des événements
    Par soulhouf dans le forum Composants
    Réponses: 4
    Dernier message: 19/08/2005, 13h21
  4. Gestion des évènements lors d'un clique sur une image.
    Par yoghisan dans le forum Débuter
    Réponses: 7
    Dernier message: 23/06/2005, 19h04
  5. Gestion d'événements hors tables
    Par Quentin dans le forum PostgreSQL
    Réponses: 8
    Dernier message: 11/02/2005, 00h09

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