Приветствую начинающих разработчиков. Сегодня мы научимся создавать простой инвентарь для нашего персонажа. Данный инвертарь подойдёт как для 2д так и для 3д игр, но рассматривать реализацию инвентаря мы будем на примере 2д игры.
Создание макета для инвентаря
Первым делом подготовим наши UI элементы. Для этого с помощью окна Hierarchy создадим объект canvas(UI - Canvas), а в нём создадим 3 UI элемента:
- UI - Panel: Обёртка для нашего слота. Дадим этому объекту название S1.
- UI - Image: Сам слот, в котором будут хранится предметы. Дадим этому объекту название Slot1. Так же вложите данный объект внутр объекта S1.
- UI - Button - TextMeshPro: Кнопка выброса предмета. Дадим этому объекту название Drop1. Так же вложите данный объект внутр объекта S1. Обратите внимание, что внутри данного объекта автоматически создастся и текст для кнопки, который необходимо удалить!
В результате в окне Hierarchy у Вас должно получится так:
Отлично, один слот готов. В нашем примере будет три слота, поэтому продублируйте всё то же самое 3 раза, переименовав объекты для ясности. Должно получится так.
Для слотов(Slot1, Slot2 и Slot3) и для кнопок выброса предметов(Drop1, Drop2 и Drop3) я присвоил картинки простого инвентаря. Теперь весь наш инвентарь на сцене выглядит так:
Отлично! Подготовительная часть завершена, теперь перейдём к написанию наших любимых скриптов. Начнём с самого простого скрипта, который будет отвечать за наш инвентарь. Создадим скрипт C# и назовём его Inventory, и сразу же перетащим его для нашего главного персонажа.
Содержимое скрипта будет следующим:
using UnityEngine;
public class Inventory : MonoBehaviour
{
public bool[] isFull;
public GameObject[] slots;
}
Как видите, скрипт очень маленький. Он хранит только 2 массива:
- isFull хранит массив значений true/false, то-есть информация о том, заполнен ли слот или нет.
- slots хранит массив слотов, которые мы только что создали(Slot1, Slot2 и Slot3).
Так же предлагаю заранее настроить данный скрипт(компонент) в окне Inspector:
- Укажите количество слотов равное трём.
- Перетащите все ваши слоты из окна Hierarchy в поля slots окна Inspector.
Работа с инвентарём завершена. Давайте теперь создадим объекты, которые можно будет подбирать нашим персонажем в инвентарь. Для этой цели я создам 2 разных объекта, например, яблоко и банан. Добавим для них компоненты Rigidbody 2D, и любой из 2D Collider-ов. Внутри компонента коллайдера, в поле Is Trigger поставим галочку для того, чтобы этот предмет можно было подбирать.
Поскольку с этими предметами мы будем довольно часто сталкиваться, то данные объекты сохраним в виде префабов, с названиями Apple и Banan.
Так же для яблока и банана нужно создать ещё по одному префабу, которые будут являться картинками, и появляться/исчезать в наших слотах инвентаря. Поскольку это не игровые объекты, а всего лишь картинки, то в основе этих префабов должны быть UI элементы, то-есть, UI - Image. Компоненты Rigidbody и Collider создавать НЕ нужно! Назовём эти префабы ItemApple и ItemBanan.
В результате у Вас должно получится 2 префаба для игровых объектов, которые персонаж может подбирать, и 2 префаба картинок для инвентаря.
Подбор предметов в инвентарь
Теперь необходимо создать скрипт, который будет отвечать за подбор объектов. Он должен удалять подобранные предметы из игровой сцены, и создавать картинку подобранного предмета в инвентаре.
Для этого создадим скрипт C# с названием Pickup, и заранее присвоим его к тем объектам, которые могут быть подобраны нашим персонажем, а именно, к двум нашим префабам, яблоке и банану, которые имеют названия Apple и Banan.
Теперь пропишем в только что созданный скрипт Pickup следующий код:
using UnityEngine;
public class Pickup : MonoBehaviour
{
private Inventory inventory;
public GameObject slotButton;
private void Start()
{
inventory = GameObject.FindGameObjectWithTag("Player").GetComponent<Inventory>();
}
private void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
for (int j = 0; j < inventory.slots.Length; j++)
{
if (inventory.isFull[j] == false)
{
Destroy(gameObject);
Instantiate(slotButton, inventory.slots[j].transform);
inventory.isFull[j] = true;
break;
}
}
}
}
}
В строке #5 мы создали переменную inventory, в которой будем хранить ссылку на скрипт(клмпонент) нашего инвентаря. А в строке #10 с помощью метода FindGameObjectWithTag(), мы осуществляем поиск по тегу Player, и потом с помощью GetComponent() получаем доступ к компоненту Inventory. Важно: Присвойте тег Player для вашего главного персонажа!
В строке #6 мы создали переменную slotButton, которая будет хранить ссылку на префаб картинки инвентаря. Это нужно для того, чтобы указать, какая картинка будет создаваться в инвентаре, при подборе яблока или банана. Подбираем яблоко - создаётся картинка яблока. Подбираем банан - создаётся картинка банана.
Поскольку наш скрипт уже присвоен к яблоке и банану(Apple и Banan), то давайте в окне Inspector настроим данный скрипт для этих объектов:
- Выбрав префаб Apple, необходимо в поле slotButton компонента Pickup, перетащить префаб картинки яблока(ItemApple).
- Выбрав префаб Banan, необходимо в поле slotButton компонента Pickup, перетащить префаб картинки банана(ItemBanan).
Пример настройки объекта яблока представлен на картинке ниже:
Продолжим разбирать код. В строках #13-28 с помощью метода OnTriggerEnter2D() мы проверяем, вошёл ли какой-либо объект в область нашего коллайдера, и если тег данного объекта Player, то с помощью цикла for, мы проходим по всем слотам! В данном цмкле мы провеяем, если слот пустой, то производим 4 следующих действия:
- С помощью метода Destroy() удаляем наш объект из игровой сцены, который мы только что подобрали (строка #21).
- С помощью метода Instantiate() в нашем инвентаре создаём объект из префаба slotButton (строка #22).
- Указываем, что данный слот в инвентаре не пустой (строка #23).
- Завершаем принудительно цикл, во избежании проблем (строка #24).
Так же обратите внимание, что выполнение всех этих действий происходит в том случае, если у вас имеется хотя бы 1 пустой слот. Если же все слоты в инвентаре будут заполнены, то этот код выполняться не будет.
Готово! Только что мы написали скрипт подбора предметов и запись его в инвентарь. На этом этапе рекоммендую запустить и протестировать работу скрипта, чтобы убедится, что вы всё сделали правильно. Если предметы удаляются из игровой сцены, и записываются в инвентарь, то всё сделано правильно, и можно идти дальше.
Выброска предметов из инвентаря
Теперь нужно создать скрипт выброса предмета, который делает всё с точностью до наоборот. То-есть, удаляет предмет из инвентаря, и создаёт его на игровой сцене. Для этого создадим скрипт с названием Spawn, и заранее присвоим его нашим префабам ItemApple и ItemBanan.
Содержимое данного скрипта следующее:
using UnityEngine;
public class Spawn : MonoBehaviour
{
public GameObject item;
private Transform player;
private void Start()
{
player = GameObject.FindGameObjectWithTag("Player").transform;
}
public void SpawnDroppedItem()
{
Vector2 playerPos = new Vector2(player.position.x + 1, player.position.y);
Instantiate(item, playerPos, Quaternion.identity);
Destroy(gameObject);
}
}
В строке #5 мы создали переменную item, которая будет хранить ссылку на префаб подбираемого объекта. Это нужно для того, чтобы указать, какой объект будет создаваться на игровой сцене, при выброске предмета из инвентаря. Выбрасываем яблоко - создаётся объект яблока. Выбрасываем банан - создаётся объект банана.
В строке #6 мы создали переменную player, в которой будем хранить координаты нашего главного персонажа. Это нужно для того, чтобы понимать, в каком месте пространства создавать выброшенный объект. А в строке #10 мы как раз и присваиваем данной переменной ссылку на координаты игрока.
Ну и самое главное! Мы создали метод SpawnDroppedItem(), который и будет создавать наш подбираемый объект на игровой сцене, и удалять картинку выброшенного предмета из инвентаря. Метод SpawnDroppedItem() должен вызываться при нажатии на кнопку выброса предмета. Поэтому давайте создадим дополнительный скрипт для этого.
Создадим скрипт C# с названием Slot, и заранее присвоим его ко всем нашим слотам(Slot1, Slot2 и Slot3). Содержимое данного скрипта следующее:
using UnityEngine;
public class Slot : MonoBehaviour
{
private Inventory inventory;
public int id;
private void Start()
{
inventory = GameObject.FindGameObjectWithTag("Player").GetComponent<Inventory>();
}
public void DropItem()
{
inventory.isFull[id] = false;
if (transform.childCount > 0)
{
transform.GetChild(0).GetComponent<Spawn>().SpawnDroppedItem();
}
}
}
Как и в предыдущих примерах, в строке #5 и в #10 мы создали переменную, в которой хранится ссылка на инвентарь нашего персонажа. А в строке #6 мы будем хранить уникальный номер для каждого нашего слота в переменной id. Поэтому предлагаю заранее в окне Inspector для каждого нашего слота проставить номера, начиная с 0:
- Для Slot1 в поле id поставим 0.
- Для Slot2 в поле id поставим 1.
- Для Slot3 в поле id поставим 2.
Мы так же написали функцию DropItem(), которая будет запускать функцию SpawnDroppedItem() из скрипта Spawn. Функцию DropItem() нам нужно запускать после нажатия на кнопку выброса предмета из ячейки. Поэтому нам необходимо для кнопок Drop1, Drop2 и Drop3, в окне Inspector добавить события On Click, перетащив туда объекты Slot1, Slot2 и Slot3 соответственно, и выбрать метод Slot.DropItem.
Отлично, для каждой нашей кнопки мы присвоили запуск функции DropItem(), которая в свою очередь запускает функцию SpawnDroppedItem() из скрипта Spawn, которая в свою очередь и выбрасывает предметы из инвентаря на игровую сцену.
Статья получилась очень большой, и я очень рад, что наконец-то её завершил. Буду рад вашим лайкам. А если остались вопросы, пишите в комментариях.
А на какую кнопку теперь подбирать? В коде это же не написано