Unity UI Toolkit: Быстрый старт
Всем привет!
В игре может быть множество элементов интерфейса, всплывающих окон и т. д., и когда появится необходимость изменить общий стиль, например цвет кнопки или текста, то придется это менять во всех созданных элементах, если используется старая система UI Canvas — uGUI (IMGUI забудем как страшный сон). Не так давно Unity предоставили новую систему UI Toolkit, вдохновленную веб-технологиями (HTML-CSS vs UXML-USS) и позволяющую изменить цвет, шрифт и другие свойства всех элементов в игре одним движением. Преимуществ много, например можно подключить веб-дизайнера, и он тут быстро освоится.
Как и ожидается при появлении новой технологии, внятная документация отсутствует, статей в интернете мало и информации в них кусочками. Официальную документацию стараются делать, но явно не для людей. А так как мы все ценим свое драгоценное время, когда еще и горят дедлайны, мы хотим быстро и без лишних затрат использовать все удобства в разработке. Целью данной статьи как раз и является помощь в быстром освоении нового подхода Unity в создании интерфейсов, чтобы не отвлекаться на рысканье в потоках бессвязной документации и продолжать реализовывать свою фантазию или фантазию заказчика. Давно не доходили руки до написания статьи, но пора бы уже уронить свою каплю в море.
Для демонстрации основных часто используемых функций займемся созданием окошка с вводом текста, выбором из подгружаемого кодом списка и обработкой нажатия кнопки. Пусть это будет меню кафешки, когда нам захотелось перекусить. Это будет для вас отправной точкой для создания более сложных интерфейсов.
Установка UI Toolkit
Меню Window — Package Manager — Кнопка + — Add package from git URL… — com.unity.ui — Add
Изображение
После этого в меню Window появится новый пункт UI Toolkit.
Создание интерфейса
Меню Window — UI Toolkit — UI Builder
Изображение
Кратко пройдемся по редактору:
(1) — Viewport — рабочее пространство, видим что создаем
(2) — StyleSheets — перечень классов USS
(3) — Hierarchy — иерархия всех элементов на странице
(4) — Library — набор стандартных элементов управления
(5) — Inspector — визуальное средство редактирования свойств
Начнем с корневого элемента, назовем его Panel:
Изображение
Добавим класс, тут же попросит сохранить:
Изображение
На видео получилась такая последовательность сохранений:
Сохраняется файл стилей USS.
Сохраняется страница с разметкой UXML.
Опять потребовало сохранить UXML, с первого раза видимо ему непонятно, не знаю как у вас, но у меня так всегда.
Здесь я нажал Ctrl-S для очередной попытки, т.к. в панели Viewport (1) продолжала висеть звездочка рядом с названием файла — это означает, что сохранение не произошло.
Он так себя ведет первый раз, потом в процессе работы просто нажимайте Ctrl-S, чтобы сохранить весь прогресс.
Теперь обязательно сделайте вот что:
Переходим на сцену.
Создаем пустой объект.
Добавим в него компонент UI Document.
Изображение
В панели Project — Create — UI Toolkit — Panel Settings Asset.
Изображение
Переносим его в свойство Panel Settings компонента UI Document.
Файл cafe.uxml переносим в свойство Source Asset компонента UI Document.
Изображение
Закрываем панель UI Builder.
Открываем панель UI Builder (уже весело).
Для чего вот это вот все? В панели Viewport (1) появился важный пункт Unity Default Runtime Theme. Он позволяет во время редактирования видеть, как будет выглядеть интерфейс в игре. Зачем они сделали Dark и Light Editor Theme, которые выглядят совсем иначе и не связаны с игрой, только им известно.
Изображение
Продолжаем веселье, заново создавая корневой элемент Panel, т.к. он потерялся из-за манипуляций с сохранениями. Не переживайте, потом ничто никуда не потеряется, только первый раз Unity решает покапризничать. Перетаскиваем класс .panel на элемент Panel, после чего окно инспектора должно выглядеть так:
Изображение
Видим, что класс добавлен в элемент.
Теперь щелкаем на название класса в окне StyleSheets (2), чтобы менять свойства. Не перепутайте, щелкая на элемент в иерархии (3), иначе вы будете менять свойства только одного элемента, а нам нужно изменять все окна в игре, редактируя класс.
Установим ширину окна, выравниваем его по центру экрана с помощью margin: auto
(все как для веб), цвет настроения черный с легкой прозрачностью, и border-radius: 10px
.
Изображение
Добавим заголовок окна. Переносим Label на нашу #Panel и убеждаемся, что она упала дочерним элементом, т.к. тут часто можно промахнуться, и элемент становится соседним, а не вложенным.
Изображение
В классе .panel установим цвет текста, чтобы цвет наследовался всем вложенным элементам, тут тоже все как в веб.
Изображение
Добавим класс для заголовка, просто установив шрифт чуть больше, и перетянем его на метку.
Изображение
В инспекторе можете сами пройтись по атрибутам, там все интуитивно понятно. Скажу только сразу, что разметка изначально настроена на технологию flex. Если вы не знакомы с flex, то гугл вам все расскажет. Все правила из веб разработки касаемо flex применимы и здесь.
Также здесь работает и масштабирование как в Canvas. Вначале мы создавали файл настроек Panel Settings Asset, и если на нем щелкнуть в панели Project, то в стандартном инспекторе мы увидим свойства Scale Mode как в Canvas. По умолчанию установлено Constant Physical Size, что для меня лично удобно, я всегда в Canvas переключал на это значение.
Обработчик событий: оживляем кнопку
Зачем нам это все, если мы не сможем это запрограммировать? Добавим обработчик на кнопку.
Добавим кнопку в наше окошко, сохраним и перейдем на сцену. Создаем скрипт с любым названием, например CafeUI. Ранее мы добавили пустой объект с компонентом UI Document. На него и вешаем скрипт. Переходим в редактор кода, например Visual Studio.
Unity рекомендует обрабатывать элементы страницы в методе OnEnable (), так и сделаем. В листинге ниже комментарии все объясняют.
CafeUI.cs
using UnityEngine;
using UnityEngine.UIElements; //ссылка на библиотеку для работы с UI Toolkit
public class CafeUI : MonoBehaviour
{
Button okButton;
void OnEnable()
{
//Получаем ссылку на компонент UIDocument
var uiDocument = GetComponent();
//Находим кнопку таким запросом, в параметр передаем имя кнопки
okButton = uiDocument.rootVisualElement.Q
Единственного удобства uGUI в перетаскивании методов на кнопку тут нет, но и такой способ особо не напрягает.
Список товаров, связывание данных (ListView и Binding)
В кафе должен быть список товаров, и мы, конечно же, хотим формировать его динамически во время выполнения. Источник данных может быть любой, но в данном случае для простоты мы будем генерировать список в коде, чтобы отобразить его в окне.
Кидаем на страницу в UI Builder элемент ListView, установим ему атрибуты fixed-item-height="50" style="height: 120px; margin: 10px;"
. В панели Project создаем новый UXML-документ (Create — UI Toolkit — UI Document), задаем ему имя item.uxml и открываем его двойным щелчком или клавишей Enter. Это будет шаблон элементов списка. Он будет состоять из картинки, названия товара и цены. Должно выглядеть это так:
Изображение
Внизу в коде uxml видно, какие атрибуты выставлены элементам. Здесь можно обойтись без uss-стилей, т.к. других окон у нас не будет, но если у вас должно быть несколько окон со списками, то удобнее будет установить единый стиль для списков в одном uss-файле. Цвет текста будет наследоваться от класса .panel. Корневому элементу установлено расположение вложенных элементов в строку и выравнивание посередине. Картинка 50 px на 50 px, название товара занимает всю оставшуюся область (flex-grow: 1
), и для цены установлена фиксированная ширина, иначе весь список будет кривой, т.к. цена может быть разной.
Далее нужно создать класс, который будет представлять данные о товаре:
Item.cs
public class Item
{
public string Name { get; set; }
public decimal Price { get; set; }
}
Теперь самое сложное. В официальной документации предоставили довольно сложноватый пример, состоящий из нескольких классов и запутанного кода. Я же не люблю плодить много файлов и классов, и максимально упростил пример, чтобы сосредоточиться только лишь на связывании данных. Сделаем все по порядку. Нумерация пунктов соответствует нумерации в комментариях кода.
Инициализируем список товаров. Здесь для простоты создаем список из двух товаров, в реальной игре же источник данных может быть любой — база данных, api-запросы, файлы и т.д.
Находим отображаемый список на странице. Это ListView с именем
list
на главной странице cafe.uxml.Связываем шаблон элементов списка с самим списком.
Связываем данные с отображаемым списком.
Регистрируем событие выбора из списка.
Переносим шаблон item.uxml на переменную
itemsListTemplate
в инспекторе
Изображение
Стилизуем список. Тут пара хитростей. В UI Toolkit есть встроенные классы для каждого контрола, их очень много и можно посмотреть по ссылке https://docs.unity3d.com/2021.3/Documentation/Manual/UIE-ElementRef.html
изменим цвет наведения мыши на элемент списка:
.unity-list-view__item:hover { background-color: rgba(0, 0, 0, 0.2); }
изменим цвет выбранного элемента; второй селектор тут добавлен, чтобы при наведении мыши не менялся цвет выбранного элемента:
.unity-collection-view__item--selected, .unity-collection-view__item--selected:hover { background-color: rgba(255, 255, 255, 0.2); }
Эти селекторы можно добавить прямо в файл index.uss.
CafeUI.cs
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UIElements; //ссылка на библиотеку для работы с UI Toolkit
public class CafeUI : MonoBehaviour
{
Button okButton;
public VisualTreeAsset itemsListTemplate; //uxml-шаблон элементов списка
List- items = new List
- (); //список товаров
ListView itemsListView; //список на странице
void OnEnable()
{
//Получаем ссылку на компонент UIDocument
var uiDocument = GetComponent
();
//Находим кнопку таким запросом, в параметр передаем имя кнопки
okButton = uiDocument.rootVisualElement.Q
Результат работы
USS как CSS
USS максимально схож с CSS, благодаря чему знакомый с веб-разработкой будет чувствовать себя здесь в своей стихии. В вашем распоряжении все возможности из мира CSS:
Использование переменных. Например:
Hidden text
:root {
--general-bg: #4D4D4D;
}
Button {
background-color: var(--general-bg);
}
Вложенность и комбинации селекторов (
selector1 selector2
;selector1 > selector2
;selector1, selector2
…)transform, translate, transition…
И т.д. и т.п. Все возможности перечислены в документации
Полезные ссылки
Создание собственных контролов
Встроенные переменные USS
Справочник USS
Справочник по элементам управления. Их на самом деле много, а в окне UI Builder Library выведены только несколько стандартных
Создание шаблонов. Один шаблон мы уже с вами сделали