Привет! Недавно я размышлял о своем опыте разработчика Unity и решил, что настало время поделиться тем, что я узнал о создании интерфейсов в Unity. Так что если это то, что вы искали, читайте дальше.
Я должен предупредить вас, что эта серия статей не даст вам окончательного руководства по работе с HUD. Здесь я просто хочу поделиться с вами своими мыслями и наблюдениями. Но если вы хотите поделиться собственным опытом или лучшими практиками, пожалуйста, сделайте это в разделе комментариев ниже.
Оглавление
Размещение элементов на Canvas
Разработка для мобильных устройств
Создание пользовательского селектора
Игровые интерфейсы
В целом, игровые интерфейсы - это полнофункциональные отдельные элементы, которые не оказывают прямого влияния на игровой процесс. Их основная задача - предоставлять пользователям полезную игровую информацию, которая может им понадобиться. Технически говоря, вы можете взять что-то простое, как шрифт Arial, и использовать его для отображения здоровья, патронов и очков (если вы делаете шутер). Да, это испортит эстетику (некоторые особо чувствительные пользователи даже заявят, что им нужно обратиться к офтальмологу, взглянув на вашу игру), но никто не будет спорить с тем, что вся необходимая информация будет выведена на экран, громко и четко.
Но это довольно радикальные методы. Естественно, лучший интерфейс - тот, который не навязчив и привлекает внимание пользователя только тогда, когда ему это нужно. Показывать патроны на оружии или уровень здоровья главного героя (привет, Dead Space!) - это решения, которые принимает дизайнер игры. Но мы, разработчики игр, призваны воплотить все эти необычные идеи в реальных играх. Итак, какие возможности по созданию интерфейсов есть в Unity?
Что такое Canvas?
Канва для Unity UI - это область, которая включает в себя все элементы пользовательского интерфейса. Поэтому, когда мы создаем новый игровой объект, холст для него создается автоматически.
Начиная с версии 4.6 для работы с элементами пользовательского интерфейса используется новая версия Unity UI. Элементы HUD (как и простые объекты) организованы в иерархии с корневым объектом, содержащим Canvas. При этом место в иерархии определяет порядок рендеринга: объекты, находящиеся на самом нижнем уровне, рендерятся последними и поэтому располагаются выше всех остальных.
Неважно, какое приложение вы разрабатываете: и 3d, и 2D-игры используют одну и ту же логику при работе с пользовательским интерфейсом. То же самое касается и платформы. Неважно, будет ли это Web с HTML5 или игра для Android - достаточно описать только один Canvas.
Режимы отображения канвы
Режим рендеринга определяет, где будет отображаться Unity UI Canvas (это может быть пространство экрана или мира). У этого параметра есть три различных режима:
- Экранное пространство - наложение - Canvas Canvas будет отображаться поверх всех элементов сцены. Если провести аналогию, то Canvas с элементами - это как окно с наклейками в поезде. Мир за окном меняется (камера перемещается в Unity), но наклейки остаются неизменными. В этом режиме Canvas меняется при изменении размера окна. Он идеально подходит для статичной информации, такой как счет или элементы управления.
- Screen Space - Camera - это то же самое окно, но вместо стикеров в нем трехмерный коллаж (неважно, 2d или 3d игра). Он также располагается поверх всех элементов сцены, но в этом случае элементы холста подчиняются законам перспективы (если тип проекции камеры - Perspective). Этот режим идеально подходит для меню или других элементов, которые должны выглядеть трехмерными.
- World Space - режим, в котором Canvas является элементом сцены и может выступать в качестве вспомогательного элемента других игровых объектов. Этот режим идеально подходит для речевых пузырей персонажей, индикаторов патронов для оружия и т. д.
Размещение элементов на холсте
Для целей верстки каждый элемент пользовательского интерфейса отображается в виде прямоугольника. Два основных компонента для работы с ними - Rect Tool и Rect Transform. Последний - новый компонент, в котором наряду с обычными полями есть специальное поле Anchors.
Якоря определяют, как элементы привязываются к родительскому элементу. Компонент имеет 4 якоря, каждый из которых соответствует одной из вершин элемента. Положение и размер элемента рассчитывается на основе расстояния между вершиной и якорем и позиции якоря. Позиция якоря определяется как процент от родительского элемента. Поэтому, когда все четыре элемента расположены в одном месте, размер элемента постоянен. Если якоря, принадлежащие одной плоскости (верхней и нижней или левой и правой), расположены в одной точке, элемент растягивается вдоль этой оси. Если якоря, принадлежащие одной плоскости, НЕ расположены в одной точке, то будет вычислено процентное положение каждого якоря и добавлено к расстоянию до вершины (оно не меняется).
.
Звучит довольно сложно, не так ли? Но не бойтесь - проведите 10 минут в редакторе, и вы освоите его.
Стоит также упомянуть, что помимо якорей у Rect Transform есть параметры Min, Preferred и Flexible Width и Height, которые можно переопределить с помощью компонента Layout Element (хотя лично я его не использую).
Кстати, разработка Canvas для новой версии Unity UI имеет несколько интересных особенностей. Одна из них - отключение всего пользовательского интерфейса для упрощения работы со сценой. Для этого используйте пункт меню Layer в редакторе.
Сначала кажется, что Rect Transform обеспечивает достаточную функциональность и больше ничего не нужно. Но недавно при написании пользовательского селектора для Facebook мне потребовалось определенным образом сгруппировать элементы.
При разработке для мобильных устройств (если вы не работаете исключительно с iOS) человек сталкивается с проблемой сегментации устройств. Это значит, что его или ее игра будет открываться на самых разных устройствах: 2'' или 9'' смартфонах и даже планшетах. Что делать с учетом этого? У нас есть несколько вариантов.
Разработка для мобильных устройств
Почему не анкоры?
Первое, что приходит на ум, - это якоря. Да, это хороший вариант, если у вас простые экраны без множества дочерних элементов, анимации и прочих пользовательских развлечений. Но при использовании такого типа верстки следует помнить, что меняется именно размер, а не визуальный масштаб элементов. Следовательно, компонент Best fit становится активным в текстовых элементах, а также появляется необходимость контролировать соотношение сторон и привязку к определенным частям экрана или другим элементам. Вот что получилось у меня (этот вариант не очень элегантен, но он работает!).
В пакете пользовательского интерфейса есть компонент Aspect Ratio Fitter. Вот как он работает: в зависимости от типа и изменения размера родительского элемента этот компонент изменяет размер своего собственного игрового объекта, сохраняя соотношение сторон.
Кстати, есть еще один компонент, Content Size Fitter, который работает в обратном направлении: он изменяет размер элемента в зависимости от его содержимого. Обычно он используется с дочерними игровыми объектами, содержащими компоненты Text, но также отлично работает с Layout Element и Grid Layout Group.
Преимущества Canvas Scaler
В настоящее время я использую Canvas Scaler, так как в этом случае компонент добавляется автоматически при создании Canvas в Unity UI. Основным преимуществом использования Canvas Scaler является то, что все дочерние элементы масштабируются (а не просто меняют свой размер). Таким образом, размер шрифта во всех текстах не изменяется, а все элементы, смещенные на несколько единиц, будут выглядеть одинаково на всех экранах.
Canvas Scaler может работать в одном из трех режимов:
- Постоянный пиксельный размер - игровой объект сохраняет свой размер в пикселях независимо от размера экрана.
- Постоянный физический размер - игровой объект сохраняет свой физический размер независимо от размера экрана и его соотношения сторон.
- Масштабировать с размером экрана - игровой объект масштабируется вместе с экраном.
Последний элемент - мой любимый, поскольку он позволяет забыть о фрагментации экрана. Вы просто выбираете целевое разрешение, и Canvas будет оптимально менять свои размеры. Вот почему я хотел бы, чтобы вы рассмотрели его более внимательно.
Вы уже знаете, что у этого режима есть собственное целевое соотношение сторон, которое режим Screen Match Mode использует для изменения текущего холста. Режим сопоставления может иметь один из следующих типов:
- Соответствие ширины или высоты - масштабирование холста в зависимости от соотношения ширины и/или высоты и фактической ширины и высоты устройства.
- Расширить - масштабирование холста для включения более широкой стороны (размер холста никогда не будет меньше указанного).
- Сжать - масштабирование холста в меньшую сторону (размер холста никогда не будет больше указанного).
И хотя у каждого из режимов есть свои преимущества, режим Match Width Or Height по-прежнему остается моим личным фаворитом. У этого режима есть еще одна полезная особенность: можно указать, какая из осей будет использоваться в качестве целевой, а какая - в качестве опорной (весь Canvas будет увеличен в зависимости от ширины, высоты или обеих).
Это реализовано с помощью параметра Match, где переменная float [0;1] используется для определения соотношения сторон. Если float = 0, изменения будут происходить по ширине, если float = 1 - по высоте. При заданном соотношении сторон в ландшафтном режиме, если Match = 0, мы получим эффект Expand, если Match = 1 - Shrink (в портретном режиме все наоборот: если Match = 0, мы получим Shrink, если Match = 1 - Expand).
Последний параметр Canvas Scaler - Reference Pixels per Unit, определяющий, сколько пикселей содержится в одной единице элемента пользовательского интерфейса. Его значение по умолчанию равно 100 метрам. Он работает с компонентами Image, поэтому если в вашей сцене каждый метр равен 100 пикселям изображения и вы используете физику Unity, это значение - то, что вам нужно.
Создание пользовательского селектора
Как я уже говорил, в моем случае задача заключалась в написании пользовательского селектора для Facebook. Нам нужен был динамически генерируемый список, из которого можно было бы удалять элементы на ходу. И хотя работа с Facebook API - это отдельная тема, давайте закончим обзор Unity UI новой версии макетами.
Как видите, с некоторыми компонентами мы уже знакомы. Так что давайте познакомимся с теми, о которых мы ничего не знаем.
Группа холста
Этот компонент очень прост в настройке, но, тем не менее, он очень мощный. Он позволяет управлять свойствами всех дочерних элементов объекта. Он полезен, когда нам нужно сделать активной определенную часть и запретить ей реагировать на взаимодействие с пользователем (через Raycast).
Для лучшего понимания создайте две одинаковые панели с кнопками и флажками. Добавьте этот компонент на одну из них и попробуйте изменить значения параметров.
И, наконец, самая интересная часть.
HorizontalLayoutGroup и VerticalLayoutGroup
Два компонента размещают все дочерние компоненты по горизонтали и вертикали, один за другим. Для дочерних элементов можно указать как подложку, так и расстояние между ними. Объекты также могут быть указаны относительно краев родительского объекта.
Учитывая, что элементы будут располагаться только в одной плоскости (горизонтальной или вертикальной), последний параметр (он включает два флажка) позволяет растянуть все дочерние элементы до высоты или ширины родительского элемента.
GridLayoutGroup
Если вам нужно создать таблицу, включающую однородные элементы, это именно то, что вы должны использовать! У него есть padding и spacing (как и у предыдущих элементов), но нам нужно указать размеры дочернего элемента. Они будут использоваться для изменения всех объектов, которые мы добавим к родительскому элементу.
Затем нужно указать StartCorner, который будет использоваться для определения позиции первого элемента, и StartAxis, который будет использоваться для указания осей заполнения (для строк и столбцов). Если вы выберете Vertical, то элементы будут использоваться для заполнения текущего столбца до тех пор, пока не будет достигнут край родительского элемента. Затем будет заполнен следующий столбец. С Горизонтальной все наоборот: родительский элемент заполняется строками. После того как мы указали, куда и как добавлять элементы, логично будет указать их выравнивание.
Последний параметр - Constraint. Он определяет, имеет ли данный макет определенное количество столбцов и строк или количество столбцов и строк рассчитывается на основе размера родительского элемента. Стоит помнить, что GroupLayout, в отличие от всех остальных компонентов макета, предварительно задает размер дочерних элементов с помощью Cell Size (ему безразличны Min, Preferred и Flexible размеры).
Кроме того, вы можете комбинировать GridLayoutGroup с ContantSizeFitter. Но для меня это было лишним. Судя по официальной документации, это не должно быть проблемой.
Вот конечный результат для моего случая:
Каждый элемент был добавлен автоматически, инициализируясь из префаба. Как видите, мы не можем изменить размер и положение элемента, поскольку они определены в GridLayoutGroup.
Кстати, элемент был создан отдельно от панели, которая была необходима для его дальнейшего удержания. Все, что мне нужно было сделать, это скопировать размер элемента в компонент CellSize в GroupLayout. Чтобы жестко задать размер элемента, я указал тип масштабирования Match Width Or Height для CanvasScaler.
Вот и все о возможностях нового пользовательского интерфейса. Эта статья - попытка систематизировать новый опыт, но если она окажется полезной для кого-то еще, я буду только рад.
До свидания, и спасибо за всю рыбу.
Нужна MVP-разработка, приложения для iOS и Android или прототипирование? Посмотрите наше портфолио и оформите заказ уже сегодня!