Важной составляющей инвентаря является возможность посмотреть всю доступную информацию об объекте. В какой-то степени это позволяет улучшить gameplay игры. Так, например, если у вещи доступен просмотр описания, можно погрузить игрока в историю, которая открывает какой-либо квест в игре. Это и касается других характеристик вещи.
Перед тем, как перейти к созданию отображения информации об объекте, я бы посоветовал вам ознакомиться с предыдущими статьями о создании инвентаря: «Улучшаем инвентарь, перемещением по нажатию на Unity» и «Создание простого инвентаря в игре на Unity» [ссылка на статью].
Настраиваем сцену.
Для того, чтобы реализовать отображение информации об объекте, для начала необходимо создать окно, которое отображает информацию об этом самом объекте.
Моё окно отображения выглядит следующим образом:
В окне отображения присутствует следующие компоненты:
- Cell – ячейка, которая содержит иконку объекта;
- Name – наименование объекта;
- Level_circle – уровень и количество очков объекта;
- Layout – слой, содержащий в себе описание объекта, а так же место, для списка характеристик;
- SellMarket – кнопка для продажи вещи на рынке;
- Sell – кнопка для продажи вещи;
- PutOn – кнопка для того, чтобы одеть вещь на игрока;
- Close – кнопка, для того, чтобы закрыть данное окно;
Когда ваше окно будет создано, можно переходить к написанию скриптов.
Пишем скрипты управления окном отображения информации об объекте.
Сразу хотелось бы отметить, что в качестве примера будет использоваться инвентарь от проекта DarkCaves.
И так, в первую очередь хотелось бы показать вам все переменные, которые отвечают за какую-либо информацию об объекте (вещи).
// тип объекта
public enum Type {
armor, // броня
weapon, // оружие
amulet, // амулет
ring // кольцо } // класс объекта
public enum Class {
standard, // стандартный
special, // специальный
rare, // раритетный
individual // индивидуальный
}
[System.Serializable]
public class Item {
public int id = 0; // идентикафиционный номер
public Type type; // тип вещи
public Class @class; // клас вещи
[Header("Информация")]
public string name = ""; // наименование вещи
public string description = ""; // описание вещи
[Header("Характеристики")]
public int level = 1; // уровень вещи
public int glasses = 0; // очки вещи
public int magArmor = 0; // магическая защита
public int damArmor = 0; // физическая защита
public int damage = 0; // урон
public int health = 0; // жизни
[Header("Зачарование")]
public int spellMagArmor = 0; // процент зачарования магической защиты
public int spellDamArmor = 0; // процент зачарования физической защиты
public int spellReverseDamage = 0; // процент зачарования обратного урона
public int spellVampirism = 0; // процент зачарования вампиризма от нанесённого урона
public int spellCriticalDamage = 0; // процент нанесения критического урона
[Header("Объекты")]
public RectTransform gameObject; // объект на сцене
public Texture2D image; // текстура объекта
}
Характеристики, которые я буду отображать:
- Тип вещи;
- Класс вещи;
- Наименование вещи;
- Описание;
- Уровень;
- Очки;
- Магическая защита;
- Физическая защита;
- Урон;
- Жизни.
Метод, который будет отображать данные характеристики необходимо вынести в отдельный скрипт, который называется InfoManager и висит на самом объекте.
Переменные данного скрипта:
public GameObject infoItem; // объект отображения информации об объекте (объект, который выключается при закрытии)
public Transform RectTransformParrent; // родитель для объектов характеристик, отображающихся списком
public GameObject itemObject; // ячейка в списке характеристик
[Space(5)]
public Text nameItem; // текст для отображения наименования об объекте
public Text desriptionItem; // текст для отображения описания об объекте
public Text level; // текст для отображения левела объекта
[Space(5)]
public RawImage icon; // объект для отображения иконки вещи
public Image imageGlasses; // объект для отображения очков вещи
[Space(5)]
public List levels = new List(50); // список левелов
Функции скрипта:
void Awake()
{
// просчитываем очки для левелов
for (int i = 1; i < 50; i++)
{
levels[i] = levels[i - 1] + (i + 1) * 10;
}
} /// /// Функция для указания информации ///
///вся информация о вещи
public void SelectInformation(Item item)
{
nameItem.text = item.name; // указываем наименование вещи
desriptionItem.text = item.description; // указываем описание вещи
icon.texture = item.image; // указываем изображение вещи
// указываем очки вещи
if (item.level > 0 && item.level < 51)
{
// если уровень больше нуля и меньше 50
float glasses = (float)item.glasses; // указываем количество очков вещи
float maxGlasses = (float)levels[item.level]; // указываем максимальное количество очков
if (item.level > 1) // если уровень больше одного
{
glasses -= (float)levels[item.level - 1]; // перерасчитвыаем очки вещи
maxGlasses -= (float)levels[item.level - 1]; // перерасчитываем максимальные очки вещи
}
imageGlasses.fillAmount = glasses / maxGlasses; // указываем очки вещи
}
level.text = item.level.ToString(); // указываем левел вещи
// переменная для расчётов
int y = -110; // -90 - высота на которой создаётся вторая ячейка
// выводим характеристики
GameObject itemClass = (GameObject)Instantiate(itemObject, RectTransformParrent, false); // создаём объект, отображающий класс вещи
itemClass.GetComponent().SelectInfo(ItemManager.type.@class, [email protected]()); // вызываем функцию заполнения информации
if (item.health != 0)
{
// если объект добавляет жизни
GameObject itemHealth = (GameObject)Instantiate(itemObject, RectTransformParrent, false); // создаём объект, отображающий жизни объекта
itemHealth.GetComponent().SelectInfo(ItemManager.type.health, item.health.ToString()); // вызываем функцию заполнения информации
itemHealth.GetComponent().anchoredPosition = new Vector2(itemHealth.GetComponent().anchoredPosition.x, y); // сдвигаем объект на строчку вниз
y -= 80;
// 80 - ширина ячейки + отступ
}
if (item.damage != 0)
{
// если объект добавляет здоровье
GameObject itemDamage = (GameObject)Instantiate(itemObject, RectTransformParrent, false); // создаём объект, отображающий урон объекта
itemDamage.GetComponent().SelectInfo(ItemManager.type.damage, item.damage.ToString()); // вызываем функцию заполнения информации
itemDamage.GetComponent().anchoredPosition = new Vector2(itemDamage.GetComponent().anchoredPosition.x, y); // сдвигаем объект на строчку вниз
y -= 80; // 80 - ширина ячейки + отступ
}
if (item.magArmor != 0)
{
// если объект добавляет магическую броню
GameObject itemMagArmor = (GameObject)Instantiate(itemObject, RectTransformParrent, false); // создаём объект, отображающий магическую броню объекта
itemMagArmor.GetComponent().SelectInfo(ItemManager.type.magArmor, item.magArmor.ToString()); // вызываем функцию заполнения информации
itemMagArmor.GetComponent().anchoredPosition = new Vector2(itemMagArmor.GetComponent().anchoredPosition.x, y); // сдвигаем объект на строчку вниз
y -= 80; // 80 - ширина ячейки + отступ
}
if (item.damArmor != 0)
{
GameObject itemDamArmor = (GameObject)Instantiate(itemObject, RectTransformParrent, false); // создаём объект, отображающий физическую броню объекта
itemDamArmor.GetComponent().SelectInfo(ItemManager.type.damArmor, item.damArmor.ToString()); // вызываем функцию заполнения информации
itemDamArmor.GetComponent().anchoredPosition = new Vector2(itemDamArmor.GetComponent().anchoredPosition.x, y); // сдвигаем объект на строчку вниз
y -= 80; // 80 - ширина ячейки + отступ
}
// добавлять отображение остальнах характеристик
} /// /// функция закрытия окна с отображением характеристик объекта ///
public void Close()
{
// удаляем старые характеристики объекта
for (int i = 0; i < RectTransformParrent.childCount; i++)
Destroy(RectTransformParrent.GetChild(i).gameObject);
// закрываем окно
infoItem.SetActive(false);
}
Данный скрипт имеет три функции. Первая функция – Awake() предназначена для просчитывания максимальных очков для каждого уровня вещи.
Функция - SelectInformation() выполняют основную функцию скрипта – заполняет текстовые поля для информации, информацией об объекте. Для начала заполняется вся статическая информация, которая существует у каждого объекта, а после происходит заполнение динамической информации – жизни, магическая защита, физическая защита, урон.
Следующий скрипт, который необходимо создать, будет отвечать за заполнения характеристик в динамической ячейке. Все динамические ячейки будут создаваться в отдельном столбце.
Вам необходимо создать, объект, который будет иметь следующие параметры:
- Иконку (icon)
- Наименование характеристики (Text)
- Значение характеристики (value)
Этот объект необходимо сохранить в префаб и в последующем указать для скрипта InfoManager.
Создадим скрипт ItemManager и добавим его на объект item.
Текст скрипта:
// тип характеристики
public enum type
{
@class, // класс
health, // здоровье
magArmor, // магическая защита
damArmor, // физическая защита
damage // урон
}
public Image icon; // иконка
public Text name; // наименование
public Text value; // значение
[Header("Иконки")]
public Sprite ic_class; // иконка класса
public Sprite ic_health; // иконка здоровья
public Sprite ic_magArmor; // иконка магической защиты
public Sprite ic_damArmor; // иконка физической защиты
public Sprite ic_damage; // иконка урона ///
/// функция заполнения информации ///
/// ///тип характерисики ///значение характеристики
public void SelectInfo(type types, string values)
{
/// // проверяем какой тип динамической характерисики
switch (types)
{
// если тип характеристики класс
case type.@class:
name.text = "Class item:"; // указываем наименование
// в зависимости от наименования указываем цвет значения
if (values == "standard")
{
value.color = new Color(1, 1, 0);
}
else if (values == "special")
{
value.color = new Color(1, 0.5f, 0);
}
else if (values == "rare")
{
value.color = new Color(1, 0, 0);
}
else if (values == "individual")
{
value.color = new Color(1, 0, 1);
}
icon.sprite = ic_class; // указываем иконку
break;
// если тип здоровье
case type.health:
icon.sprite = ic_health; // указываем иконку
name.text = "Health:"; // указываем наименование
break; // если тип магическая защита
case type.magArmor:
icon.sprite = ic_magArmor; // указываем иконку
name.text = "Magic armor:"; // указываем наименование
break; // если тип физическая защита
case type.damArmor:
icon.sprite = ic_damArmor; // указываем иконку
name.text = "Physical armor:"; // указываем наименование
break; // если тип урон
case type.damage:
icon.sprite = ic_damage; // указываем иконку
name.text = "Damage:"; // указываем наименование
break;
}
value.text = values; // указываем значение
}
Осталось только дописать основной скрипт, который управляет инвентарём. Переходим к редактированию InventoryManager.
Здесь у нас появился новый метод, отвечающий за открытие окна с информацией об объекте:
/// /// Открытие окна информации об объекте /// ///Идентификатор объекта в списке
void OpenItemInformation(int id) {
ItemInfo.SetActive(true); // показываем окно информации об объекта
infoManager.SelectInformation(items[id]); // обновляем информацию об объекта
}
Так же добавились две новые переменные:
public InfoManager infoManager; // скрипт управления окном информации public GameObject ItemInfo; // окно информации
И самая главная функция, отвечающая за полную работу инвентаря, функция Update(). В данной функции открытие инвентаря настроено на двойное нажатие по объекту.
void Update()
{
if (Input.GetKeyDown(KeyCode.Mouse0))
{
if (activeCell != -1 && items[activeCell].gameObject != null)
{
oldActiveCell = activeCell;
OldPositionMouse = Input.mousePosition; // запоминаем координаты мыши
}
}
if (Input.GetKey(KeyCode.Mouse0))
{
if (oldActiveCell != -1)
{
if (Vector2.Distance(OldPositionMouse, Input.mousePosition) > 10)
{ // если дистанция перемещения больше 10
items[oldActiveCell].gameObject.parent = canvas; // меняем родителя для объекта вещи
float x = Input.mousePosition.x / Screen.width * canvas.sizeDelta.x; // расчитвываем координаты мыши
float y = Input.mousePosition.y / Screen.height * canvas.sizeDelta.y; // расчитвываем координаты мыши
items[oldActiveCell].gameObject.anchoredPosition = new Vector2(x, y); // перемещаем объект
}
}
}
if (Input.GetKeyUp(KeyCode.Mouse0))
{
if (activeCell != -1)
{
// если мы навели на ячейку
if (items[activeCell].gameObject == null)
{
// если объекта в ячейке не существует
if (oldActiveCell != -1) { ChangeItem(activeCell, oldActiveCell); ResetItem(activeCell); }
else
{
// если мы не перемещали до этого вещь
if (activeCellClick != -1)
{
// если у нас выделена какая-то вещь
ChangeItem(activeCell, activeCellClick); // меняем вещи местами
ResetItem(activeCell); // перемещаем объект вещи на новую позицию
cells[activeCellClick].GetComponent().enabled = false; // отключаем обводку
activeCellClick = -1; // удаляем сохранение выделенной вещи
}
}
}
else
{
// если в ячейке существует объект
if (oldActiveCell != -1)
{
if (activeCell == oldActiveCell)
{
if (activeCellClick == -1)
{
// проверка на нажатие
if (Vector2.Distance(OldPositionMouse, Input.mousePosition) < 10)
{ // если дистанция перемещения меньше 10
cells[activeCell].GetComponent().enabled = true; // выделяем ячейку
activeCellClick = activeCell; // запоминаем выделенную ячейку
}
}
else
{
if (activeCellClick == activeCell)
{ // если старое нажатие произошло на тот-же самый объект
OpenItemInformation(activeCellClick); // открываем информацию об объекте
} // дописать смену местами
cells[activeCellClick].GetComponent().enabled = false; activeCellClick = -1;
}
}
ResetItem(oldActiveCell);
}
}
}
else
{
// если мы не навели на ячейку
if (oldActiveCell != -1) { ResetItem(oldActiveCell); }
}
oldActiveCell = -1;
}
}
Ну и на этом всё, осталось только настроить сцену.
Настройка сцены.
Для начала необходимо настроить скрипт InfoManager, отвечающий за заполнение информации об объекте. Указываем все поля.
Так же, для клавиши закрытия окна, необходимо указать функцию в скрипте:
После чего переходим к настройке динамической ячейки. Здесь так же, необходимо указать все поля.
Осталось только настроить InventoryManager следующим образом:
- В переменную infoManager нужно указать скрипт, который у меня находится на объекте с информацией;
- А в переменную ItemInfo, необходимо указать сам объект информации.
На этом всё. Если вы всё правильно сделали, то при двойном нажатии на вещь у вас будет открываться информация об объекте.
Автор статьи: Александр Каримов