Journal Les artistes, ce fléau ou l'invasion des profanateurs de GUI

Posté par (page perso) . Licence CC by-sa
Tags :
26
20
mar.
2014

Sommaire

Bonjour Nal,

Je travaille sur les menus du jeu libre Ned et les maki. Au départ, ceux-ci étaient bien organisés avec des boutons et des widgets bien alignés.

Malheureusement la rationalité et l'ergonomie n'est pas du goût des artistes de l'équipe qui développe le jeu. Déstructuration de l'espace, placement selon le nombre d'or, tentative d'éblouissement mental du joueur pour provoquer un choc cathartique ou placement au hasard "parce que c'est plus joli hihi", on m'a demandé s'il était possible d'avoir une interface avec des widgets placés librement.

Exposé du problème

Cette liberté pose un problème: comment gérer correctement la navigation au clavier ou à la manette?

En effet l'interface est basée sur un "curseur" qui permet de choisir le widget courant et que l'on peut déplacer dans quatre direction: haut, bas, gauche, droite.

Mettre ce curseur sur le widget suivant une direction est assez facile et naturel avec une interface bien rangée.

http://tof.canardpc.com/view/056a79ac-5451-4726-9544-3d885a3323fa.jpg

Avec un placement libre, je tombe sur plusieurs problèmes:

  • existe-t-il un mode de déplacement "naturel"?
  • s'il existe est-il régi par des règles mathématiques?
  • si oui, comment les implémenter?

Les différents algorithmes envisagés et leurs résultats

J'ai fait quelques essais en essayant de choisir le widget le plus proche, le widget faisant un angle minimum suivant la direction de déplacement, un mix des deux… Mais impossible de trouver quelque chose de naturel.

À chaque fois je bute sur des cas "limites":

  • Cas 1 : cas limite 1
  • Cas 2 : cas limite 2
  • Cas 3 : cas limite 3
  • Cas 4 : cas limite 4

Pour simplifier, dans les cas exposés ici, on considère que l'utilisateur va toujours à droite (la direction ne change presque rien dans les algorithmes).

Distance euclidienne

Bon petit rappel de ce qu'est la distance euclidienne, dans un repère x, y on peut définir un triangle rectangle grâce à 2 points et à la différence entre leurs x et y ; quand on a un triangle rectangle on peut tout à fait calculer l’hypoténuse et donc la distance réelle entre les 2 points => tous les lecteurs de linuxfr le savent à priori…

repère hortogonale

Dans le cas d'un déplacement à droite

valeurRetour
dMinimale = nombreMax

Pour tous les boutons ou y > mon y :
   dEuclide = calculeDistanceEuclidienne(centreBoutonOrigin, centreBoutonAutre)
   si dEuclide < minimale :
       dMinimale = dEuclide
       valeurRetour = BoutonAutre

retourne valeurRetour

Les résultats de l'algorithme sont :

  • Cas 1 : on suit le schéma.
  • Cas 2 : Si les distances RV et RB sont les mêmes, c'est la loterie: ça dépend de l'ordre de création des widgets en mémoire…
  • Cas 3 : le bouton B est choisi?
  • Cas 4 : le bouton B est choisi.

Cet algorithme marche assez bien quand les boutons sont placés en grille avec tous la même taille et des écarts horizontal et vertical identiques.

Angle et distance euclidienne

On est toujours dans un triangle rectangle donc on peut faire un peu de trigonométrie et calculer l'angle entre la droite passant par les 2 boutons et l'horizontale.

L'algorithme est très similaire au précédent :

valeurRetour
dMinimale = nombreMax
angleMin = nombreMax

Pour tous les boutons ou y > mon y :

   dEuclide = calculeDistanceEuclidienne(centreBoutonOrigin, centreBoutonAutre)
   angle = calculeAngle(centreBoutonOrigin, centreBoutonAutre)
   si angle <= angleMin 3f09687f2a1bfe4a60ef1318710436c2702eb5e53f09687f2a1bfe4a60ef1318710436c2702eb5e5 dEuclide < dMinimale :
       dMinimale = dEuclide
       angleMin = nombreMax
       valeurRetour = BoutonAutre

retourne valeurRetour

Les résultats de l'algorithme sont :

  • Cas 1 : on suit le schéma
  • Cas 2 : Si les angles par rapport a l'horizontale sont les mêmes, c'est la loterie: ça dépend de l'ordre de création des widgets en mémoire…
  • Cas 3 : le bouton V est choisi.
  • Cas 4 : le bouton V qui est choisi.

Seul le cas 3 est problématique pour cet algorithme, en effet ce n'est pas le bouton le plus proche qui est choisi mais le plus éloigné. Cet algorithme fonctionne assez bien sauf si on a un groupe de boutons non alignés et un bouton éloigné mais aligné avec l'un des boutons du groupe.

Distance euclidienne et angle

On peut aussi choisir de prioriser la distance euclidien par rapport a l'angle c'est juste une inversion des tests

-    si angle <= angleMin \&\& dEuclide < dMinimale :
+    dEuclide <= dMinimale \&\& si angle < angleMin :

Les résultats sont les mêmes que pour l'algorithme utilisant la distance d’Euclide.

Angle et distance Euclidienne normalisée

