Академический Документы
Профессиональный Документы
Культура Документы
Development
Unreal Engine
MIDDLE
Урок 5
Создание виджета
инвентаря
2
Инвентарь. Создание виджета инвентаря
Инвентарь.
Создание виджета инвентаря
Инвентарь — это элемент игрового интерфейса, ши-
роко используемый во множестве проектов, от детских
приключенческих игр до шутеров от первого лица и RPG.
В инвентаре персонажа могут храниться предметы,
необходимые для выполнения квестов, оружие и доспе-
хи, пища, зелья, драгоценности. При этом все собранные
объекты нередко рассортированы по категориям (рис. 1).
Рисунок 1
Давайте создадим собственный инвентарь на движ-
ке Unreal Engine 4. Для этого воспользуемся шаблонной
сценой Inventory System c видом сверху (Top Down). Ее
можно найти в дополнительных материалах. В данном
проекте уже реализована первичная структура и логика.
3
Урок 5
Рисунок 2
Откроем редактор данного блупринта и составим
следующую структуру. Добавим Size Box, внутрь кото-
рого поместим Canvas Panel, содержащий кнопку (But
ton) (рис. 3).
Рисунок 3
Также зададим элементу Size Box значение Desired on
Screen, чтобы инвентарь масштабировался согласно со-
держимому (рис. 4).
4
Инвентарь. Создание виджета инвентаря
Рисунок 4
Зададим высоту и ширину этого элемента — 65х65
(рис. 5).
Рисунок 5
5
Урок 5
Рисунок 6
Далее займемся кнопкой. Данный элемент должен
полностью заполнять пространство Canvas Panel. Для
этого переведем его в режим заполнения (выпадающее
меню Anchors) и обнулим размеры по осям X и Y (рис. 7).
Рисунок 7
6
Инвентарь. Создание виджета инвентаря
Рисунок 8
Таким же образом настроим внешний вид остальных
состояний, поменяв цвет для значений Hovered и Pressed
(рис. 9).
Рисунок 9
7
Урок 5
Рисунок 10
Зададим ему следующие настройки (рис. 11):
■■ Padding — 1;
■■ заполнение по горизонтали и вертикали;
■■ Visibility — Hidden.
Рисунок 11
8
Инвентарь. Создание виджета инвентаря
Рисунок 12
Настроим его так, как показано на рисунке 13. В ре-
зультате текст разместится в правом нижнем углу ячейки.
Рисунок 13
Дополнительно уменьшим кегль и добавим небольшую
тень, чтобы текст не терялся на светлом фоне (рис. 14).
9
Урок 5
Рисунок 14
В конце скроем текст так же, как и иконку (рис. 15).
Рисунок 15
Рисунок 16
10
Инвентарь. Создание виджета инвентаря
Рисунок 17
Пропишем логику True/False. Данные ветки будут
проверять, заполнена ли ячейка или нет, и показывать,
либо скрывать иконки объектов сбора (рис. 18–19).
Рисунок 18
11
Урок 5
Рисунок 19
Установим саму текстуру. Для этого скрипт должен
обратиться к ноде ItemInfo и с помощью блока Break вы-
вести информацию в ноду Set Brush from Texture. Про-
блем с размерами быть не должно, так как размер икон-
ки совпадает с размерами кнопки (рис. 20).
Рисунок 20
В конце добавим еще одну ноду — Set Visibility. Дан-
ный параметр указывает на то, что при клике по слоту,
12
Инвентарь. Создание виджета инвентаря
Рисунок 21
Теперь создадим логическую связь заполненной ячей-
ки и выводимого текста. Выделим объект Text и нажмем
Bind — Create Binding (рис. 22).
Рисунок 22
Переименуем созданную функцию в Text Amount
Binding.
Подключим значение Amount с помощью ноды String
к блоку Append. В слот А пропишем знак умножения (*),
а саму ноду Amount подключим в слот В. Данный скрипт
13
Урок 5
Рисунок 23
Таким же образом создадим связь для поведения тек-
ста (Behavior) (рис. 24).
Рисунок 24
Рисунок 25
14
Инвентарь. Создание виджета инвентаря
Рисунок 26
Создадим следующую иерархию вложенных элемен-
тов: Canvas Panel => Vertical Box => Border => Horizontal
Box => Text (рис. 27).
Рисунок 27
Выставим нулевые отступы (Padding) для элемента
Horizontal Box (рис. 28).
15
Урок 5
Рисунок 28
Также настроим текст (рис. 29):
■■ выравнивание по левому краю;
■■ текст — Inventory;
■■ размер шрифта — 22.
Рисунок 29
16
Инвентарь. Создание виджета инвентаря
Рисунок 30
Выставим следующие отступы для текста: слева и спра-
ва по 10, сверху и снизу — 0. В строке Text пропишем X
(рис. 31).
Рисунок 31
Переименуем кнопку на Close Button и зададим ей
отступ 10 по левой стороне. Также переключим размер
17
Урок 5
Рисунок 32
Рисунок 33
18
Инвентарь. Создание виджета инвентаря
Рисунок 34
А также фоновый цвет — черный со значением Alpha =
0,6. В результате инвентарь получится полупрозрачным
(рис. 35).
Рисунок 35
Внутрь SizeBox добавим еще несколько элементов,
как показано на рисунке (рис. 36).
19
Урок 5
Рисунок 36
Выделим Uniform Grid Panel и переименуем ее в Slot
Panel. Отметим галочкой значение Is Variable, чтобы ячей-
ки могли менять свой внешний вид. Также зададим Slot
Padding = 5 (рис. 37).
Рисунок 37
После этого вернемся к SizeBox и зададим выравни-
вание по центру в строке Horizontal Alignment (рис. 38).
Этап визуализации завершен. Теперь необходимо
прописать логику поведения ячеек.
20
Инвентарь. Создание виджета инвентаря
Рисунок 38
Перейдем в Event Graph. Создадим функцию Gener
ateSlotWidget (Сгенерировать виджет слота) и две пере-
менные: Inventory (Инвентарь) и SlotPerRow (Количество
строк со слотами) (рис. 39).
Рисунок 39
Выставим значение последней функции — 5. То есть,
в инвентаре не может появиться больше 5 строк с ячей-
ками (рис. 40).
Рисунок 40
21
Урок 5
Рисунок 41
Далее возьмем функцию Create Widget с классом
W_InventorySlot и подключим его к ноде Add Child to Uni
form Grid. В конце ветки подключим ноды Set Row и Set
Column, которые отвечают за количество строк и коло-
нок в инвентаре (рис. 42).
Создадим формулы, которые будут просчитывать
максимальное количество слотов, относительно которо-
го будет выстраиваться высота инвентаря. Вспомогатель-
ная нода Truncate позволяет избавиться от значений по-
сле запятой, то есть в ячейке будут отображаться только
целые числа (рис. 43).
Похожим образом просчитываем и количество ко-
лонок (рис. 44).
22
Инвентарь. Создание виджета инвентаря
Рисунок 42
Рисунок 43
Рисунок 44
23
Урок 5
Рисунок 45
Подключим данный массив после ноды Create Wid
get (рис. 46).
Рисунок 46
24
Инвентарь. Создание виджета инвентаря
Рисунок 47
Далее создадим еще один UI-виджет w_MainWidget
(рис. 48).
Рисунок 48
Откроем редактор. Найдем виджет W_Inventory и раз-
местим его в том месте экрана, где должен отображаться
инвентарь (рис. 49).
Переименуем объект в InventoryWidget и пометим
галочкой Size to Content (рис. 50).
25
Урок 5
Рисунок 49
Рисунок 50
Далее перейдем в Event Graph данного блупринта
и создадим две переменные Inventory и SlotsPerRow со
значениями Instance Editable и Expose on Spawn (рис. 51).
26
Инвентарь. Создание виджета инвентаря
Рисунок 51
Пропишем логику для EventConstruct, где Inventory
Widget будет обращаться к нодам локальных перемен-
ных. В результате вся информация должна попасть в ноду
Generate Slot Widget (рис. 52).
Рисунок 52
Рисунок 53
27
Урок 5
Рисунок 54
Чтобы объекты отображались в инвентаре, создадим
Custom Event — UpdateSlotAtIndex с входящим параме-
тром Index и подключим Inventory Widget с помощью
массива Slots Widget к ноде Update Slot (рис. 55).
Рисунок 55
28
Инвентарь. Создание виджета инвентаря
Рисунок 56
Скопируем эти блоки и добавим во все ветки после
ноды Set Array Elem.
После этого запускаем игру и начинаем собирать пред-
меты. Если все скрипты выстроены правильно, в инвен-
таре отобразятся бутылки с зельями (рис. 57).
Рисунок 57
29
Урок 5
Рисунок 58
■■ Dragon Age: Inquisition (рис. 59);
Рисунок 59
30
Инвентарь. Создание виджета инвентаря
Рисунок 60
■■ Freddi Fish (рис. 61).
Рисунок 61
31
Урок 5
Рисунок 62
32
Дополнительные материалы
Дополнительные
материалы
Любой проект, прежде всего, нужно структурировать.
Давайте для этого создадим новую папку InventorySystem
и добавим в нее еще 4 папки (рис. 1):
■■ Blueprint;
■■ DragAndDrop;
■■ Textures;
■■ Widget.
Рисунок 1
В папке c текстурами создадим еще одну папку Item
Icons, в которую загрузим иконки предметов для сбо-
ра — карту, зелье и кольцо. Каждый из этих предметов
будет обладать уникальными свойствами и настройка-
ми (рис. 2).
Также, в корень папки Textures загрузим изображе-
ние InventoryButton (рис. 3).
33
Урок 5
Рисунок 2
Рисунок 3
Зайдем в редактор данной текстуры и зададим ей сле-
дующие настройки (рис. 4):
■■ Texture Group => UI, так как данный элемент является
частью пользовательского интерфейса;
■■ Compression => UserInterfase2D (RGBA), для 2D-изоб
ражения.
Далее вернемся в папку с иконками. Выделим все объ-
екты, кликнем ПКМ и вызовем команду Asset Action =>
Bulk Edit via Property Matrix. Данная функция позволяет
одновременно редактировать несколько подобных объ-
ектов (рис. 5).
34
Дополнительные материалы
Рисунок 4
Рисунок 5
Зададим иконкам общую текстурную группу Texture
Group => UI, а также Compression Settings => UserInter
fase2D (RGBA). Далее нажимаем Ctrl+Shift+S => Save All,
чтобы сохранить все изменения (рис. 6).
35
Урок 5
Рисунок 6
Далее структурируем все виды объектов. Для этого
в папке Blueprint создадим подпапку Structure и доба-
вим в нее специальный одноименный блупринт: ПКМ =>
Blueprints => Structure. Назовем его S_ItemInfo (рис. 7).
Рисунок 7
Откроем редактор данного блупринта и создадим
7 классов переменных (рис. 8):
1. Наименование — Name с типом Text.
2. Описание объекта — Description, также с типом Text.
3. Иконки — Icon, тип Texture2D.
36
Дополнительные материалы
Рисунок 8
Чтобы настроить тип последнего класса переменных,
необходимо создать дополнительный блупринт Enumer
ation. Он будет содержать в себе перечисление всех до-
ступных видов объектов. Создадим в папке Blueprints
дополнительную папку Enums и добавим в нее блупринт
37
Урок 5
Рисунок 9
Откроем редактор и добавим 4 типа объектов (рис. 10):
Рисунок 10
1. Consumable — потребляемые предметы (зелья, пища,
напитки и т.д.).
2. Equipment — любые предметы, которые можно одеть
на персонажа (доспехи, кольца и т.д).
38
Дополнительные материалы
Рисунок 11
Дополнительно выставим настройки по умолчанию
(Default Values) для всех новых объектов, как показано
39
Урок 5
Рисунок 12
Откроем редактор данного блупринта и добавим
в него переменную ItemInfo с типом S_ItemInfo, который
был создан ранее (рис. 13).
Рисунок 13
40
Дополнительные материалы
Рисунок 14
Далее вернемся в папку ItemClasses. Выделим bp_Mas
terItem и создадим для него дочерний класс блупринта:
ПКМ => Create Child Blueprint Class. Назовем его Item
HealthPotion (рис. 15).
Рисунок 15
Откроем редактор и зададим настройки по умолча-
нию для данного объекта, как на рисунке 16. Введем имя
предмета — HealthPotion (Зелье здоровья), а также краткое
описание его функций — Use potion for refill your health
(Используй зелье, чтобы восстановить здоровье). Также
подключим иконку объекта в пункте Icon. Далее идут
41
Урок 5
Рисунок 16
Аналогичным образом поступим с двумя другими
объектами — картой и кольцом. Создадим еще два до-
черних класса блупринтов для bp_MasterItem: ItemMap
и ItemRing (рис. 17).
Рисунок 17
Настроим данные блупринты по аналогии с зельем.
42
Дополнительные материалы
Рисунок 18
Рисунок 19
43
Урок 5
Рисунок 20
Создадим две переменные: Item Class типа Bp_Master
Item c классом Reference, и Amount для подсчета количе-
ства ячеек, тип Integer (рис. 21).
Рисунок 21
Сохраняем изменения.
Далее вернемся в папку блупринтов и создадим но-
вый Blueprint типа Actor для самого инвентаря. Переи-
менуем его в bp_Inventory (рис. 22).
44
Дополнительные материалы
Рисунок 22
В редакторе данного блупринта создадим перемен-
ные AmountOfSlots (Количество слотов) и MaxStackSize
(Максимальный размер стека) типа Integer (рис. 23).
Рисунок 23
Рисунок 24
Далее создадим переменную для референса персона-
жа с типом Top Down Character. Дополнительно отметим
галочками опции Instance Editable (Редактируемый объ-
45
Урок 5
Рисунок 25
Прежде всего зададим адаптивность инвентаря в за-
вистимости от количества слотов, заложеного в проект.
Для этого соединим ноду Event BeginPlay, массив Slots
и Amount Of Slots с помощью блока Resize (рис. 26).
Рисунок 26
Далее создадим новую функцию isSlotEmpty?, которая
будет проверять заполненность ячеек (рис. 27).
46
Дополнительные материалы
Рисунок 27
Зададим ей следующие настройки: добавим два па-
раметра входящих и исходящих данных в блоках Inputs
и Outputs. Также отметим галочкой параметр Pure, что-
бы движок не менял состояние классов (рис. 28).
Рисунок 28
Сформируем проверочный скрипт, работающий на
базе логики True/False. Для этого воспользуемся нода-
ми Break и Is Valid Class. Соединим из с массивом Slots
так, как показано на рисунке 29. В результате, если вну-
47
Урок 5
Рисунок 29
Следующая функция, которую необходимо создать, —
GetItemInfoAtIndex. Также добавим ей несколько пара-
метров: один входящий и три исходящих. Дополнитель-
но отметим галочкой значение Pure, как и в предыдущей
функции (рис. 30).
Рисунок 30
Первая половина скрипта, по сути, дублирует пре-
дыдущий. Далее необходимо включить блок Branch, от-
48
Дополнительные материалы
Рисунок 31
Создадим еще одну функцию SearchEmptySlot — по-
иск пустого слота. Создадим для нее два исходящих па-
раметра: Success и Index (рис. 32).
Рисунок 32
Подключим к ней массив Slots через ноду ForEachLoop
WithBreak, чтобы цикл прерывался каждый раз, когда
будет найден пустой слот. После этого подключим ноду
Branch (рис. 33).
49
Урок 5
Рисунок 33
Далее воспользуемся локальными переменными, ко-
торые будут применяться исключительно к этой функ-
ции. Создадим две переменные: local_Bool и localIndex
(рис. 34).
Рисунок 34
Подключим их в скрипт, в ветку True co значением
Set. Отметим галочкой Local Bool, а индекс подключим
в соответствующую строку блока Loop, как показано на
рисунке 35.
Рисунок 35
50
Дополнительные материалы
Рисунок 36
Теперь создадим функцию Search free stack — поиск
свободного стека в инвентаре. Добавим один входящий
параметр ItemClass и два исходящих — Success и Index
(рис. 37).
Рисунок 37
Повторяем стартовую логику скрипта. После это до-
бавим блок Equal, который подключим в строки Item
51
Урок 5
Рисунок 38
Осталось создать две локальные переменные local_
Bool и localIndex, как и в прошлой функции (рис. 39).
Рисунок 39
Следующая функция — AddItem (Добавление предме-
тов). Входящие параметры — ItemClass и Amount, исхо-
дящий — Success. Данная функция немного отличается
от предыдущих. Именно она должна складывать одина-
52
Дополнительные материалы
Рисунок 40
Если предмет уникален, и ячейка может содержать
только один подобный объект, должна срабатывать ло-
гика False. Скрипт должен обратиться к функции Search
Empty Slot, проверить Local Found Index и перейти к ноде
Set Array Elem, где Target Array — это Slots, а Item — Lo
cal Item Class (рис. 41).
Рисунок 41
Чтобы предметы добавлялись в ячейку поштучно,
подключим к ноде Set Array блок Add Item с проверкой,
является ли числовое значение Local Amount >1. То есть,
53
Урок 5
Рисунок 42
Напоследок добавим такой же блок в значение False
функции Search Empty Sloth (рис. 43).
Рисунок 43
54
Дополнительные материалы
Рисунок 44
Если пустая ячейка найдена, сработает значение True,
которое запустит следующий скрипт (рис. 45).
Рисунок 45
В результате в ячейку будет добавлен предмет, если он
не превышает допустимое количество объектов в ячей-
ке, и цикл завершится (рис. 46).
Для значения False срабатывает следующая ветка
(рис. 47).
55
Урок 5
Рисунок 46
Рисунок 47
Если свободный стек все же найден, получаем Local
Found Index. Суммируем его с Local Amount и проверя-
ем, чтобы данное число не оказалось больше значения
MaxStackSize (рис. 48).
Далее прописываем логику True/False. Отрицатель-
ное значение должно учитывать суммированную пере-
менную Local Found Index и Local Amount (рис. 49).
56
Дополнительные материалы
Рисунок 48
Рисунок 49
Ветка True показана на рисунке 50.
Рисунок 50
57
Урок 5
Рисунок 51
Сформируем следующий скрипт (рис. 52).
Рисунок 52
Далее выделим переменную MaxStackSize и пропи-
шем для нее значение максимального количества пред-
58
Дополнительные материалы
Рисунок 53
Таким же образом пропишем максимальное количе-
ство ячеек в инвентаре — 20 (рис. 54).
Рисунок 54
После этого подкорректируем функцию AddItem.
59
Урок 5
Рисунок 55
Теперь подключим ноду Local Amount в строку Rest
в следующих ветках. Данный параметр позволит реали-
зовать логику, в которой все равно будет отображено ко-
личество предметов, даже если нельзя добавить новые
объекты в инвентарь (рис. 56–59).
Рисунок 56
Рисунок 57
60
Дополнительные материалы
Рисунок 58
Рисунок 59
Следующий этап — создать шаблон самих предметов
сбора и прописать логику их добавления в инвентарь.
Прежде, чем создать сам объект, перейдем в блупринт
персонажа. Подключим к ноде Event BeginPlay блок Spawn
Actor frow Class с классом bp_Inventory. Данное действие
отвечает за вызов инвентаря. Замкнем данный блок на
самого персонажа (Self) и выставим настройки Collision
Handing Override на Always Spawn, Ignore Collisions. В кон-
61
Урок 5
Рисунок 60
Далее создаем новый блупринт для объекта сбора
с классом Actor. Называем его bp_PickUpActor (рис. 61).
Рисунок 61
Заходим в редактор, создаем объект Sphere Collision
и подключим к нему дочерний объект Static Mesh, кото-
рый переименуем на Potion Bottle (рис. 62).
62
Дополнительные материалы
Рисунок 62
Подключим на данный мэш модель бутылки с зельем.
Ее можно найти на любом сайте с 3D-моделями, либо
воспользоваться сеткой, заранее загруженной в шаблон
(рис. 63).
Рисунок 63
Далее выделим объект Sphere Collision и добавим ему
ноду On Component Begin Overlap (рис. 64).
Рисунок 64
Подключим к ней ноду самого персонажа (Cast to
TopDown Character). Данная нода должна обращаться
63
Урок 5
Рисунок 65
Дополнительно в обеих локальных переменных от-
мечаем галочками пункты Instance Editable и Expose On
Spawn (рис. 66).
Рисунок 66
64
Дополнительные материалы
Рисунок 67
Сохраним изменения. Теперь можно проверить, сра-
батывает ли скрипт. Для этого нужно разместить не-
сколько предметов сбора в сцене, например, две бутыл-
ки и свиток (рис. 68).
Рисунок 68
65
Урок 5
Рисунок 69
Базовая сцена готова, теперь можно приступать к ви-
зуализации самого инвентаря.
66
Дополнительные материалы
67
Урок 5
Создание виджета инвентаря