Введение в skinning графического интерфейса

Для игры крайне важно предоставлять игрокам понятный, информативный и при этом визуально приятный пользовательский интерфейс. Хотя узлы Control изначально имеют вполне функциональный вид, всегда есть возможность для уникальности и настройки под конкретный случай. Для этого в движке Godot предусмотрена система skinning (или theming) графического интерфейса, которая позволяет настраивать внешний вид каждого элемента управления в пользовательском интерфейсе, включая ваши собственные элементы управления.

Вот пример этой системы в действии — игра с графическим интерфейсом, который радикально отличается от стандартной темы пользовательского интерфейса движка:

../../_images/tank-kings-by-winterpixel-games.png

Экран «Gear Up!» в Tank Kings, предоставленный Winterpixel Games

Помимо достижения уникального внешнего вида вашей игры, эта система также позволяет разработчикам предоставлять конечным пользователям возможности настройки, включая параметры доступности. Темы пользовательского интерфейса применяются каскадным образом (т.е. распространяются от родительских элементов управления к их дочерним элементам), что означает, что настройки шрифта или корректировки для слепых пользователей могут применяться в одном месте и влиять на все дерево пользовательского интерфейса. Конечно, эта система может быть использована и в игровых целях: ваша игра, основанная на герое, может менять свой стиль в зависимости от выбранного персонажа игрока, или вы можете придать разный вкус сторонам в вашем командном проекте.

Основы тем

Система скинов управляется ресурсом Theme. Каждый проект Godot имеет встроенную тему по умолчанию, которая содержит настройки, используемые встроенными узлами управления. Это то, что придает элементам управления их отличительный внешний вид из коробки. Однако тема описывает только конфигурацию, и каждый отдельный элемент управления должен использовать эту конфигурацию так, как ему нужно для своего отображения. Это важно помнить при реализации собственных пользовательских элементов управления.

Примечание

Даже сам редактор Godot использует тему по умолчанию. Но он выглядит не так, как проект Godot, поскольку применяет собственную, сильно модифицированную тему поверх стандартной. В принципе, это работает точно так же, как в вашей игре, как описано ниже.

Тематические элементы

Конфигурация, хранящаяся в теме, состоит из элементов темы. Каждый элемент имеет уникальное имя и должен иметь один из следующих типов данных:

  • Color

    Значение color, которое часто используется для шрифтов и фонов. Цвета также можно использовать для модуляции элементов управления и значков.

  • Constant

    Целочисленное значение, которое может использоваться либо для числовых свойств элементов управления (например, для разделения элементов в BoxContainer), либо для логических флагов (например, для рисования линий отношений в Tree).

  • Font

    Ресурс font, используемый элементами управления для отображения текста. Шрифты содержат большинство настроек отрисовки текста, за исключением его размера и цвета. Кроме того, выравнивание и направление текста задаются отдельными элементами управления.

  • Font size

    Целочисленное значение, которое используется вместе со шрифтом для определения размера отображаемого текста.

  • Icon

    Ресурс texture, который обычно используется для отображения значка (например, на Button).

  • StyleBox

    Ресурс StyleBox, представляющий собой набор параметров конфигурации, определяющих способ отображения панели пользовательского интерфейса. Это относится не только к элементу управления Panel, поскольку стили используются многими элементами управления для фонов и наложений.

    Различные элементы управления применяют элементы StyleBox по-разному. В частности, элементы StyleBox focus отображаются как наложение на другие элементы StyleBox (например, normal или pressed), чтобы базовый элемент StyleBox оставался видимым. Это означает, что элемент StyleBox фокуса должен быть оформлен как контур или полупрозрачный блок, чтобы его фон оставался видимым.

Типы тем

Для упрощения организации элементов каждая тема разделена на типы, каждый из которых должен принадлежать к одному типу. Другими словами, каждый элемент темы определяется своим именем, типом данных и типом темы. Эта комбинация должна быть уникальной в пределах темы. Например, в типе Label не может быть двух элементов цвета с именем font_color, но в типе LineEdit может быть другой элемент font_color.

Тема Godot по умолчанию содержит несколько типов тем, по одному для каждого встроенного узла элемента управления, использующего скины пользовательского интерфейса. В примере выше представлены реальные элементы темы, присутствующие в теме по умолчанию. Вы можете обратиться к разделу Theme Properties в справочнике классов для каждого элемента управления, чтобы узнать, какие элементы доступны для него и его дочерних классов.

Примечание

Дочерние классы могут использовать элементы темы, определённые для родительского класса (например, Button и его производные). Фактически, каждый элемент управления может использовать любой элемент темы любого типа, если это необходимо (но для ясности и предсказуемости мы стараемся избегать этого в движке).

Важно помнить, что для дочерних классов этот процесс автоматизирован. Всякий раз, когда встроенный элемент управления запрашивает элемент темы, он может опустить тип темы, и вместо него будет использовано имя его класса. Кроме того, в свою очередь будут использоваться имена классов его родительских классов. Это позволяет изменять родительский класс, например Button, чтобы повлиять на все производные классы без необходимости настраивать каждый из них.

Вы также можете определить собственные типы тем и дополнительно настроить как встроенные, так и ваши собственные элементы управления. Поскольку встроенные элементы управления не имеют информации о ваших пользовательских типах тем, для доступа к ним необходимо использовать скрипты. Все узлы элементов управления имеют несколько методов, позволяющих извлекать элементы темы из примененной к ним темы. Эти методы принимают тип темы в качестве одного из аргументов.

var accent_color = get_theme_color("accent_color", "MyType")
label.add_theme_color_override("font_color", accent_color)