On garde toujours les même mesures sauf qu'on les normalise, en les divisant par leur valeur maximale :
* Pour la distance euclidienne $$\sqrt{maxX{2} + maxY{2}}$$
* Pour l'angle 360 degrés ou pi/2 radiant

On a donc deux valeurs qui sont comprises entre ]0, 1]. Si on en fait la somme, on est entre ]0, 2]. Il ne reste plus qu'a comparer ces valeurs:

valeurRetour
nomaMax = 2

Pour tous les bouton ou y > mon y :
   dEuclide = calculeDistanceEuclidienneNormalise(centreBoutonOrigin, centreBoutonAutre)
   angle = calculeNormalise(centreBoutonOrigin, centreBoutonAutre)
   si (angle + dEuclide) < normaMax :
       normaMax = angle + dEuclide
       valeurRetour = BoutonAutre

retourne valeurRetour

Les résultats de l'algorithme sont :

  • Cas 1 : on suit le schéma.
  • Cas 2 : Si les angles par rapport a l'horizontale sont les mêmes et que les distances sont les mêmes, c'est la loterie: ça dépend de l'ordre de création des widgets en mémoire…
  • Cas 3 : le bouton B est choisi.
  • Cas 4 : ça dépend vraiment des valeurs exactes, une petite variation de la distance ou de l'angle de B peut faire changer le choix du bouton.

C'est le meilleur des algorithmes que j'ai testé mais il présente un faiblesse importante, le choix peut changer pour de très petites variations de position.

Piste non testée

J'ai eu d'autres idées en écrivant ce journal et je n'ai pas pris le temps de les tester:

  • Déterminer un angle maximal au delà duquel le bouton n'est pas pris en compte, mais on est toujours sensible au variations et comment déterminer cette angle ?
  • Une pondération de la distance par l'angle normalisé ? Peut-être une bonne idée.
  • Pondéré de manière arbitraire l'angle normalisé et la distance normalisé ? Comment déterminer les bons poids ?
  • Utiliser la distance entre le bord du bouton droit (quand c'est à droite que l'utilisateur veut aller), et le bord de gauche des boutons, oui mais on prend quel point du bord, le centre, les 2 points les plus proches (pas forcement très rapide à trouver) ?

Et vous

Nal, sauras-tu m'aider à trouver une solution? (Pas comme devnewton< dont la solution se limite à "on s'en fout de ces connards d'artistes de merde")

Est-ce que vous avez d'autres algorithmes à proposer, ou d'autres cas limites pour tester les algorithmes.

Merci pour ton aide Nal.

