Существует несколько способов перемещение вещи в инвентаре:
- Перетаскиванием
- Нажатием или выбором
- В этой статье мы разберем, как перемещать вещь, путём перемещения по нажатию. Перед тем как прочитать эту статью, я бы настоятельно рекомендовал вам ознакомиться со статью написанной ранее «Создание простого инвентаря в игре на Unity».
В качестве примера будет использоваться инвентарь из игры DarkCaves.
Настраиваем сцену.
Для начала необходимо настроить игровую сцену, а вернее немного изменить её. После выбора перемещаемой вещи, у нас будет появляться белая обводка вокруг ячейки, поэтому необходимо сделать следующую структуру для каждой ячейки.
В основном ячейки не изменились, на них всё так же находиться текстура и элемент EventTrigger, позволяющий вызывать события наведения и сведения с ячейки. Изменения коснулись текстуры ячейки, она стала белой. Это нужно для того, чтобы добавленный компонент Outline, мог выдавать белую обводку вокруг ячейки. Поэтому устанавливаем белое изображение и добавляем компонент Outline. Все настройки можете выставить самостоятельно.
Что касается самой текстуры, она была перемещена дочерней объекту ячейки.
Обратите внимание, что у компонента image необходимо отключить свойство Raycast Trigger. Нужно это для того, чтобы компонент EventTrigger мог отлавливать райкаст от курсора и обрабатывать события.
На этом настройка сцены закончена, переходим к скрипту.
Дописываем скрипт.
Я не буду описывать весь алгоритм работы скрипта, поскольку это было сделано в статье «Создание простого инвентаря в игре на Unity»
Для начала расскажу, что было изменено.
В первую очередь изменения коснулись класса Item. Данный класс представляет следующую структуру:
// тип объекта
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; // клас вещи
public int level = 0; // уровень вещи
public int glasses = 0; // очки вещи
public int magArmor = 0; // магическая защита
public int damArmor = 0; // физическая защита
public int damage = 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 Image image; // текстура объекта
}
Теперь характеристик у вещи стало значительно больше. В связи с этим добавилась новая функция, которая отвечает за смену двух вещей в массиве:
void ChangeItem(int oldId, int id) { // создаём копию вещи со старой позиции
Item newItem = new Item();
newItem.id = items[oldId].id;
newItem.type = items[oldId].type;
newItem.@class = items[oldId].@class;
newItem.level = items[oldId].level;
newItem.glasses = items[oldId].glasses;
newItem.magArmor = items[oldId].magArmor;
newItem.damArmor = items[oldId].damArmor;
newItem.damage = items[oldId].damage;
newItem.spellMagArmor = items[oldId].spellMagArmor;
newItem.spellDamArmor = items[oldId].spellDamArmor;
newItem.spellReverseDamage = items[oldId].spellReverseDamage;
newItem.spellVampirism = items[oldId].spellVampirism;
newItem.spellCriticalDamage = items[oldId].spellCriticalDamage;
newItem.gameObject = items[oldId].gameObject;
newItem.image = items[oldId].image; // на старую позицию перемещаем вещь с новой позиции
items[oldId].id = items[id].id;
items[oldId].type = items[id].type;
items[oldId].@class = items[id].@class;
items[oldId].level = items[id].level;
items[oldId].glasses = items[id].glasses;
items[oldId].magArmor = items[id].magArmor;
items[oldId].damArmor = items[id].damArmor;
items[oldId].damage = items[id].damage;
items[oldId].spellMagArmor = items[id].spellMagArmor;
items[oldId].spellDamArmor = items[id].spellDamArmor;
items[oldId].spellReverseDamage = items[id].spellReverseDamage;
items[oldId].spellVampirism = items[id].spellVampirism;
items[oldId].spellCriticalDamage = items[id].spellCriticalDamage;
items[oldId].gameObject = items[id].gameObject;
items[oldId].image = items[id].image; // на новую позицию перемещаем копию вещи со старой позиции
items[id].id = newItem.id;
items[id].type = newItem.type;
items[id].@class = newItem.@class;
items[id].level = newItem.level;
items[id].glasses = newItem.glasses;
items[id].magArmor = newItem.magArmor;
items[id].damArmor = newItem.damArmor;
items[id].damage = newItem.damage;
items[id].spellMagArmor = newItem.spellMagArmor;
items[id].spellDamArmor = newItem.spellDamArmor;
items[id].spellReverseDamage = newItem.spellReverseDamage;
items[id].spellVampirism = newItem.spellVampirism;
items[id].spellCriticalDamage = newItem.spellCriticalDamage;
items[id].gameObject = newItem.gameObject;
items[id].image = newItem.image;
}
В данную функцию необходимо отправить два идентификационных номера, номер ячейки с которой происходит перемещение, и номер ячейки на которую происходит перемещение.
Следующая функция, которая была добавлена, это функция возвращающая вещь на свою позицию, либо, на какую любую другую позицию. Выглядит она следующим образом:
void ResetItem(int id) {
items[id].gameObject.parent = cells[id]; // меняем родителя у объекта вещи
items[id].gameObject.anchoredPosition = new Vector2(40, 40); // выравниваем объект вещи по средине ячейки (40 - половина ширины ячйки)
}
При вызове данной функции необходимо указать номер ячейки, в которую перемещается объект вещи.
Необходимо так же добавить несколько переменных, которые отвечают за сохранение id выделенной ячейки и сохранение координат мыши.
public int activeCellClick = -1; // переменная для сохранения идентификационного номера выделенной ячейки
[Space(10)]
public Vector2 OldPositionMouse; // старые координаты мыши
Осталось только заменить функцию Update().
void Update() {
if (Input.GetKeyDown(KeyCode.Mouse0))
{
if (activeCell != -1 && items[activeCell].gameObject != null)
{
oldActiveCell = activeCell; OldPositionMouse = Input.mousePosition; // запоминаем координаты мыши
if (activeCellClick != -1)
{ // если выделена какая-то ячейка
cells[activeCellClick].GetComponent<Outline>().enabled = false; // снимаем выделение
activeCellClick = -1; // удаляем сохранение
}
}
}
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<Outline>().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<Outline>().enabled = true; // выделяем ячейку
activeCellClick = activeCell; // запоминаем выделенную ячейку
}
}
else {
// дописать смену местами
cells[activeCellClick].GetComponent<Outline>().enabled = true;
activeCellClick = -1;
}
}
ResetItem(oldActiveCell);
}
}
}
else
{
// если мы не навели на ячейку
if (oldActiveCell != -1)
{
ResetItem(oldActiveCell);
}
}
oldActiveCell = -1;
}
}
На этом написание скрипта для перемещения завершено. Если вы всё сделали правильно, то можете наблюдать как у вас по нажатию сначала на объект, а затем на пустую клетку, объект перемещается.
Автор статьи: Александр Каримов.
Полный код:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class InventoryManager : MonoBehaviour
{
// тип объекта
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; // клас вещи
public int level = 0; // уровень вещи
public int glasses = 0; // очки вещи
public int magArmor = 0; // магическая защита
public int damArmor = 0; // физическая защита
public int damage = 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 Image image; // текстура объекта
}
public List<Item> items = new List<Item>();
public List<RectTransform> cells = new List<RectTransform>();
[Space(10)] public RectTransform canvas;
[Space(10)] public int activeCell = -1;
public int oldActiveCell = -1;
public int activeCellClick = -1; // переменная для сохранения идентификационного номера выделенной ячейки
[Space(10)]
public Vector2 OldPositionMouse; // старые координаты мыши
void Update()
{
if (Input.GetKeyDown(KeyCode.Mouse0))
{
if (activeCell != -1 && items[activeCell].gameObject != null)
{
oldActiveCell = activeCell;
OldPositionMouse = Input.mousePosition; // запоминаем координаты мыши
if (activeCellClick != -1)
{ // если выделена какая-то ячейка
cells[activeCellClick].GetComponent<Outline>().enabled = false; // снимаем выделение
activeCellClick = -1; // удаляем сохранение
}
}
}
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<Outline>().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<Outline>().enabled = true; // выделяем ячейку
activeCellClick = activeCell; // запоминаем выделенную ячейку
}
}
else
{ // дописать смену местами
cells[activeCellClick].GetComponent<Outline>().enabled = true;
activeCellClick = -1;
}
}
ResetItem(oldActiveCell);
}
}
}
else
{ // если мы не навели на ячейку
if (oldActiveCell != -1)
{
ResetItem(oldActiveCell);
}
}
oldActiveCell = -1;
}
}
void ResetItem(int id)
{
items[id].gameObject.parent = cells[id]; // меняем родителя у объекта вещи
items[id].gameObject.anchoredPosition = new Vector2(40, 40); // выравниваем объект вещи по средине ячейки (40 - половина ширины ячйки)
}
void ChangeItem(int oldId, int id)
{ // создаём копию вещи со старой позиции
Item newItem = new Item();
newItem.id = items[oldId].id;
newItem.type = items[oldId].type;
newItem.@class = items[oldId].@class;
newItem.level = items[oldId].level;
newItem.glasses = items[oldId].glasses;
newItem.magArmor = items[oldId].magArmor;
newItem.damArmor = items[oldId].damArmor;
newItem.damage = items[oldId].damage;
newItem.spellMagArmor = items[oldId].spellMagArmor;
newItem.spellDamArmor = items[oldId].spellDamArmor;
newItem.spellReverseDamage = items[oldId].spellReverseDamage;
newItem.spellVampirism = items[oldId].spellVampirism;
newItem.spellCriticalDamage = items[oldId].spellCriticalDamage;
newItem.gameObject = items[oldId].gameObject;
newItem.image = items[oldId].image; // на старую позицию перемещаем вещь с новой позиции
items[oldId].id = items[id].id;
items[oldId].type = items[id].type;
items[oldId].@class = items[id].@class;
items[oldId].level = items[id].level;
items[oldId].glasses = items[id].glasses;
items[oldId].magArmor = items[id].magArmor;
items[oldId].damArmor = items[id].damArmor;
items[oldId].damage = items[id].damage;
items[oldId].spellMagArmor = items[id].spellMagArmor;
items[oldId].spellDamArmor = items[id].spellDamArmor;
items[oldId].spellReverseDamage = items[id].spellReverseDamage;
items[oldId].spellVampirism = items[id].spellVampirism;
items[oldId].spellCriticalDamage = items[id].spellCriticalDamage;
items[oldId].gameObject = items[id].gameObject;
items[oldId].image = items[id].image; // на новую позицию перемещаем копию вещи со старой позиции
items[id].id = newItem.id;
items[id].type = newItem.type;
items[id].@class = newItem.@class;
items[id].level = newItem.level;
items[id].glasses = newItem.glasses;
items[id].magArmor = newItem.magArmor;
items[id].damArmor = newItem.damArmor;
items[id].damage = newItem.damage;
items[id].spellMagArmor = newItem.spellMagArmor;
items[id].spellDamArmor = newItem.spellDamArmor;
items[id].spellReverseDamage = newItem.spellReverseDamage;
items[id].spellVampirism = newItem.spellVampirism;
items[id].spellCriticalDamage = newItem.spellCriticalDamage;
items[id].gameObject = newItem.gameObject;
items[id].image = newItem.image;
} /// <summary> /// Функция наведения на ячейку
/// </summary>
public void EnterCell(int id)
{
activeCell = id;
} /// <summary> /// Функция сведения с ячейку /// </summary>
public void ExitCell()
{
activeCell = -1;
}
}