Чтобы предоставить больше возможностей для настройки, типы можно также соединять вместе в виде вариантов типов. Это еще один случай использования пользовательских типов тем. Например, тема может содержать тип Header, который может быть отмечен как вариация базового типа Label. Затем отдельный элемент управления Label можно настроить на использование вариации Header для своего типа, и каждый раз, когда элемент темы запрашивается из темы, эта вариация будет использоваться перед любым другим типом. Это позволяет хранить различные предустановки элементов темы для одного и того же класса узла управления в одном ресурсе Theme.

Предупреждение

В качестве вариантов в панели инспектора отображаются только вариации, доступные в теме по умолчанию или определенные в пользовательской теме проекта. Вы по-прежнему можете вручную ввести название вариации, определенной вне этих двух мест, но рекомендуется сохранять все вариации в теме проекта.

Подробнее о создании и использовании вариаций типов тем можно узнать в специальной статье.

Настройка элементов управления

Каждый узел элемента управления можно настраивать напрямую, без использования тем. Это называется "локальным переопределением". Каждое свойство темы из ссылки на класс элемента управления можно переопределить непосредственно в самом элементе управления, используя панель инспектора или скрипты. Это позволяет вносить детальные изменения в определённую часть пользовательского интерфейса, не затрагивая при этом остальные элементы проекта, включая дочерние элементы этого элемента управления.

../../_images/themecheck.webp

Локальные переопределения менее полезны для визуального оформления пользовательского интерфейса, особенно если вы стремитесь к единообразию. Однако для узлов макета они необходимы. Такие узлы, как BoxContainer и GridContainer, используют константы темы для определения разделителей между дочерними элементами, а MarginContainer сохраняет настраиваемые поля в элементах темы.

Если элемент управления переопределяет локальный элемент темы, он использует это значение. Значения, предоставляемые темой, игнорируются.

Настройка проекта

По умолчанию каждый проект использует тему проекта по умолчанию, предоставленную Godot. Сама тема по умолчанию постоянна и не может быть изменена, но её элементы можно переопределить пользовательской темой. Пользовательские темы можно применять двумя способами: как настройку проекта и как свойство узла в дереве управляющих узлов.

Существует два параметра проекта, которые можно изменить для всего проекта: GUI > Theme > Custom позволяет задать пользовательскую тему для всего проекта, а GUI > Theme > Custom Font делает то же самое для резервного шрифта по умолчанию. При запросе элемента темы узлом управления сначала проверяется пользовательская тема проекта, если она есть. Только если элемент отсутствует, проверяется тема по умолчанию.

Это позволяет вам настроить внешний вид каждого элемента управления Godot по умолчанию с помощью одного ресурса темы, но вы можете сделать это более детально. Каждый узел элемента управления также имеет свойство theme, которое позволяет задать пользовательскую тему для ветви узлов, начинающейся с этого элемента управления. Это означает, что элемент управления и все его дочерние элементы, а также их дочерние элементы в свою очередь, сначала проверят ресурс пользовательской темы, прежде чем вернуться к проекту и темам по умолчанию.

Примечание

Вместо изменения настроек проекта вы можете установить ресурс пользовательской темы в корневой элемент управления всей ветки пользовательского интерфейса, что даст практически тот же эффект. В запущенном проекте всё будет работать как и ожидалось, но отдельные сцены будут по-прежнему использовать тему по умолчанию при предварительном просмотре или непосредственном запуске. Чтобы исправить это, можно установить тот же ресурс темы в корневой элемент управления каждой отдельной сцены.

Например, вы можете использовать определенный стиль для кнопок в теме проекта, но хотите, чтобы кнопки во всплывающем диалоговом окне выглядели по-другому. Вы можете установить ресурс пользовательской темы для корневого элемента управления всплывающего окна и определить другой стиль для кнопок в этом ресурсе. Пока цепочка узлов управления между корнем всплывающего окна и кнопками не прервется, эти кнопки будут использовать стили, определенные в ближайшем к ним ресурсе темы. Все остальные элементы управления будут по-прежнему оформлены с использованием общей темы проекта и стилей темы по умолчанию.

Подводя итог, для произвольного элемента управления поиск его элемента темы будет выглядеть примерно так:

  1. Проверьте наличие локальных переопределений того же типа данных и имени.

  2. Используя вариацию типа элемента управления, имя класса и имена родительских классов:

    1. Проверьте каждый элемент управления, начиная с него самого, и посмотрите, установлено ли для него свойство темы;

    2. Если это так, проверьте тему на наличие соответствующего элемента с таким же именем, данными и типом темы;

    3. Если пользовательской темы нет или в ней нет элемента, перейдите к родительскому элементу управления;

    4. Повторяйте шаги a–c, пока не будет достигнут корень дерева или неконтролируемый узел.

  3. Используя вариацию типа элемента управления, имя класса и имена родительских классов, проверьте тему проекта, если она присутствует.

  4. Используя вариацию типа элемента управления, имя класса и имена родительских классов, проверьте тему по умолчанию.

Даже если элемент не существует ни в одной теме, будет возвращено соответствующее значение по умолчанию для этого типа данных.

Не только controls

Разумеется, темы — идеальный тип ресурса для хранения конфигурации чего-либо визуального. Хотя поддержка тем встроена в узлы управления, другие узлы также могут использовать их, как и любой другой ресурс.

Примером использования тем для чего-то помимо управления может быть модуляция спрайтов для одних и тех же юнитов в разных командах в стратегической игре. Ресурс темы может определить коллекцию цветов, а спрайты (с помощью скриптов) могут использовать эти цвета для рисования текстуры. Главное преимущество заключается в том, что вы можете создавать разные темы, используя одни и те же элементы темы для красной, синей и зеленой команд, и менять их местами одним изменением ресурса.