J'ai travaillé sur le développement d'applications avec beaucoup de systèmes d'interface graphique "conservés" (comme ci-dessous), tels que MFC, QT, Forms, SWING et plusieurs cadres Web-GUI il y a quelques années. J'ai toujours trouvé les concepts de la plupart des systèmes d'interface graphique trop compliqués et maladroits. La quantité d’événements de rappel, d’écouteurs, de copies de données, d’un élément à l’autre - les conversions (et ainsi de suite) étaient toujours une source d’erreurs et de maux de tête par rapport aux autres éléments de l’application. (Même avec une utilisation "correcte" des liaisons / modèles de données).
Maintenant, j'écris des jeux informatiques :). Jusqu'à présent, j'ai travaillé avec une interface graphique: Miyagi (peu connue, mais fondamentalement la même idée que tous les autres systèmes.)
C'était horrible.
Pour les environnements de rendu en temps réel tels que les jeux, j'ai l'impression que les systèmes d'interface graphique "conservés" sont encore plus obsolètes. Les interfaces utilisateur n'ont généralement pas besoin d'être automatiquement mises en page ou d'avoir des fenêtres redimensionnables à la volée. Au lieu de cela, ils doivent interagir très efficacement avec des données en constante évolution (comme les positions 3d des modèles dans le monde).
Il y a quelques années, je suis tombé sur "IMGUI", qui est fondamentalement un mode graphique immédiat, mais pour les interfaces utilisateur. Je n'ai pas fait trop attention, étant toujours en développement d'applications et la scène IMGUI elle-même ne semblait pas vraiment large ni réussie. Malgré tout, leur approche semble être tellement sexy et élégante, que cela m'a donné envie d'écrire quelque chose pour le prochain projet en utilisant cette interface utilisateur (j'ai échoué à convaincre quiconque au travail: (...)
Permettez-moi de résumer ce que je veux dire par "retenu" et "immédiat":
Interface graphique conservée: dans une phase d'initialisation distincte, vous créez des "commandes d'interface graphique" telles que des étiquettes, des boutons, des zones de texte, etc. Les contrôles conservent la plupart de leurs propres états en mémoire, tels que l'emplacement X, l'emplacement Y, la taille, les bordures, les contrôles enfants, le texte de l'étiquette, les images, etc. Vous pouvez ajouter des rappels et des écouteurs pour être informé des événements et mettre à jour les données dans le contrôle de l'interface graphique.
Interface graphique immédiate: La bibliothèque d’interface graphique se compose de fonctions uniques "RenderButton", "RenderLabel", "RenderTextBox" ... (modifier: ne vous laissez pas troubler par le rendu.préfixe. Ces fonctions font également la logique derrière les contrôles, comme interroger l'utilisateur, interroger, insérer des caractères, gérer la vitesse de répétition des caractères lorsque l'utilisateur appuie sur une touche, etc.) que vous pouvez appeler pour rendre "immédiatement" le rendu d'un contrôle Il n'est pas nécessaire d'écrire immédiatement sur le GPU (en général, il est mémorisé pour l'image en cours et trié par la suite en lots appropriés). La bibliothèque ne détient aucun "état" pour ceux-ci. Si vous souhaitez masquer un bouton ... N'appelez pas la fonction RenderButton. Toutes les fonctions de RenderXXX qui ont une interaction utilisateur comme un bouton ou une case à cocher ont des valeurs de retour indiquant par exemple si l'utilisateur a cliqué sur le bouton. Donc, votre "RenderGUI" fonction ressemble à une grosse fonction if / else où vous appelez ou n’appelez pas vos fonctions RenderXXX en fonction de votre état de jeu et de toute la logique de mise à jour des données (lorsqu’un bouton est enfoncé) est mêlée au flux. Tout le stockage de données est "en dehors" de l'interface graphique et transmis à la demande aux fonctions de rendu. (Bien sûr, vous diviseriez les grandes fonctions en plusieurs fonctions ou utiliseriez des abstractions de classe pour regrouper des parties de l'interface graphique. Nous n'écrivons plus de code comme en 1980, n'est-ce pas?;))
Maintenant, j'ai découvert qu'Unity3D utilise la même approche de base pour ses systèmes d'interface graphique intégrés. Il y a probablement quelques interfaces graphiques avec cette approche également?
Pourtant… quand on regarde autour de soi, il semble y avoir un fort parti pris pour les systèmes d’interface graphique conservés? Au moins, je n'ai pas trouvé cette approche, sauf dans Unity3D, et la communauté IMGUI d'origine semble être plutôt… .. silencieuse.
Donc, quiconque a travaillé avec les deux idées et a une opinion forte?
Edit: Je suis plus intéressé par les opinions qui découlent d'une expérience réelle. Je pense qu'il y a beaucoup de discussions animées dans le forum IMGUI sur toute "faiblesse théorique" de l'approche d'interface graphique immédiate, mais je trouve toujours plus instructif de connaître les faiblesses du monde réel .
Réponses:
Non. J'ai effectué un travail rémunéré sur une interface graphique "en mode retenu" et sur une interface graphique en "mode immédiat". Bien que les deux me donnaient envie de m'arracher les yeux, l'approche en mode retenu est toujours clairement la meilleure.
Les inconvénients du mode immédiat sont nombreux:
Les interfaces graphiques en mode immédiat sont tentantes pour les programmeurs solitaires qui veulent un système rapide de HUD, et pour cela ils sont géniaux. Pour toute autre chose ... dites simplement non.
la source
En tant que personne avec cinq ou six ans d'expérience réelle avec IMGUI sur le bureau, je me sens obligé de le défendre. Toutes les réponses (et la question elle-même) reposent sur une définition très limitée de l’IMGUI et de nombreuses allégations douteuses semblent être formulées.
Cela provient en grande partie de l'hypothèse qu'une bibliothèque IMGUI ne peut pas conserver de données sous le capot. Ce n'est pas vrai du tout. Une bibliothèque IMGUI sophistiquée conservera en fait environ autant de données qu'une bibliothèque RMGUI équivalente. La différence est qu'une bibliothèque IMGUI met principalement les résultats en mémoire cache , alors qu'une bibliothèque RMGUI maintient un état faisant autorité. Dans IMGUI, l'application fournit une fonction qui prend l'état actuel du modèle et génère une interface graphique pour cet état. Ceci est la définition faisant autorité de l'interface graphique. La bibliothèque est responsable de s'assurer que l'interface graphique à l'écran correspond au résultat de cette fonction. Cela ne signifie pas qu'il doit évaluer pleinement cette fonction à chaque image et reconstruire entièrement l'interface graphique. C'est le point de la mise en cache.
Avec cette vue d'IMGUI, vous pouvez en fait faire une mise en page avancée et la performance est assez raisonnable. Vous pouvez également conserver l'état faisant autorité si cela facilite l'interface. Le but de IMGUI n'est pas de faire en sorte que l'application conserve tout. L'application ne souhaite probablement pas avoir à stocker la position de chaque barre de défilement et l'état développé / réduit de chaque nœud d'arbre. Le but est de pouvoir spécifier de manière procédurale le contenu de ces nœuds d’arbre et leur existence même.
Je voudrais répondre à toutes les critiques des IMGUI, point par point, mais je ne les comprends pas vraiment. La plupart d'entre eux semblent découler d'une croyance fondamentale selon laquelle IMGUI est un hack et RMGUI est bien structurée, ce qui, je suppose, découle des malentendus susmentionnés. Il n'y a aucune raison inhérente pour que les bibliothèques IMGUI rencontrent des problèmes de complexité ou soient encombrées de globals ou combinent logique et présentation. Je dirai que plus votre contenu est axé sur les artistes, moins les avantages d’IMGUI sont importants, mais je ne vois pas pourquoi ce serait pire pour les contenus créés par les artistes. (Je n'utilise pas personnellement le contenu créé par un artiste, mis à part les feuilles de style pour des éléments tels que les couleurs, la taille des polices / bordures, etc., mais je ne vois pas pourquoi il serait plus difficile à implémenter que pour RMGUI.)
Dans mon esprit, IMGUI est incontestablement une bonne chose. Cela vous donne un bien meilleur modèle pour raisonner sur votre interface graphique. Cela devient beaucoup plus fonctionnel et réactif, et vous minimisez la quantité d'état mutable sur lequel vous devez raisonner. D'un autre côté, la mise en œuvre d'une bibliothèque IMGUI sophistiquée est un défi de taille, et certainement plus difficile que la mise en œuvre d'une bibliothèque RMGUI équivalente. C'est un compromis entre la complexité de la bibliothèque et la complexité des applications. Si vous envisagez de créer des applications complexes (ou même beaucoup d'applications simples), le compromis est très bon. Si vous faites cela pour une seule application et que c'est assez simple, vous atteindrez probablement votre objectif plus rapidement avec RMGUI.
En tout cas, bonne chance!
la source
J'irais même jusqu'à dire que cela ne constitue pas une bibliothèque d'interface graphique. C'est juste un tas de fonctions de rendu.
Rendre l'interface graphique est la partie la plus facile de la création d'une interface graphique. Prenons une zone de texte par exemple. Je vais supposer le cas le plus simple possible: une simple zone de texte d’une seule ligne.
RenderTextBox
va juste dessiner une zone de texte. Il fera quelques mesures de texte simples et dessiner les glyphes à l'écran. Ça ne va pasJe peux continuer, mais je pense que mon propos est clair. Si vous souhaitez utiliser
RenderTextBox
pour dessiner une zone de texte, vous obtiendrez une zone de texte statique et non fonctionnelle. Toute fonctionnalité réelle doit être implémentée par vous.Faire la mesure du texte et dessiner des glyphes? C'est la partie facile du travail d'interface graphique. GUI signifie "Interface utilisateur graphique". Les deux derniers mots, où vous prenez l’entrée de l’utilisateur et faites quelque chose avec, sont la partie la plus difficile.
Les joueurs de jeux s'attendent à ce que les commandes de l'interface graphique fonctionnent raisonnablement Dans un environnement de type PC (souris et clavier, par exemple), si les joueurs voient une zone de texte, ils s’attendent à ce qu’elle fonctionne comme une zone de texte normale. Ils s'attendent à pouvoir s'y déplacer avec les touches fléchées, à sauter au début et à terminer avec home, à supprimer, à sélectionner des lettres, etc.
Cela signifie que vous allez devoir implémenter tout ce code d'interface utilisateur. Vous devez tester quel contrôle a été cliqué. Vous devez ensuite faire quelque chose en fonction du contrôle sur lequel vous avez cliqué. Vous devez avoir le concept d'un contrôle "actif", celui qui obtient une entrée au clavier. Différents contrôles doivent répondre différemment à différents types d'interaction utilisateur.
Fondamentalement, vous allez avoir besoin d'un
TextBoxWindow
cours.Disons que vous implémentez un écran d'options de jeu. Vous avez donc différents groupes d’options: gameplay, graphismes, son, commandes, etc. Vous avez donc une liste de différents groupes sur le côté gauche de l’écran. Chaque groupe appelle une série de contrôles que l'utilisateur peut manipuler. Que se passe-t-il lorsque l'utilisateur appuie sur la touche de tabulation?
Cela dépend du contrôle actif. Si l'un des contrôles de groupe est actif (le dernier clic a été choisi), il passe au groupe suivant. Si , au contraire l' une des commandes au sein du groupe est actif, il passe au contrôle suivant dans ce groupe. C'est ainsi que le système est censé fonctionner.
Ainsi, non seulement une entrée au clavier du processus de contrôle actif doit être entrée, mais elle doit maintenant alimenter toute entrée non traitée du contrôle qui en est propriétaire . Soit ça, soit les contrôles doivent être dans une sorte de liste chaînée, pour pouvoir aller et venir. Cela signifie qu'il doit y avoir un comportement par défaut dans chaque contrôle.
Cela ressemble de plus en plus à une interface graphique conservée, n'est-ce pas? La seule différence est que ... c'est vous qui faites le travail difficile. Utiliser quelqu'un d'autre est censé être un moyen de faire moins de travail. Mais l'effort qu'il faut pour faire une interface graphique de répondre que l'utilisateur attend est non négligeable.
N'oubliez pas que l'interface utilisateur n'est pas pour vous, mais pour vos utilisateurs . C'est pour le joueur. Il devrait se comporter comme ils s'y attendent. Et si ce n'est pas le cas, vous avez échoué.
C'est une pensée limitée et limitante.
Je pourrais vous donner le spiel sur les différents jeux ayant des besoins différents de l' interface utilisateur, que certains jeux font besoin de fenêtres redimensionnables et ainsi de suite. Mais il y a un problème beaucoup plus grand.
Votre façon de penser mène au problème des batailles spatiales gratuites.
Si vous n’avez jamais joué à ce jeu, c’est un jeu peu coûteux, indépendant et très graphique. Le gameplay réel est entièrement effectué dans l’interface graphique (il s’agit d’un jeu de type "configurer les unités et les regarder se battre"). Le problème?
L'interface graphique ne peut pas être annulée!
Oh, c'est bien si vous utilisez un moniteur normal ou si vous avez une vue normale. Mais si vous êtes moi-même, par exemple, qui gère un moniteur ridiculement énorme (un moniteur tellement grand que Windows a la taille de son texte pour pouvoir le lire), c'est terrible . Le texte est microscopique. Il n'y a aucun moyen de changer la taille de la police.
Certes, GSB est un jeu basé sur une interface graphique, il est donc absolument inexcusable pour eux. Un jeu GUI-lite peut probablement s'en tirer.
Ne supposez jamais que votre utilisateur regarde son jeu exactement comme vous. Le faire est une folie.
Disposer d’un système d’interface graphique capable de s’adapter à la résolution de l’utilisateur, une interface graphique véritablement indépendante de la résolution, nécessite que la présentation fasse partie du système d’interface graphique elle-même. Si vous ne fournissez pas cela, votre texte va apparaître minuscule sur le moniteur géant de quelqu'un. Ce n'est pas une bonne chose.
Je dirais donc que votre réflexion sur ce sujet est à courte vue. Vous avez besoin de ce genre de choses. Vous avez besoin de ce que les interfaces graphiques conservées fournissent. Oh, vous n’avez peut-être pas besoin de tout ce qu’un système d’interface graphique fournit. Mais vous en avez besoin.
Le travail standard que vous devez effectuer pour obtenir des données dans le système est un petit prix à payer, en plus de l'assurance raisonnable que l'utilisateur peut interagir correctement avec les contrôles et qu'il se redimensionnera lui-même pour répondre aux besoins du lecteur.
Vous pourrez peut-être vous en sortir avec une interface graphique en mode immédiat si vous n'utilisez pas beaucoup les informations du lecteur. Mais ce serait à peu près tout.
la source
RenderTextBox
c'était une fonction , pas une classe. Ainsi, votre division entre "mode immédiat" et "mode conservé" semble se situer autour de l'endroit où les données sont stockées, et non de la personne qui les gère. Si c'est le cas, vous devez préciser cette distinction dans votre question, car elle suggère qu'une "interface graphique en mode immédiat" dessine simplement des éléments à l'écran. Qu'il ne peut pas obtenir d'entrée (car cela nécessiterait un état persistant) et autres. Alors c'est quoi?Il y a quelque temps, IMGUI a également attiré mon attention. En tant que test, j'ai écrit quelques tutoriels pour me familiariser avec les techniques (commencez ici si vous êtes intéressé, mais ce n'est pas beaucoup plus que C # / XNA + le 'tutoriel' original ici ) .
J'ai beaucoup aimé les IMGUI pendant un court instant, car les informations qu'elles affichent sont toujours à jour et correctes (puisqu'il n'y a pas d'état dans lequel vous alimentez toujours les données réelles). Mais à la fin, j’ai perdu tout intérêt, alors j’utilise normalement à nouveau les interfaces graphiques conservées.
En fin de compte, j'ai pensé que le caractère immédiat de l'interface graphique rendait plus difficile la séparation de l'interface graphique des données et parfois, j'essayais de dissocier davantage les choses en introduisant un état, brisant l'élégance des IMGUI. Je ne pense pas non plus que l'écriture de code pour les interfaces graphiques conservées représente plus de travail que l'écriture de code pour les IMGUI et j'aime bien que les interfaces graphiques conservées puissent être déclenchées et oubliées, et j'aime vraiment les événements :).
Cependant, chaque fois que quelqu'un mentionne IMGUI, quelque chose en moi veut essayer à nouveau et essayer plus fort de bien faire les choses, car il y a vraiment une certaine élégance, je ne suis pas tout à fait sûr que cela facilitera toujours votre travail. Je dirais de l'essayer, peut-être d'essayer comme je l'ai fait et d'écrire quelques tutoriels (je trouve que le meilleur moyen d'apprendre de nouvelles techniques est de les expliquer à d'autres).
la source
J'ai beaucoup travaillé avec le système d'interface graphique Unity3D, qui fonctionne exactement comme vous l'avez décrit. Et je dois dire que je déteste ça avec passion.
L'approche "immédiate" fonctionne vraiment bien dans certains cas. Tout d’abord, lorsque vous n’avez besoin que de quelques boutons et étiquettes - pensez au tireur HUD, par exemple. Les créer avec une approche "retenue" n'est pas très difficile, mais c'est très facile avec UnityGUI. Le deuxième cas est celui où vous devez remplir de nombreux contrôles à l’écran, sans vous soucier de la mise en page. Surtout quand les contrôles exacts ne sont connus qu'au moment de l'exécution. Ce n'est vraiment utile dans aucun jeu, mais très utile pour créer des outils fonctionnant dans l'éditeur Unity.
Cependant, toute interface graphique semi-complexe - pour un RPG (MMO) ou un jeu de stratégie, par exemple - se transforme inévitablement en un horrible fouillis de code indéchiffrable, parsemé de cas spéciaux et se brisant de mille manières. Lors de la construction d'une telle interface graphique, vous avez généralement une présentation assez spécifique qui doit fonctionner pour n'importe quelle résolution et être capable d'afficher toutes les données que vous lui envoyez. Vous avez besoin de choses comme, par exemple, déplacer certains boutons plus bas pour faire place à un texte plus long. Avec l'interface graphique "retenue", vous pouvez avoir un contrôle qui le fait automatiquement. Avec le mode "immédiat", il n'y a pas de contrôle, vous devez donc tout faire explicitement.
Un autre problème avec UnityGUI (vous ne savez pas si cela arrive à toutes les interfaces graphiques en mode immédiat) est que, par exemple, un
Button()
appel fonctionne sans prendre en compte les autres appels d'interface graphique. Ainsi, si un bouton est au-dessus d'un autre, un clic appuiera simultanément sur les deux boutons. Ce n'est certainement pas ce à quoi l'utilisateur s'attend, alors cela ajoute un autre cas particulier à gérer.Pour vivre avec tout cela, j'ai toujours écrit mon propre wrapper autour de UnityGUI qui le transforme en un système en mode "retenu": des commandes qui stockent leur propre état et appellent simplement les
GUI
fonctions requises chaque image pour moi.Je ne peux pas dire que le mode « immédiat » est certainement pire que « retenu », mais je me sens certainement beaucoup mieux travailler en mode « retenu ».
la source
Je vais défendre IMGUI ici car certains des problèmes énumérés précédemment peuvent être résolus si vous êtes prêt à écrire le code correspondant. De plus, si vous écrivez le code, vous disposez alors d'une bibliothèque robuste, réutilisable et ne nécessitant que très rarement des modifications.
peut-être au début il semble que les artistes n’ont pas beaucoup de flexibilité avec IMGUI, ceci est résolu ou amélioré avec le chargement de la mise en page de l’interface graphique à partir d’un schéma xml ou JSON.
ce problème est résolu avec le tri, vous devez créer la classe UI Manager qui trie l'ordre de tirage au sort. J'ai résolu ce problème en C # XNA avec des panneaux amovibles et cliquables se dessinant les uns sur les autres. Je peux poster du pseudo-code si demandé.
pouvez-vous dessiner des chaînes d'un tableau? pouvez-vous définir des zones rectangulaires à partir de la hauteur et de la largeur des polices de ces chaînes? pouvez-vous créer un rapport entre la taille de votre bouton de défilement et la hauteur de tous les rectangles ajoutés? Ensuite, vous êtes sur le point de créer une zone de liste avec un bouton déroulant pour vous déplacer vers le haut ou le bas. Je pensais que ça allait être difficile, mais ça s'est avéré être beaucoup plus simple que je ne le pensais. pas de tampons, pas d'états, pas de rappels impliqués.
ne laissez pas les panneaux individuels, boutons, boîtes contiennent les données. Je sais que lors de ma première tentative d'IMGUI a été immédiate, mais seulement au sens graphique. J'ai commis l'erreur de conserver des données sur l'interface utilisateur. C’était presque un changement philosophique que de penser différemment sur l’endroit où placer et modifier les données via les changements d’UI.
c'est la limite et la fonctionnalité du code du SDK, pas le vôtre. Je trouve que l'interface utilisateur du SDK (Hammer, Unity, UDK) est presque une nouvelle langue à apprendre de toute façon. En fait, ils me ressemblent en tant que Windows.Forms, les deux sont configurés pour la possibilité la plus large possible et ont donc un poids supplémentaire dans la complexité.
et enfin regarder ceci> http://mollyrocket.com/861
la source
Cela dépend du genre et du jeu en question. Un bon système de gestion des stocks est essentiel pour la plupart des RPG. Vous allez vouloir quelque chose qui gère les mises en page pour vous, qui supporte les barres de défilement, les glisser-déposer, les info-bulles et d’autres fonctionnalités bien plus faciles à mettre en œuvre à l’aide de l’interface graphique conservée.
Je ne peux pas penser à un moyen de glisser-déposer avec une interface graphique immédiate qui ne nécessite pas beaucoup de jonglage ou de sauvegarde de l'état de l'utilisateur, telle que changer temporairement le tampon Z et stocker des informations temporelles pour éliminer un clic qui est arrivé pour déplacer un bit.
Mais du point de vue du design, j'ai du mal à imaginer un monde sans mes événements d'interface graphique. De plus, une interface graphique immédiate n'est pas compatible avec la POO, ce qui vous oblige à recourir à la programmation procédurale.
La simplicité offerte par les interfaces graphiques immédiates se traduit par une complexité supplémentaire de votre code, qui augmente rapidement à mesure que la complexité requise par votre interface utilisateur augmente; où, en tant que bonne interface graphique conservée, elle est plus complexe à l’origine mais évolue mieux. Donc, au-dessous d'un certain point de complexité, une interface graphique immédiate est adéquate, mais dans la plupart des situations, je préfère une interface graphique conservée.
la source