(Les casus qui ont pensé "ouais mais avec un écran tactile, pas besoin de curseur" en lisant ce journal peuvent aller jouer à Candy Crush sur l'autoroute, merci).

  • # Orthographe

    Posté par (page perso) . Évalué à 5.

    Je sais qu'il y a sûrement des fautes dans ce journal, les personnes souhaitant les corriger ce file est fait pour vous.

    • [^] # Re: Orthographe

      Posté par . Évalué à 1. Dernière modification le 20/03/14 à 12:10.

      Nal, seras-tu m'aider à trouver une solution? => sauras-tu
      Est-ce que vous avez d'autre algorithme a proposer, ou d'autre cas limite pour testé les algorithmes. => d'autres algorithmes à proposer, ou d'autres cas limite pour tester

    • [^] # Re: Orthographe

      Posté par . Évalué à 2.

      Dans les titres ça pique aussi les yeux :

      Exposer du problème => Exposé
      Les différents algorithmes envisagés et leur résultats => leurs

    • [^] # Re: Orthographe

      Posté par (page perso) . Évalué à 3.

      Je confirme, il y en a plein. Normalement moins maintenant.

      • [^] # Re: Orthographe

        Posté par (page perso) . Évalué à 1.

        Merci a tous pour votre aide et votre participations a la guérison de ma maladie.

        • [^] # Re: Orthographe

          Posté par . Évalué à 4.

          Nan mais par contre, faut que t'arrêtes d'écrire parce qu'ils n'arriveront jamais à suivre la cadence! ;)

          Merci a tous pour votre aide et votre participationXX [au singulier] a à la guérison de ma maladie.

          Truc mnémotechnique: Quand on ne sait pas s'il faut mettre un accent à "a/à", remplacer le mot par "avait" dans la proposition pour voir si ça se tient. Ici: "merci à tous pour votre participation avait la guérison": ça ne marche pas, donc tu écris "à".

          • [^] # Re: Orthographe

            Posté par . Évalué à 2.

            t'en as oublié un : merci a tous

    • [^] # Re: Orthographe

      Posté par . Évalué à 2.

      s/ce file est fait pour vous/ce fil est fait pour vous/

  • # Hardcoder ?

    Posté par (page perso) . Évalué à 10. Dernière modification le 20/03/14 à 11:59.

    Pourquoi ne pas hardcoder les déplacements… ? C'est pas comme si t'allais avoir 4000 widgets… c'est un jeu non ?

    Voir.. si tu veux pas hardcoder… indiquer les déplacements possible en dure dans un fichier de config que tu lis… comme ça, si ça te plais pas, tu changes juste la config de déplacement… pas besoin de chercher un algo complexe pour ça.

    • [^] # Re: Hardcoder ?

      Posté par (page perso) . Évalué à 2.

      Un algo générique profiterait à d'autres projets: Ned et les maki utilise la même bibliothèque (jnuit) que Newton Adventure et d'autres jeux à venir.

      http://devnewton.bci.im

      • [^] # Re: Hardcoder ?

        Posté par (page perso) . Évalué à 10.

        Ben oui mais ça sera jamais aussi bien que de décider explicitement au cas par cas… et un fichier config… l'algo pour le lire et associer les déplacement peut parfaitement être générique… sans pour autant que la décision de ceux-ci le soit.

    • [^] # Re: Hardcoder ?

      Posté par (page perso) . Évalué à 1.

      Tu hardcode un boutons pour tout les direction (4) pour l'ensemble de tes boutons (n), pour tout tes menus (m) ? Sa veut dire hardcodé 4*n*m (je simplifie, tout les menus on le même nombre de boutons) sa fait un paquet de code a écrire.

      Et puis dans les faits la GUI est gère par la bibliothèque jnuit, et donc l'algorithme doit-être généraliste car elle est utilisé dans d'autre jeux, on ne fait que donné la position des boutons a jnuit.

      • [^] # Re: Hardcoder ?

        Posté par (page perso) . Évalué à 5.

        Mais non ça fait pas un paquet de code à écrire… c'est un fichier de config à la con pour chaque bouton tu indiques le boutons suivant pour la direction donnée… enfin un jeu est pas censé avoir 5000 boutons non plus, ou je m’inquiéterai de l'ergonomie du jeu. L'avantage ici c'est que tu auras toujours à coup sûr le déplacement désiré… vu que tu l'auras choisis.

      • [^] # Re: Hardcoder ?

        Posté par . Évalué à 4.

        à priori ça n'est que la direction qui pose problème dans ton cas, donc tu as 4 (direction) * m (nombre de menus) à définir.

        m n'est pas sensé être trop grand non plus, je ne pense pas que ce soit excessif.

        tu étends l'api jnuit et au lieu de lui donner la position d'un bouton, tu lui donne sa position + ses transitions.

        dans le cas ou tu utilise la première api, tu gardes ton ancien algo, avec la nouvelle api, les transitions sont données de ton coté.

        Du coup tu auras même amélioré ta lib en la rendant plus souple :)

    • [^] # Re: Hardcoder ?

      Posté par . Évalué à 2.

      Je suis globalement d'accord, à moins que la position de tes menus ne soit choisi aléatoirement à chaque fois que tu lances ton application, elle est figée une fois pour toute, c'est de l'aléatoire, mais pas trop (http://xkcd.com/221/)

      donc une fois que les artistes se sont mis d'accord sur la position des menus, tu décide de l'ordre de navigation et tu le codes en dur.

      • [^] # Re: Hardcoder ?

        Posté par (page perso) . Évalué à 1.

        donc une fois que les artistes se sont mis d'accord sur la position des menus

        Une fois, deux fois, trois fois… Tout configurer à chaque changement, c'est lourd :-)

        http://devnewton.bci.im

        • [^] # Re: Hardcoder ?

          Posté par (page perso) . Évalué à 6.

          Utilises l'algo de distance pour générer une config de base (dans un fichier de config lu au runtime) et ensuite tu modifies le fichier pour que la config soit parfaite ====> []

        • [^] # Re: Hardcoder ?

          Posté par . Évalué à 2. Dernière modification le 20/03/14 à 13:48.

          tu utilises un fichier texte pour stocker la config, comme ça tu leurs explique comment faire ça et ils se débrouillent !
          Tu verras qu'ils auront tout de suite moins envie de tout changer toutes les 5 minutes :)

          Et une fois encore, c'est u menu, s'il y a 4 entrée, c'est pas trop la mort d'écrire un truc du genre (très verbeux pour l'exemple, on peut faire beaucoup mieux)

          menu "Nouveau Jeux" {
            precedent rien
            suivant "Charger une savegarde"
          }
          
          menu "Charger une savegarde" {
            precedent "Nouveau Jeux"
            suivant "Options"
          }
          
          menu "Options" {
            precedent "Charger une savegarde"
            suivant rien
          }
          

          c'est franchement pas la mort, et même si ça change souvent, ça reste simple a décrire et même un designer peut le faire !

          • [^] # Re: Hardcoder ?

            Posté par (page perso) . Évalué à 1. Dernière modification le 20/03/14 à 19:48.

            c'est franchement pas la mort,

            C'est juste la meilleure méthode pour avoir un résultat des plus incohérant possible.
            C'est le genre de truc impossible à vérifier sauf manuellement, et d'une les gens feront les modifs vite fait car chiant (donc bugs), testeront vite fait car chiant (donc bugs pas détectés), et les utilisateurs feront une tonne de rapport (ou trouveront simplement le jeu pas du tout agréable)

            Tu verras qu'ils auront tout de suite moins envie de tout changer toutes les 5 minutes :)

            Ils le feront quand même, juqte sans tester tout à chaque fois.


            Ou comment faire le nécessaire pour pourir un produit, à cause de principes "qu'ils se démerdent, ils ont qu'à bien faire attention à tout, on est des puristes".

            • [^] # Re: Hardcoder ?

              Posté par . Évalué à 4.

              Ou sinon tu fais au moins un vrai test avant de sortir le produit, et tu évite les changements après le début de la phase de test, on est en phase de dévelopement/debogague là.

              Si tu ne testes même pas le menu de base avant la sortie de ton produit, j'ai de fort doutes sur sa qualité globale, même s'il est écrit avec un super algo de la mort qui tue.

        • [^] # Re: Hardcoder ?

          Posté par . Évalué à 2.

          C'pas comme si je te faisais tout changer tout les deux jours Dev', allez quoi :D.

        • [^] # Commentaire supprimé

          Posté par . Évalué à 1.

          Ce commentaire a été supprimé par l'équipe de modération.

      • [^] # Re: Hardcoder ?

        Posté par (page perso) . Évalué à 1.

        Si seulement ils pouvaient tombé d'accord une fois pour tout, mais non il faut change la GUI tout les 5 minutes. Et puis si on trouve l'algo idéale plus besoin de s’embête a écrire ou modifié un fichier configuration on le laisse faire le boulot.

        L'automatisation prend du temps mais elle en fait gagner beaucoup.

        • [^] # Re: Hardcoder ?

          Posté par (page perso) . Évalué à 3. Dernière modification le 20/03/14 à 12:13.

          En automatique ce sera jamais parfait… car tu auras toujours un cas limite/artistique :D (ou tu as de la chance…) donc voir plus haut, tu peux utiliser un truc auto pour générer une config de base et celle-là tu la modifies à la main (ou non), sans pour autant intégrer l'algo de déplacement dans la lib elle-même (et cette fois c'est sans rire)

          • [^] # Re: Hardcoder ?

            Posté par (page perso) . Évalué à 1.

            J'ai un eu envies de dire que les cas limites le seront toujours, on peut trouver des situation ou une personne considère un mouvement comme logique et une autre personne éstimera que ce déplacement n'est pas le bon. Donc même en hardcodant on a pas la solution.

            • [^] # Re: Hardcoder ?

              Posté par (page perso) . Évalué à 3.

              Ben si… car au final ce sont les designers du jeu qui ont le dernier mot… pas l'algo. Donc c'est mieux (+1)

              • [^] # Re: Hardcoder ?

                Posté par (page perso) . Évalué à 2.

                Ben si… car au final ce sont les designers du jeu qui ont le dernier mot…

                Pas sur un projet libre :-)

                http://devnewton.bci.im

                • [^] # Re: Hardcoder ?

                  Posté par (page perso) . Évalué à 2.

                  Ben si… car au final ce sont les designers du jeu qui ont le dernier mot…

                  Pas sur un projet libre :-)

                  Ceci explique cela…

                  ------> []

                  alf.life

              • [^] # Re: Hardcoder ?

                Posté par . Évalué à 2.

                J'l'aime bien c'monsieur, écoutez le !

            • [^] # Re: Hardcoder ?

              Posté par . Évalué à 6.

              Vous n'avez pas honte d'exercer de telles violences sur les systèmes digestifs de ces pauvres diptères?

          • [^] # Re: Hardcoder ?

            Posté par (page perso) . Évalué à 2.

            Rien ne prouve que la solution manuelle sera bonne.

            Plus je regarde les exemples, plus j'ai l'impression qu'il n'y a finalement pas d'ordre logique ou naturel sur certains cas.

            http://devnewton.bci.im

            • [^] # Re: Hardcoder ?

              Posté par (page perso) . Évalué à 2.

              plus j'ai l'impression qu'il n'y a finalement pas d'ordre logique ou naturel sur certains cas

              Je suis d’accord. Il y a des cas qui sont de toutes façons problématiques. Ensuite, la question ici est de savoir comment les traiter :

              • une solution justifiable par la logique étant inexistante, un algo donnera des résultats insatisfaisants pour ces cas ;
              • une solution paramétrable en dur ne sera sûrement pas meilleure, mais elle présente l’avantage de pouvoir être décidée par le concepteur du menu, donc le jour ou il a une bonne raison d’agencer les widgets de façon anti-naturelle (je n’en ai pas en tête, c’est hypothétique), il a les outils pour assumer ce choix et maîtriser le résultat.

              Pour la lib jnuit qui se veut générique, la différence entre les deux solutions peut se reformuler ainsi :

              • veut-on une bibliothèque complètement générique utilisable par tout le monde, même si les cas d’utilisations n’ont pas été envisagés à l’avance par l’auteur ;
              • ou comme le but est de bien faire les choses, est-il préférable de ne pas fournir d’outils qui facilitent les mauvais choix de conception (au risque que la notion de « mauvais » ne soit pas partagée par tous, ni par toutes les applications possibles).

              En tant que développeur de la bibliothèque en question, c’est toi qui feras ce choix, et quel qu’il soit, il sera justifié.

            • [^] # Re: Hardcoder ?

              Posté par . Évalué à 6.

              A mon avis, le plus important c'est la cohérence : pour tous les cas limites, il faut que le comportement soit le même pour que le joueur puisse intégrer la logique. Le plus irritant, ce qui fait abandonner le joueur, c'est l'absence de logique. Exemple : pour tous les cas limites, c'est la boîte la plus haute sur l'écran qui est choisie. Inconsciemment, le joueur va l'intégrer, et il deviendra pour lui logique que dans ce jeu c'est ce comportement qui est attendu.

              Du coup dans l'algo il faudrait repérer les cas limites avec un critère (si deux distances entre boîtes sont différentes de moins d'une certaine distance arbitraire), et traiter ces cas limites de façon unique (on choisit la boîte la plus haute sur l'écran).

    • [^] # Re: Hardcoder ?

      Posté par (page perso) . Évalué à 10.

      Même si une solution inintéressante et rébarbative existe, un développeur choisit toujours une solution intéressante à développer ;-) (sinon c'est pas drôle)

      blog.rom1v.com

  • # Accessibilité de tous les boutons ?

    Posté par (page perso) . Évalué à 4.

    J'avoue que j'ai pas regardé de près les dispositions possibles en fonction des algorithmes proposés pour voir s'il y avait ce risque, mais en gros le truc indispensable c'est que tous les boutons soient accessibles depuis n'importe quel autre bouton (par une combinaison de touches plus ou moins longue), quelle que soit la disposition.

    À vue de pif, mais je me trompe peut-être, j'aurais tendance à penser qu'il y a moins de risque d'avoir un bouton inaccessible avec les distances euclidiennes qu'avec les angles (par exemple avec les angles, si tu as 4 boutons situés en carré parfait, plus un bouton au centre de ce carré, ce dernier ne pourra il me semble jamais être atteint depuis le bord du carré).

  • # Schéma Indiqué

    Posté par (page perso) . Évalué à 5. Dernière modification le 20/03/14 à 13:06.

    Salut,

    Je pense à une chose :
    La position du curseur pourrait être pourvue d'une flèche qui indique le prochain bouton visité.
    La liste des boutons visités et leur ordre de visite serait déterminé à l'ouverture de la page.
    L'indication ne dérouterait pas trop l'utilisateur.

    Autre idée :
    En repensant à Métroid sur GameCube, tu pourrais lier chaque bouton avec un trait. Le trait sélectionné pourrait être choisi avec les flèches de directions, et serait munie d'une flèche quand il est sélectionné.
    Un appuie sur le bouton d'action normale lancerait l'action de déplacement (voir d'ouverture du dit bouton).

    Mes deux idées nécessitent une action de plus, mais elle est nécessaire pour s'assurer de toujours choisir le bon bouton.

    Dans ton cas, il se peut que 2 boutons soient à des distances identiques, ce qui pose problème (puisque tu ne peux pas lire l'esprit de l'utilisateur).

    • [^] # Re: Schéma Indiqué

      Posté par (page perso) . Évalué à 2.

      J'aime cette idée, elle a l'avantage de résoudre le problème de l'algo, c'est le créateur qui choisie l'ordre, et d'éviter que l'utilisateur soit dérouté par le choix du créateur il est indiqué a l'utilisateur de manière clair.

      Même mieux on peut conserver l'algorithme, et indiqué le bouton suivant de manière visuel, c'est utile au créateur de l'interface car il sait quel sont les boutons suivant et peut ainsi facilement vérifié que l'interface correspond a ce qu'il veut, c'est facile pour l'utilisateur de comprendre la logique du créateur.

      Le plus dure vas être de convaincre le créateur de jnuit que c'est une solution a envisagé :).

  • # automatique + quelques re ecritures manuelle

    Posté par . Évalué à 3.

    hello,

    A ta place, j'utiliserais cet algo automatique comme base.
    Ensuite, pour les cas où cela ne rends pas bien, je me donnerais la possibilité de définir le comportement pour tel et tel cas en particulier. via un fichier de config comme cité précédemment.
    Ainsi tu peux profiter du meilleur des deux mondes.

    A voir après comment tu implémentes cela dans tes libs, aucune idée.

  • # Algo simple

    Posté par . Évalué à 7.

    Franchement, je ferais le truc suivant : découper l'espcace en quatre quadrants (haut bas droite gauche), et naviguer vers la fenêtre la plus proche dans le quadrant correspondant au déplacement. Quelque chose comme (sans les pointeurs nus dégueus):

    Widget * current = get_current_widget();
    Widget * next = NULL;
    vector<Widget *> all_windows;
    int direction = 1; // 1, 2, 3, or 4
    
    for (auto ww = all_windows.begin(); ww != all_windows.end(); w++) {
      bool keep = false;
      double angle = arccos(/* bla bla, don't forget the sign */);
      switch(direction) { // first, keep the widget only if it is in the good quadrant
         case 1: // say, right
           if ((angle > 7*pi/4) || (angle < pi/4)) {
             keep = true;
             break;
         case 2:
           /* etc */
      }
      if (keep) { // Then, select the closest one
        if (next == NULL)
          next = ww;
        else {
          if (dist (current, ww) < dist(current, next)) // if necessary: in case of equality, choose according to some stable criterion
            next = ww;
        }
      }
    }
    
    

    Bon, après, il faudrait vérifier si c'est intuitif. En cas d'égalité, il faut choisir toujours le même, quelle que soit la règle (histoire d'avoir de la cohérence dans l'interface).

    Ça me semble vachement plus simple que les autres solutions envisagées.

    • [^] # Re: Algo simple

      Posté par . Évalué à 2.

      J'aurais fait pareil.

      D'un autre côté, dans le journal, il manque un élément essentiel : qu'est-ce qui est attendu sur les exemples donnés ?

    • [^] # Re: Algo simple

      Posté par . Évalué à 2.

      Petite auto-correction : il faut élargir un peu l'angle, genre pi/4+epsilon, pour éviter l'effet "carré" discuté au-dessus. Ça ne change pas l'intuitivité du truc.

  • # Naviguer selon le "poids" des boutons ?

    Posté par . Évalué à 7.

    Ne serait-il pas plus simple de donner des poids à tes boutons afin de les ordonner (1, 2, 3, 4… ou A, B, C, D…) et d'utiliser l'algo suivant :
    - Si flèche droite ou bas aller sur bouton+1
    - Si flèche gauche ou haut aller sur bouton-1

    En plus du peux prioriser l'accès aux boutons les plus utiles :
    1 - jouer
    2 - mode multi-joueurs
    2 - options
    3 - quitter

    Par défaut tu es sur 1 (jouer), tu appuies sur flèche droite et tu arrives sur 2 (multi-joueur), etc.

    Enfin tu demandes à tes "artistes" de faire en sorte que ne soit pas complètement farfelue niveau ergonomie … et au pire tu as juste à change le poids de tes boutons dans le code.

    • [^] # Re: Naviguer selon le "poids" des boutons ?

      Posté par . Évalué à 1.

      Oui, oui, oui. J'ai aussi pensé à une solution de ce genre en lisant le journal.
      En fait, j'ai même pensé à la façon dont les navigateurs gèrent la navigation entre les champs dans les formulaires web. Il y a un ordre par défaut (l'ordre de déclaration, pas terrible ici, qu'il serait préférable de remplacer par un des algorithmes ci-dessus) et l'ordre choisi explicitement par le designer (si les « artistes » sont capable d'un peu de réflexion de ce type :-).

      Dans les formulaires HTML, ce n'est pas un « poids », mais l'attribut tabindex qui est utilisé.

      Petite difficulté ici : il faut pouvoir distinguer un déplacement latéral d'un déplacement vertical. À moins de considérer, comme Pifou, que « droite » et « bas » ont la même signification…

      Du coup, si une bibliothèque est écrite pour faire cela, elle permettra :

      • de naviguer automatiquement dans l'ordre naturel pour les interfaces calées sans ambiguïté sur une grille invisible
      • de naviguer de façon guidée par le designer pour les interfaces avec placement trop libre
    • [^] # Re: Naviguer selon le "poids" des boutons ?

      Posté par (page perso) . Évalué à 1.

      J'aime bien cette idée, c'est ce qui me paraîtrait le plus intuitif en tant qu'utilisateur.

  • # Et pour les coordonnées polaires?

    Posté par (page perso) . Évalué à 1.

    Bonjour,

    Est il possible de passer par les coordonnées polaires en tenant compte de la distance et de l'angle? En plus cela fera un joli effet boucle qui sera apprécié des artistes…

  • # Quelque chose de compréhensif par l'utilisateur

    Posté par . Évalué à 3.

    Il faut que l'action soit intuitive et compréhensible, je choisirais simplement le plus proche dans la direction demandée.

    Si on appuie pour aller dans l'ordre croissant des x, que l'on est à la position x0, on choisit x1 tel que x1 > x0 et qu'aucun autre point soit dans ]x0,x1[.
    Il faudrait ensuite tester le comportement pour le cas où plusieurs blocs ont un x qui satisfasse cette condition, je vois la possibilité de prendre le plus proche ou bien systématiquement choisir celui ayant le y le plus faible par exemple, ou encore en fonction de la direction de x, prendre le y plus grand ou plus petit.

    Il faudrait bricoler un code python par exemple pour tester toutes les suggestions et faire un vote

    • [^] # Re: Quelque chose de compréhensif par l'utilisateur

      Posté par . Évalué à 3.

      Il faut que l'action soit intuitive et compréhensible, je choisirais simplement le plus proche dans la direction demandée.

      Je suis d'accord et pour les distances identiques choisir le plus haut en premier.

      Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

    • [^] # Re: Quelque chose de compréhensif par l'utilisateur

      Posté par (page perso) . Évalué à 2.

      Il faut que l'action soit intuitive et compréhensible, je choisirais simplement le plus proche dans la direction demandée.

      C'est l'algo actuel dans jnuit que j'avais fait pour les widgets alignés.

      Le problème, c'est que l'exemple du quinconce pulvérise tous les algos proposés :-(

      http://devnewton.bci.im

    • [^] # Re: Quelque chose de compréhensif par l'utilisateur

      Posté par (page perso) . Évalué à 6. Dernière modification le 21/03/14 à 13:08.

      Une solution seulement basée sur les distances a de gros défauts car selon moi, il y a quelques propriétés à vérifier qui ne sont pas forcément garanties :

      1. toutes les entrées de menu doivent être accessibles. Il faut en effet voir la navigation dans le menu comme un graphe où les nœuds (les entrées) sont de degré d'au moins 1 et de maximum 4 (le mieux étant qu'ils soient tous de degré 4). Il faut veiller à ce que ce graphe soit connexe pour que tout soit accessible.

      2. si je vais à droite, puis à gauche ; ou en haut puis en bas ; ou l'inverse, je dois retourner à mon point de départ.

      • [^] # Re: Quelque chose de compréhensif par l'utilisateur

        Posté par (page perso) . Évalué à 1.

        J'aime bien cette idée de représentation sous forme d'arbre connexe, car elle permet de crée un algorithme pour vérifie que le placement des boutons et l'algorithme de choix associé est juste : tout les boutons sont accessible et les aller retour fonctionne.

        Mais aussi permet d'obtenir un score de qualité sur le cas précis \frac{\sum degré bouton_{i}}{nombre de boutons * 4}, ce score vaut ce qu'il vaut mais il peut permettre d'évaluer la puissance d'un algorithme, si on le lance dans N situation généré aléatoire.

        On peut imaginer un score suivant cette algorithme :

        Si au moins un bouton non accessible :
        retourne 0
        Sinon :
        retourne \frac{\sum degré bouton_{i}}{nombre de bouton * 4} - k * aller retour échouer

        Si on lance sa pour chaque algorithme sur 100 même cas aléatoire on obtient enfin une pseudo mesures de leurs puissance a chacun, et on peut les comparer objectivement.

        Et on peut même en analysant les résultats pour chaque cas, définir des types de cas ou l'algorithme est bon ou non, et a de la partir si on a plusieurs bon algorithme prédire lequel est le meilleur pour ce placement de bouton particulier.

        En claire il reste plus qu'a le coder.

  • # Vous été cool, vous me donnez plein d'idée

    Posté par (page perso) . Évalué à 1.

    Je viens de penser a quel que chose qui est peut-être une solution sympa et qui résout même le cas du quinconce.

    On établit une grille ou chaque case contient ne contient que un seul boutons (ou centre de bouton, pour être au plus petit possible), comment établir cette grille n'est pas traité ici.

    Le pseudo code pour aller a droite :

    boutonSuivant = null
    j = bouton.posY
    
    pour i = bouton.posX, tant que vraie == vraie, i++ :
        si i == maxI :
            i = min //0
            si j == maxJ :
                j = minJ
            sinon :
                j++
    
        si case[i][j].ContientBouton :
            return case[i][j].getBouton
    

    Si il n'y a pas de bouton dans la ligne on passe a la ligne d'en dessous, si on a pas rencontré de bouton et qu'on est a la dernière ligne on recommence au début.
    Après on peut choisir de monté dans les lignes, plus tôt que de descendre, de partir a gauche ou a droite dans quand l'utilisateur monte ou descend.

    Je pense qu'il faut définir de manière globale l'angle qui doit-être atteint avant de recommencé a zéro par exemple on par toujours vers le bas (quand c'est la direction droite et gauche qui on été choisie) ou a droite (dans les 2 autres cas).

  • # Tu te trompes de problème

    Posté par . Évalué à 7.

    J'ai l'impression qu'il y a un petit soucis dans ton approche du problème.

    Tu prévois une interface basé sur des widgets, traditionnellement conçu et utilisé pour un dispositif de pointage, mais tu veux concevoir ton jeu pour des contrôles qui n'ont pas de dispositifs de pointage (clavier ou manette).

    Est-ce que tes interfaces ne sont pas tout simplement mal adaptés à ton jeu et à tes contrôles ?

    Si ton jeu nécessite des interfaces à l'utilisation complexe, faut-il vraiment lui penser un support manette, ou clavier uniquement ? Aussi ergonomique que sera la solution que tu trouveras, le joueur ne se retrouvera t'il pas frustré de devoir se contenter d'un substitut de dispositif de pointage ? Ne faut-il pas repenser le jeu lui même pour réduire le nombre d'interfaces ou leur complexité ?

    Si au contraire tes interfaces sont plutôt simples, n'y a t'il pas de moyens plus simples pour naviguer entre elles ?

    Parmi les jeux récents jouables à la manette, même les jeux de gestion les plus compliqués évitent d'afficher trop d'interfaces simultanées et préfèrent ne les afficher qu'au besoin, via l'utilisation de sous menus ou d'onglets. Et lorsqu'il y a peu d'interface, il devient possible de les associer à l'utilisation d'un, ou d'une combinaison de boutons.

    Finalement, ton problème peut-être ramené à celui de la navigation au clavier dans des interfaces type GTK, et ça a toujours été une horreur à gérer. Le jeu vidéo, avec son emballage graphique et sa nécessité de rester ludique, ne pourra qu'empirer le problème, car naviguer dans des menus, en tant que tel, c'est pas amusant.

    • [^] # Re: Tu te trompes de problème

      Posté par (page perso) . Évalué à 1.

      Les contrôles supporté sont souris, clavier et manette, potentiellement tactile, il nous faut donc des interfaces adapter a tout ces contrôles.

      On est partie sur une interface commun, c'est peut-être une erreur, mais c'est aussi un gain de temps et sa apporte une cohérence qui est aussi important. Vous avez déjà vue une interface changer complètement quand vous branché une nouveau type de contrôleur.

      Il faut donc arrivé a mettre en place une interface utilisable pour tout les types de contrôleur.

      Concernant la simplicité des interfaces ce sont les "créative" qui les on crée, le débat de savoir si on doit leur laisser ce pouvoir n'est pas posé maintenant.

      De plus les menu sont assez peut présent dans le jeux, on pourrais éviter de ce faire chier et monté quelque chose de spécifique pure et dure mais c'est pas intéressant. on fait de l'enculage de mouche je l'accorde.

      Au finale le faite qu'on soit dans un jeux vidéo avec des menus on s'en fout, la vraie question c'est quel est l'algorithme "naturel", qui me permet de déplacer le curseur vers le prochain item quand je choisie une direction dans un espace a 2 dimension ? Promis je ferais la généralisation pour n dimension un jour.

      Je suis tout a fait d'accord pour dire que d'un point de vue ergonomique on est tout pourris mais on peut pas crée une interface pour chaque contrôleur.

      • [^] # Re: Tu te trompes de problème

        Posté par . Évalué à 2.

        On est partie sur une interface commun, c'est peut-être une erreur, mais c'est aussi un gain de temps et sa apporte une cohérence qui est aussi important.

        Dans ce cas-là, visez le plus petit dénominateur commun : un menu vertical linéaire comme dans 83% des jeux. Ce n'est pas pour rien qu'ils font généralement ça.

        Ou alors, adaptez votre interface à vos contrôleurs. Mais j'ai le sentiment que toute solution intermédiaire ne serait que de l'en*ulage de mou*he.

    • [^] # Re: Tu te trompes de problème

      Posté par (page perso) . Évalué à 2.

      Si ton jeu nécessite des interfaces à l'utilisation complexe

      L'interface dont on parle, c'est un menu classique de jeux vidéos:

      • des boutons démarrer, continuer, options, quitter…
      • de quoi configurer la résolution, le son…

      C'est super basique et ça doit pouvoir être utilisable avec n'importe quel dispositif.

      Dans 99,9% des jeux vidéos, tu as un menu bien organisé. Pourquoi? Certainement parce que la plupart des studios adoptent ma solution :-)

      http://devnewton.bci.im

  • # Qt

    Posté par (page perso) . Évalué à 9.

    Il se trouve que il y a quelque années, j'ai bossé sur un algorithme similaire pour la navigation entre les boutons dans Qt: le code est là:

    http://code.woboq.org/qt5/qtbase/src/widgets/widgets/qabstractbutton.cpp.html#_ZN22QAbstractButtonPrivate9moveFocusEi

    Je sais que cet algorithme n'est pas parfait malheureusement.

  • # Convention

    Posté par . Évalué à 8.

    Après avoir navigué dans des menus de DVD tous plus artistiques les-uns que les-autres, disons qu'on apprécie les conventions simples. Voilà ce que moi je ferais (et qui n'engage que moi hein!):

    Quand j'appuie sur un bouton de direction, je m'attends à ce que la case suivante soit celle la plus proche dans la direction. Si les cases ne sont pas alignées, plusieurs cas:
    -Soit la case la plus proche sur l'axe de la direction a un chevauchement dans l'autre axe, auquel cas elle est sélectionnée, soit elle n'en a pas, auquel cas la convention est soit de l'ignorer, soit de privilégier un sens sur l'axe orthogonal: en haut ou à gauche.
    Comme je viens de relire ce paragraphe et que je ne le comprends pas moi-même, prenons tes exemples:

    Cas n°2:
    Je m'attends à passer de R à B, direction vers le haut privilégiée sur direction vers le bas

    Cas n°3:
    Je m'attends encore à passer de R à B, parce que B chevauche R suivant l'axe Y.

    Cas n°4:
    S'ils ne se chevauchent pas, soit on ignore B sur l'axe X, soit on définit la direction suivant un arc de cercle qui passe par toutes les cases qui tomberont dedans. Aucun des deux ne me choque, pourvu que ce soit cohérent dans tous les menus.

    Bref, au lieu de chercher un algorithme "parfait", établis des conventions. Les utilisateurs ne sont pas des machines non plus, ils sont conditionnés depuis l'enfance à suivre des conventions: on lit de gauche à droite et de haut en bas*

    Ah, détail supplémentaire: sur presque tous les DVD que j'ai parcourus, quand tu es sur la dernière case de la ligne à droite et que tu appuies encore vers la droite, il passe sur la ligne suivante vers le bas à gauche. Et oui, on peut ainsi parcourir absolument tout le menu sans les boutons haut et bas, et c'est très intuitif finalement, histoire de convention et conditionnement, encore une fois.

    *Bon, ok, sauf le Chinois ancien mais tout le monde s'en fout, hein, et quelques langues qui s'écrivent de droite à gauche, auquel cas tu peux mettre les directions privilégiée dans un fichier de config avec la langue de l'interface!!! On est vendredi j'écris les conneries que je veux!

    • [^] # Re: Convention

      Posté par . Évalué à 1.

      Tu as oublié les locuteurs de langues basées sur l'alphabet arabe aussi ;) Mais il y a de l'idée, de se baser sur les conventions de lecture.

  • # j'ai une solution

    Posté par . Évalué à 10.

    tu codes le chemin entre les boutons aléatoirement (une nouvelle map à chaque lancement) comme ça tu rajoutes un jeu dans le jeu ;)

    Il ne faut pas décorner les boeufs avant d'avoir semé le vent

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.