Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Unity_в_действии_Джозеф_Хокинг_Рус.pdf
Скачиваний:
83
Добавлен:
21.06.2022
Размер:
26.33 Mб
Скачать

148      Глава 6. Двухмерный GUI для трехмерной игры

Итак, все визуальные элементы уже на своих местах, пришло время обеспечить их интерактивность.

6.3. Программирование интерактивного UI

Для взаимодействия с UI нам потребуется указатель мыши. Если помните, в этой игре его настройки редактируются в методе Start() сценария RayShooter, в котором мы блокировали и скрывали указатель мыши. Такое поведение прекрасно подходило для элементов управления в шутере от первого лица, но оно помешает работе с UI. Удалите эти строки из сценария RayShooter.cs, чтобы получить возможность щелкать на проекционном дисплее.

Кроме того, в сценарий RayShooter.cs нужно добавить строки, блокирующие возможность стрелять в процессе взаимодействия с GUI. Следующий листинг демонстрирует новую версию кода.

Листинг 6.2. Добавление команд взаимодействия с GUI в код сценария RayShooter.cs

using UnityEngine.EventSystems; ¬ Подключение библиотеки для UI-системы.

...

void Update() {

Выделенный курсивом код в сценарии уже

if (Input.GetMouseButtonDown(0) &&

¬ присутствовал; он приведен здесь для справки.

EventSystem.current.IsPointerOverGameObject(); ¬ Проверяем, что GUI не используется.

Vector3 point = new Vector3( camera.pixelWidth/2, camera.pixelHeight/2, 0);

...

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

СОВЕТ  Иногда только что созданные элементы взаимодействия с UI могут мешать игре. Помните автоматически появившийся вместе с холстом объект EventSystem? Он контролирует в числе прочего и элементы интерфейса, по умолчанию используя для взаимодействия с GUI кнопки со стрелками. Имеет смысл отключить режим работы с этими кнопками для компонента EventSystem: выделите его на вкладке Hierarchy и на панели Inspector сбросьте флажок Send Navigation Event.

Однако щелчок на кнопке пока ни к чему не приводит, так как она не связана ни с каким кодом. Давайте исправим этот недостаток.

6.3.1. Программирование невидимого объекта UIController

В общем случае программирование взаимодействия с элементами UI сводится к стандартной процедуре, общей для всех элементов:

1.В сцене создается UI-объект (в нашем случае это созданная в предыдущем разделе кнопка).

6.3. Программирование интерактивного UI      149

2.Пишется сценарий, который будет вызываться при обращении к этому элементу UI.

3.Сценарий присоединяется к объекту в сцене.

4.Элементы UI (например, кнопки) связываются с объектом, к которому присоединен этот сценарий.

Кнопка у вас уже есть, осталось создать контроллер, который будет с ней связываться. Создайте сценарий с именем UIController (его код приведен в следующем листинге) и перетащите этот сценарий на объект-контроллер в сцене.

Листинг 6.3. Сценарий UIController, предназначенный для программирования кнопок

using UnityEngine;

using UnityEngine.UI; ¬ Импорт инфраструктуры для работы с кодом UI. using System.Collections;

public class UIController : MonoBehaviour {

[SerializeField] private Text scoreLabel; ¬ Объект сцены Reference Text, предназначенный для задания свойства text.

void Update() {

scoreLabel.text = Time.realtimeSinceStartup.ToString();

}

public void OnOpenSettings() { ¬ Метод, вызываемый кнопкой настроек.

Debug.Log("open settings");

}

}

СОВЕТ  Скорее всего, вам интересно, зачем нам два объекта: SceneController и UIController. Ведь наша сцена настолько проста, что с управлением ее объектами и элементами интерфейса вполне мог бы справиться один контроллер. Но по мере ее усложнения вы убедитесь, что намного лучше иметь отдельные модули управления, взаимодействующие друг с другом косвенным образом. Этот принцип применим не только к играм, но и к программному обеспечению в целом; в среде разработчиков ПО такой подход называют разделением ответственности (separation of concerns).

Теперь нужно перетащить объекты на ячейки компонентов, чтобы связать их друг с другом. Перетащите созданный нами для отображения счета текстовый объект на поле Score Label объекта UIController. После этого код сценария UIController начнет определять отображаемый в данной подписи текст. В настоящее время отображаются значения времени — мы добавили таймер, чтобы протестировать, как все работает; чуть позже мы заменим значения времени набранными игроком очками.

Теперь нужно снабдить кнопку элементом OnClick, чтобы добавить ее к объекту-кон- троллеру. Выделите кнопку и найдите в нижней части панели Inspector поле OnClick; изначально оно пустое, но, как показано на рис. 6.12, можно щелкнуть на кнопке со значком + (плюс) и добавить туда элемент. Каждый элемент определяет одну функцию, вызываемую щелчком на кнопке; в листинге присутствуют как ячейка для объекта, так и меню для вызываемой функции. Перетащите на ячейку объект-контрол- лер, выделите в меню строку UIController и выберите в дополнительном меню вариант

OnOpenSettings().

150      Глава 6. Двухмерный GUI для трехмерной игры

П OnClick

а а а

Щ а +

а

• а

П а• • • а • • • • •• • • •

Рис. 6.12. Поле OnClick в нижней части панели с настройками кнопки

РЕАКЦИЯ НА ОСТАЛЬНЫЕ СОБЫТИЯ МЫШИ

Наша кнопка реагирует только на событие OnClick, в то время как UI-элементы могут отвечать на разные варианты взаимодействий. Для программирования взаимодействий, отличных от заданных по умолчанию, пользуйтесь компонентом EventTrigger.

Добавьте к кнопке новый компонент и найдите раздел Event в меню этого компонента. Выберите там вариант EventTrigger. Хотя событие OnClick кнопки отвечает только на полноценный щелчок (кнопка мыши нажимается, а затем отпускается), попробуем запрограммировать реакцию только на нажатие кнопки мыши. Последовательность действий будет той же самой, что и для события OnClick, просто на этот раз мы укажем реакцию на другое событие. Первым делом добавьте в сценарий UIController еще один метод:

...

public void OnPointerDown() { Debug.Log("pointer down");

}

...

Щелкните на кнопке Add New Event Type для добавления нового типа к компоненту EventTrigger. Выберите вариант Pointer Down. Появится пустое поле для этого события, полностью аналогичное полю для события OnClick. Щелкните на кнопке со значком + (плюс), чтобы добавить элемент, и перетащите на этот элемент объект-контроллер, после чего выберите в меню вариант

OnPointerDown(). Все готово!

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

6.3.2. Создание всплывающего окна

Наш интерфейс содержит кнопку, открывающую окно диалога, при этом само окно пока отсутствует. Его роль будет играть новый объект-изображение с присоединенными к нему элементами управления (такими, как кнопки и ползунки). Первым делом следует создать новое изображение, поэтому выберите в меню GameObject команду UI, а затем — команду Image. Как и раньше, на панели Inspector вы найдете ячейку Source Image. Перетащите на нее спрайт с именем popup.

По умолчанию спрайт масштабируется под размеры объекта-изображения; именно это происходило со спрайтами, предназначенными для отображения счета и кнопки настроек, и вы щелкали на кнопке Set Native Size, чтобы подогнать объект под размер картинки. Это стандартное поведение объектов-изображений, но у всплывающего окна другое назначение.

6.3. Программирование интерактивного UI      151

Как показано на рис. 6.13, у компонента image есть параметр Image Type. По умолчанию он имеет значение Simple, что раньше нас вполне устраивало. Но для всплывающего окна присвойте параметру Image Type значение Sliced.

И а

К а Set Native Size а

а а

- а а а Simple,

Simple а Sliced

‚ƒ

 

„ а Fill Center

Рис. 6.13. Параметр Image Type компонента image

Переход к фрагментированному изображению может завершиться сообщением об ошибке, информирующим, что у изображения отсутствуют границы. Дело в том, что спрайт popup пока не разделен на девять частей. В этом случае выделите этот спрайт на вкладке Project и на панели Inspector щелкните на кнопке Sprite Editor, как показано на рис. 6.14. Откроется окно диалога Sprite Editor.

 

 

а а

 

а а• а.

 

В • L R B T

 

(Left Right Bottom Top)

 

‡ а 12, ‹

 

а 12 ‡ ,

Щ а

‡а аŒŽ ‘ а

Sprite Editor…

 

Рис. 6.14. Кнопка Sprite Editor на панели Inspector и открываемое ею окно

ОПРЕДЕЛЕНИЕ  Фрагментированное изображение (sliced image) разбито на девять частей, которые масштабируются по-разному. Масштабируя края отдельно от середины, вы гарантируете сохранение четких и резких границ при любом изменении размеров. В других инструментах разработки имена таких изображений часто содержат цифру 9 (например, 9-slice, 9-patch, scale-9), что подчеркивает факт разделения на девять частей.

В окне Sprite Editor вы увидите зеленые линии, указывающие, каким образом будет осуществляться разбивка изображения. Изначально границ у нашего спрайта нет (то есть величина всех границ равна 0). Увеличьте ширину границ со всех сторон, чтобы получить показанный на рис. 6.14 результат. Так как все четыре параметра (Left, Right, Bottom и Top) имеют значение 12 пикселов, то пересекающиеся зеленые линии поделят изображение на девять частей. Закройте окно редактора и примените сделанные изменения.

Теперь, когда спрайт разделен на девять частей, параметр Image Type без проблем примет значение Sliced (а внизу появится флажок Fill Center). Перетащите находящийся в любом из углов изображения манипулятор синего цвета, чтобы выполнить масштабирование (если вы не видите манипуляторов, активируйте описанный в главе 5

152      Глава 6. Двухмерный GUI для трехмерной игры

инструмент Rect). Боковые фрагменты при этом сохранят свои размеры, в то время как центральная часть поменяет масштаб.

Это свойство боковых фрагментов сохраняет резкость границ изображения при любом изменении размеров, что идеально подходит для UI-элементов: различные окна могут иметь разные размеры, но выглядеть при этом должны одинаково. Сделайте ширину нашего окна равной 250, а высоту — 200, придав ему такой же вид, как на рис. 6.15 (заодно убедитесь, что оно находится в точке с координатами 0, 0, 0).

Рис. 6.15. Фрагментированное изображение отмасштабировано до размеров всплывающего окна

СОВЕТ  Способ наложения элементов UI друг на друга определяется порядком их следования на вкладке Hierarchy. Расположите всплывающее окно поверх остальных элементов UI (разумеется, сохранив его связь с холстом). Теперь подвигайте это окно по сцене и посмотрите, каким образом перекрываются изображения. Затем перетащите окно в самый низ иерархического списка дочерних элементов холста, чтобы оно отображалось поверх всего остального.

Итак, всплывающее окно готово, пришла пора написать для него код. Создайте сценарий SettingsPopup (его код представлен в следующем листинге) и перетащите его на наше окно.

Листинг 6.4. Сценарий SettingsPopup для всплывающего окна

using UnityEngine;

using System.Collections;

public class SettingsPopup : MonoBehaviour { public void Open() {

gameObject.SetActive(true); ¬ Активируйте этот объект, чтобы открыть окно.

}

public void Close() {

gameObject.SetActive(false); ¬ Деактивируйте объект, чтобы закрыть окно.

}

}

Теперь откройте сценарий UIController.cs и добавьте в него содержимое следующего листинга.