Несколько лет назад я работал над разработкой приложений с множеством «сохраненных» систем графического интерфейса (ниже я расскажу о том, что я имею в виду), таких как MFC, QT, Forms, SWING и несколько структур веб-графического интерфейса. Я всегда находил концепции большинства систем с графическим интерфейсом слишком сложными и неуклюжими. Количество событий обратного вызова, слушателей, копий данных, что-то, что можно связать во что-то - преобразования (и т. Д.) Всегда были источником ошибок и головной боли по сравнению с другими частями приложения. (Даже при «правильном» использовании привязок данных / моделей).
Сейчас я пишу компьютерные игры :). До сих пор я работал с одним графическим интерфейсом: Miyagi (не очень известный, но в основном та же идея, что и все другие системы).
Это было ужасно.
В средах рендеринга в реальном времени, таких как Игры, у меня возникает ощущение, что «сохраненные» системы графического интерфейса еще более устарели. Пользовательские интерфейсы обычно не нуждаются в автоматической компоновке или имеют изменяемые размеры окон на лету. Вместо этого им необходимо очень эффективно взаимодействовать с постоянно изменяющимися данными (например, 3D-позициями моделей в мире).
Пару лет назад я наткнулся на «IMGUI», который в основном похож на режим Immediate Graphics, но для пользовательских интерфейсов. Я не уделял слишком много внимания, так как все еще занимался разработкой приложений, а сама сцена IMGUI казалась не слишком широкой и не успешной. Тем не менее подход, который они используют, кажется настолько сексуальным и элегантным, что я захотел написать что-то для следующего проекта, используя этот способ пользовательского интерфейса (я не смог никого убедить на работе: (...)
позвольте мне резюмировать, что я подразумеваю под «удержанным» и «немедленным»:
Сохраненный графический интерфейс: на отдельной фазе инициализации вы создаете «элементы управления графическим интерфейсом», такие как «Метки», «Кнопки», «Текстовые поля» и т. Д., И используете какой-то описательный (или программный) способ размещения их на экране - все до того, как что-либо будет отображено. Элементы управления хранят большую часть своего собственного состояния в памяти, такие как X, Y расположение, размер, границы, дочерние элементы управления, текст метки, изображения и так далее. Вы можете добавить обратные вызовы и слушателей, чтобы получать информацию о событиях и обновлять данные в элементе управления GUI.
Немедленный графический интерфейс: библиотека графического интерфейса состоит из однократных функций «RenderButton», «RenderLabel», «RenderTextBox» ... (редактировать: не запутайтесь в Renderприставка. Эти функции также выполняют логику за элементами управления, такие как опрос пользовательского ввода, вставка символов, обработка скорости повторения символов, когда пользователь удерживает клавишу, и т. Д.), Которую можно вызвать для «немедленной» визуализации элемента управления (не делает). Это должно быть немедленно записано в графический процессор. Обычно его запоминают для текущего кадра и позже сортируют по соответствующим партиям). Библиотека не содержит никакого «состояния» для них. Если вы хотите скрыть кнопку ... просто не вызывайте функцию RenderButton. Все функции RenderXXX, которые взаимодействуют с пользователем, например кнопки или флажки, имеют возвращаемые значения, которые указывают, например, нажал ли пользователь на кнопку. Так что твой "RenderGUI" функция выглядит как большая функция if / else, где вы вызываете или не вызываете функции RenderXXX в зависимости от состояния вашей игры, и вся логика обновления данных (при нажатии кнопки) включается в поток. Все хранилище данных находится «за пределами» графического интерфейса и передается по требованию функциям рендеринга. (Конечно, вы бы разбили большие функции на несколько или использовали бы некоторые абстракции классов для группировки частей графического интерфейса. Мы больше не пишем код, как в 1980 году, не так ли?)
Теперь я обнаружил, что Unity3D фактически использует тот же самый базовый подход к своим встроенным системам графического интерфейса. Возможно, есть пара GUI с таким подходом?
Тем не менее ... при взгляде вокруг, кажется, есть сильный уклон в сторону сохраненных систем графического интерфейса? По крайней мере, я не нашел такого подхода, кроме как в Unity3D, и первоначальное сообщество IMGUI кажется довольно .... тихим.
Так кто-нибудь работал с обеими идеями и имел какое-то твердое мнение?
Редактировать: меня больше всего интересуют мнения, основанные на реальном опыте. Я думаю, что на IMGUI-форуме много горячих дискуссий по поводу любой «теоретической слабости» непосредственного подхода с графическим интерфейсом, но я всегда нахожу более полезным узнать о реальных слабостях.
Ответы:
Най. Я выполнил оплачиваемую работу gamedev с ужасным графическим интерфейсом «с сохраненным режимом» и с ужасным графическим интерфейсом с «непосредственным режимом», и хотя оба заставили меня захотеть вырвать глаза, подход с сохраненным режимом все еще явно лучше.
Недостатки немедленного режима много:
Интерфейсы с непосредственным режимом заманчивы для одиноких программистов, которые хотят иметь быструю систему HUD, и для этой цели они хороши. Для всего остального ... просто скажи нет.
источник
Как человек с пяти-шестилетним опытом работы с IMGUI на рабочем столе, я чувствую себя обязанным защищать его. Все ответы (и сам вопрос) основаны на очень ограниченном определении IMGUI, и кажется, что делается много сомнительных заявлений.
Во многом это происходит из-за предположения, что библиотека IMGUI не может хранить какие-либо данные в тайне. Это совсем не так. Сложная библиотека IMGUI фактически будет хранить столько же данных, сколько эквивалентная библиотека RMGUI. Разница в том, что библиотека IMGUI в основном кэширует результаты, тогда как библиотека RMGUI поддерживает авторитетное состояние. В IMGUI приложение предоставляет функцию, которая принимает текущее состояние модели и создает графический интерфейс для этого состояния. Это авторитетное определение GUI. Библиотека отвечает за то, чтобы экранный графический интерфейс соответствовал результату этой функции. Это не означает, что необходимо полностью оценить эту функцию в каждом кадре и полностью перестроить графический интерфейс. В этом смысл кеширования.
С этим представлением IMGUI вы можете сделать расширенный макет, и производительность вполне приемлема. Вы также можете сохранить фактическое авторитетное состояние, если это облегчает интерфейс. Смысл IMGUI не в том, чтобы приложение сохраняло все. Приложение, вероятно, не хочет хранить положение каждой полосы прокрутки и развернутое / свернутое состояние каждого узла дерева. Суть в том, чтобы иметь возможность процедурно определять содержимое этих узлов дерева и само их существование.
Я хотел бы пройтись и ответить на все критические замечания IMGUI по пунктам, но я действительно не понимаю многие из них. Большинство из них, кажется, основаны на некотором фундаментальном убеждении, что IMGUI является хакерским, а RMGUI хорошо структурирован, что, я полагаю, проистекает из вышеуказанных недоразумений. Нет никакой внутренней причины, по которой библиотеки IMGUI должны иметь проблемы со сложностью или должны быть завалены глобальными переменными или смешивать логику с представлением. Я скажу, что преимущества IMGUI становятся менее важными, чем более управляемым художником является ваш контент, но я не уверен, почему он будет на самом деле хуже для контента, управляемого художником. (Лично я не использую контент, управляемый художником, кроме таблиц стилей для таких вещей, как цвета, размеры шрифтов / границ и т. Д., Но я не понимаю, почему это будет сложнее реализовать, чем для RMGUI.)
На мой взгляд, IMGUI, безусловно, хорошая вещь. Это дает вам гораздо лучшую модель для рассуждений о вашем графическом интерфейсе. Он становится намного более функциональным и реактивным, и вы сводите к минимуму количество изменяемых состояний, о которых вам нужно рассуждать. С другой стороны, реализация сложной библиотеки IMGUI является довольно сложной задачей и, безусловно, более сложной, чем реализация эквивалентной библиотеки RMGUI. Это компромисс между сложностью библиотеки и сложностью приложения. Если вы планируете создавать сложные приложения (или даже множество простых приложений), компромисс очень хорош. Если вы делаете это для одного приложения, и это довольно просто, вы, вероятно, достигнете своей цели быстрее с помощью RMGUI.
В любом случае, удачи!
источник
Я бы сказал, что это не библиотека GUI. Это просто набор функций рендеринга.
Рендеринг GUI - самая простая часть создания GUI. Возьмите текстовое поле для примера. Я собираюсь предположить самый простой случай: простое однострочное текстовое поле ввода.
RenderTextBox
просто нарисую текстовое поле. Это сделает простое измерение текста и нарисует глифы на экране. Это будет неЯ могу продолжать, но я думаю, что моя точка зрения ясна. Если вы хотите использовать
RenderTextBox
для рисования текстовое поле, все, что вы получите, это статическое, нефункциональное текстовое поле. Любая актуальная функциональность должна быть реализована вами.Делать текстовые измерения и рисовать глифы? Это простая часть работы с графическим интерфейсом. GUI расшифровывается как «Графический интерфейс пользователя». Последние два слова, где вы берете ввод от пользователя и что-то делаете с ним, являются трудной частью.
Игроков ожидают разумного управления графическим интерфейсом. В среде ПК (например, мышь и клавиатура), если игроки видят текстовое поле, они ожидают, что оно будет работать как обычное текстовое поле. Они ожидают, что смогут перемещаться в нем с помощью клавиш со стрелками, прыгать вперед и заканчивать домом и удалять, выбирать буквы в нем и т. Д.
Это означает, что вам придется реализовать весь этот код пользовательского интерфейса. Вы должны проверить, какой элемент управления был нажат. Затем вы должны сделать что-то на основе того, какой элемент управления был нажат. Вы должны иметь понятие «активный» элемент управления, который получает ввод с клавиатуры. Различные элементы управления должны по-разному реагировать на различные типы взаимодействия с пользователем.
В основном вам понадобится
TextBoxWindow
класс.Допустим, вы реализуете экран настроек игры. Таким образом, у вас есть различные группы параметров: игровой процесс, графика, звук, элементы управления и т. Д. Итак, у вас есть список различных групп в левой части экрана. Каждая группа вызывает набор элементов управления, которыми пользователь может манипулировать. Что происходит, когда пользователь нажимает клавишу Tab?
Ну, это зависит от того, какой контроль активен. Если один из элементов управления группы активен (последний раз был нажат), он переходит к следующей группе. Если вместо этого активен один из элементов управления в группе, он переходит к следующему элементу управления в этой группе. Вот как система предназначена для работы.
Таким образом, не только активный ввод с клавиатуры должен обрабатывать любой необработанный ввод для элемента управления, которому он принадлежит . Либо так, либо элементы управления должны быть в каком-то связанном списке, чтобы он мог перемещаться взад и вперед. Это означает, что в каждом элементе управления должно быть поведение по умолчанию.
Это все больше и больше напоминает сохраненный графический интерфейс, не так ли? Разница лишь в том, что ... ты тот, кто делает тяжелую работу. Использование кого-либо еще GUI должно быть способом сделать меньше работы. Но усилие, которое требуется, чтобы заставить графический интерфейс реагировать, как ожидает пользователь, нетривиально.
Помните: пользовательский интерфейс не для вас, а для ваших пользователей . Это для игрока. Это должно вести себя так, как они ожидают. И если это не так, то вы потерпели неудачу.
Это ограниченная и ограничивающая мысль.
Я мог бы рассказать о разных играх с разными потребностями пользовательского интерфейса, которые делают некоторые игры. нужно Resizeable окна и так далее. Но есть гораздо большая проблема.
Ваш образ мышления приводит к проблеме «Битвы за космические сражения».
Если вы никогда не играли в эту игру, это дешевая, инди-игра и игра с большим графическим интерфейсом. Фактический игровой процесс полностью выполнен в графическом интерфейсе (это игра типа «настраивай юнитов и наблюдай, как они сражаются»). Проблема?
Графический интерфейс не может быть изменен!
О, это хорошо, если вы используете обычный монитор или у вас нормальное зрение. Но если вы, например, я, управляете смехотворно огромным монитором (настолько большим, что у вас Windows увеличивает размер всего текста, чтобы вы могли его прочитать), это ужасно . Текст микроскопический. Там нет никакого способа изменить размер шрифта.
Конечно, GSB - это игра на основе графического интерфейса, поэтому для них это абсолютно непростительно. Игра с графическим интерфейсом может сойти с рук.
Никогда не думайте, что ваш пользователь смотрит на свою игру именно так, как вы. Делать это глупо.
Наличие системы GUI, которая может масштабировать себя до разрешения пользователя, действительно независимого от разрешения GUI, требует, чтобы макет был частью самой системы GUI. Если вы не собираетесь предоставлять это, то ваш текст будет казаться крошечным на чьем-то гигантском мониторе. Это не очень хорошая вещь.
Поэтому я бы сказал, что ваше мышление на эту тему недальновидно. Тебе это нужно. Вам нужно то, что предоставляют сохраненные графические интерфейсы. О, вам может не понадобиться все, что предоставляет какая-либо конкретная система графического интерфейса. Но вам нужно немного этого.
Базовая работа, которую вы должны выполнить, чтобы получить данные в систему, - это небольшая цена, которую нужно заплатить в дополнение к разумной уверенности в том, что пользователь может правильно взаимодействовать с элементами управления и что он изменит свой размер в соответствии с потребностями игрока.
Возможно, вам удастся обойтись без графического интерфейса в немедленном режиме, если вы не принимаете много пользовательского ввода от игрока. Но это было бы об этом.
источник
RenderTextBox
была функция , а не класс. Таким образом, ваше разделение между «немедленным режимом» и «сохраненным режимом», по-видимому, заключается в том, где хранятся данные, а не в том, кто ими управляет. Если это так, вам нужно сделать это различие более ясным в вашем вопросе, потому что это предполагает, что «графический интерфейс в непосредственном режиме» просто рисует вещи на экране. Что он не может получить вход (потому что это потребует постоянного состояния) и тому подобное. Так что это?Некоторое время назад IMGUI также заинтересовали меня, в качестве теста я написал несколько учебных пособий, чтобы ознакомиться с методами (начните здесь, если вам интересно, но это не намного больше, чем C # / XNA + оригинальный «учебник» здесь ) ,
Мне очень понравились IMGUI на короткое время, потому что информация, которую они отображают, всегда актуальна и верна (так как нет состояния, которое вы всегда передаете фактическим данным). Но, в конце концов, я потерял интерес, поэтому теперь я снова использую сохраненные графические интерфейсы.
В конце я подумал, что непосредственность GUI усложнила отделение GUI от данных, и время от времени я пытался отделить вещи, вводя некоторые состояния, нарушая элегантность IMGUI. Я также не думаю, что написание кода для сохраненных графических интерфейсов - это больше работы, чем написание кода для IMGUI, и мне нравится, что сохраненные графические интерфейсы можно запускать и забывать, и мне действительно нравятся события :).
Тем не менее, каждый раз, когда кто-то упоминает IMGUI, что-то внутри меня хочет попробовать еще раз, и стараться изо всех сил сделать это правильно, потому что там действительно есть некоторая элегантность, я просто не уверен на 100%, всегда ли это облегчит вашу работу. Я бы сказал, попробуй, может, попробуй, как я, и напишу несколько уроков (я считаю, что лучший способ освоить новые техники - это объяснить их другим).
источник
Я много работал с системой Unity3D GUI, которая работает так же, как вы описали. И я должен сказать, я ненавижу это со страстью.
«Немедленный» подход в некоторых случаях работает действительно хорошо. Во-первых, когда вам нужна только пара кнопок и меток - подумайте, например, о шутере HUD. Создать их с «сохраненным» подходом не очень сложно, но это очень просто с UnityGUI. Второй случай - когда вам нужно набросать много элементов управления на экран, но на самом деле вам нет дела до макета. Особенно, когда точные средства управления известны только во время выполнения. На самом деле это бесполезно в любой игре, но действительно полезно при создании инструментов, работающих в редакторе Unity.
Однако любой полусложный графический интерфейс - например, для (MMO) RPG или стратегической игры - неизбежно превращается в ужасную неразбериху с неразборчивым кодом, полную особых случаев и ломающуюся множеством способов. При создании такого GUI у вас обычно есть довольно специфическая компоновка, которая должна работать для любого разрешения и иметь возможность показывать любые данные, которые вы отправляете на свой путь. Вам нужны такие вещи, как, например, перемещение некоторых кнопок ниже, чтобы освободить место для более длинного текста. С «сохраненным» GUI вы можете иметь элемент управления, который делает это автоматически. В «немедленном» режиме нет никаких элементов управления, поэтому вы должны делать все явно.
Еще одна проблема с UnityGUI (не уверен, что это происходит со всеми графическими интерфейсами непосредственного режима) заключается в том, что, например,
Button()
вызов работает без учета любых других вызовов GUI. Таким образом, если одна кнопка находится поверх другой, щелчок будет нажимать обе кнопки одновременно. Это определенно не то, что ожидает пользователь, так что это добавляет еще один особый случай для обработки.Чтобы жить со всем этим, я всегда писал свою собственную обертку вокруг UnityGUI, которая превращает его в систему «сохраненных» режимов: элементы управления, которые хранят свое собственное состояние и просто вызывают необходимые
GUI
функции каждый кадр для меня.Я не могу сказать, что «немедленный» режим определенно хуже, чем «сохраненный», но я определенно чувствую себя намного лучше, работая в «сохраненном» режиме.
источник
Я собираюсь защищать IMGUI здесь, потому что некоторые из проблем, которые были перечислены ранее, могут быть решены, если вы захотите написать код для него. Кроме того, если вы пишете код для него, у вас есть надежная библиотека, которую можно многократно использовать и которую очень редко требуется модифицировать.
Возможно, на первый взгляд кажется, что у художников нет большой гибкости с IMGUI, это решается или улучшается с загрузкой макета GUI из схемы XML или JSON.
эта проблема решается с помощью сортировки, вы должны создать класс UI Manager, который сортирует порядок отрисовки. Я решил эту проблему в C # XNA с помощью подвижных панелей с возможностью нажатия, которые рисуются друг на друге. Я могу опубликовать псевдокод, если спросят.
вы можете рисовать строки из массива? Вы можете определить прямоугольные области от высоты и ширины шрифтов этих строк? Вы можете создать отношение размера кнопки прокрутки к высоте всех этих прямоугольников, добавленных вместе? Затем вы на полпути к созданию списка с прокручиваемой кнопкой для перемещения вверх или вниз. Я думал, что это будет трудно, но все оказалось намного проще, чем я думал. без буфера, без состояний, без обратных вызовов.
не позволяйте отдельным панелям, кнопкам, полям хранить данные. Я знаю, что моя первая попытка IMGUI была немедленной, но только в графическом смысле. Я сделал ошибку, сохранив данные в пользовательском интерфейсе. Это был почти философский сдвиг, чтобы по-другому думать о том, где размещать и изменять данные через изменения пользовательского интерфейса.
это предел и функциональность кода SDK, а не ваш. Я считаю, что SDK UI (Hammer, Unity, UDK) - это почти новый язык для изучения в любом случае. На самом деле они похожи на меня как Windows. Формы, обе настроены на максимально широкую возможность и поэтому имеют некоторый дополнительный вес по сложности.
и, наконец, посмотреть это> http://mollyrocket.com/861
источник
Это зависит от жанра и игры. Хорошая система управления запасами жизненно важна для большинства любой RPG. Вам нужно что-то, что обрабатывает макеты для вас, поддерживает полосы прокрутки, drag-n-drop, всплывающие подсказки и другие функции, которые намного проще реализовать с помощью Retained GUI.
Я не могу придумать способ перетаскивания n-drop с немедленным графическим интерфейсом, который не требует много манипуляций или сохранения состояния пользователя, таких как временное изменение буфера Z и сохранение информации о времени, чтобы исключить щелчок, который произошел для перемещения немного.
Но с точки зрения дизайна мне сложно представить мир без событий с графическим интерфейсом. Также графический интерфейс Immediate не совместим с ООП, заставляя вас прибегать к процедурному программированию.
Простота, предоставляемая непосредственными графическими интерфейсами, достигается за счет дополнительной сложности в вашем коде, которая быстро растет по мере увеличения сложности, требуемой вашим пользовательским интерфейсом; где хороший сохраненный графический интерфейс изначально сложнее, но лучше масштабируется. Поэтому ниже определенного уровня сложности немедленный графический интерфейс является адекватным, но для большинства ситуаций я бы предпочел оставить графический интерфейс.
источник