Улучшаем инвентарь, перемещением по нажатию на Unity

Существует несколько способов перемещение вещи в инвентаре:

  • В этой статье мы разберем, как перемещать вещь, путём перемещения по нажатию. Перед тем как прочитать эту статью, я бы настоятельно рекомендовал вам ознакомиться со статью написанной ранее «Создание простого инвентаря в игре на 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;
    }
} 
5/5 (1)

Оцените