[Unity Practical Combat] Create an inventory backpack system from scratch

Preface

The inventory backpack system is a key part of most games and may be used in almost every type of game. Today I will take you to implement a backpack system from scratch that is capable of drag-and-drop inventory splitting, stacking and discarding. It can be easily ported to your game.

Old fans should know that I have made a backpack system before. It was relatively simple at that time and many functions were not implemented, so this time it is considered a reset version. Of course, if you are interested, you can take a look at the backpack system implemented before: https: / /blog.csdn.net/qq_36303853/article/details/129962414

Let’s first take a look at the final effect achieved
Insert image description here

material

Insert image description here
Insert image description here
Insert image description here
Insert image description here
Insert image description here
Insert image description here

Insert image description here

Insert image description here

start

1. Draw the backpack UI

Insert image description here
Add Grid Layout Group component to item list grid to control item grid sorting
Insert image description here
effect
Insert image description here

2. Opening and closing the backpack

Item slot information class, used to store information about each item slot

// 物品槽信息类,用于存储每个物品槽的信息
[System.Serializable]
public class ItemSlotInfo
{
    
    
    public Item item;// 物品对象
    public string name;// 物品名称
    public int stacks;// 堆叠数量
    public ItemSlotInfo(Item newItem, int newstacks)
    {
    
    
        item = newItem;
        stacks = newstacks;
    }
}

Inventory system

using System.Collections.Generic;
using UnityEngine;

public class Inventory : MonoBehaviour
{
    
    
    [SerializeReference] public List<ItemSlotInfo> items = new List<ItemSlotInfo>();// 物品列表
    [Space]
    [Header("库存菜单组件")]
    public GameObject inventoryMenu;// 背包菜单
    public GameObject itemPanel;// 物品列表容器
    public GameObject itemPanelGrid;// 物品列表网格布局

    [Space]
    public int inventorySize = 24;// 背包容量大小
    void Start()
    {
    
    
        // 初始化物品列表并赋值为 null
        for (int i = 0; i < inventorySize; i++)
        {
    
    
            items.Add(new ItemSlotInfo(null, 0));
        }
    }

    void Update()
    {
    
    
        // 按下 Tab 键显示或隐藏背包界面
        if (Input.GetKeyDown(KeyCode.Tab))
        {
    
    
            if (inventoryMenu.activeSelf)
            {
    
    
                inventoryMenu.SetActive(false);
                Cursor.lockState = CursorLockMode.Locked;// 隐藏光标并锁定在屏幕中心
            }
            else
            {
    
    
                inventoryMenu.SetActive(true);
                Cursor.lockState = CursorLockMode.Confined;// 显示光标并限制在屏幕内部移动
            }
        }
    }
}

Mount the Inventory script on canvas and configure data
Insert image description here

running result
Insert image description here

3. Initialize the backpack grid

Create new item container script

using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class ItemPanel : MonoBehaviour
{
    
    
    public Inventory inventory;// 背包脚本引用
    public ItemSlotInfo itemSlot;// 物品槽信息
    public Image itemImage;// 物品图像组件
    public TextMeshProUGUI stacksText;// 堆叠数量文本组件
}

Mount code
Insert image description here

Create a new item abstract class, all item types need to inherit this class

using UnityEngine;
//物品抽象类,所有物品类型都需要继承此类
[System.Serializable]
public abstract class Item
{
    
    
    public abstract string GiveName();// 获取物品名称
    public virtual int MaxStacks()// 获取每个物品槽的最大堆叠数量
    {
    
    
        return 30;// 默认为 30
    }
    public virtual Sprite GiveItemImage()// 获取物品图片
    {
    
    
        return Resources.Load<Sprite>("UI/Item Images/No Item Image Icon");// 默认图片
    }
}

Inventory has added the function of refreshing the backpack. RefreshInventory() is called every time the backpack is opened;

private List<ItemPanel> existingPanels = new List<ItemPanel>();//物品容器列表

//刷新背包
public void RefreshInventory()
{
    
    
    //物品容器列表
    existingPanels = itemPanelGrid.GetComponentsInChildren<ItemPanel>().ToList();
    //如果物品列表容器不足,创建物品面板
    if (existingPanels.Count < inventorySize)
    {
    
    
        int amountToCreate = inventorySize - existingPanels.Count;
        for (int i = 0; i < amountToCreate; i++)
        {
    
    
            GameObject newPanel = Instantiate(itemPanel, itemPanelGrid.transform);
            existingPanels.Add(newPanel.GetComponent<ItemPanel>());
        }
    }
    int index = 0;
    foreach (ItemSlotInfo i in items)
    {
    
    
        //给物品列表元素命名
        i.name = "" + (index + 1);
        if (i.item != null) i.name += ":" + i.item.GiveName();
        else i.name += ":-";
        //更新物品面板
        ItemPanel panel = existingPanels[index];
        panel.name = i.name + " Panel";
        if (panel != null)
        {
    
    
            panel.inventory = this;
            panel.itemSlot = i;
            if (i.item != null)
            {
    
    
                panel.itemImage.gameObject.SetActive(true);  // 显示物品图标
                panel.itemImage.sprite = i.item.GiveItemImage();  // 设置物品图标的精灵
                panel.stacksText.gameObject.SetActive(true);  // 显示物品叠加数量
                panel.stacksText.text = "" + i.stacks;  // 设置物品叠加数量的文本
            }
            else
            {
    
    
                panel.itemImage.gameObject.SetActive(false);  // 隐藏物品图标
                panel.stacksText.gameObject.SetActive(false);  // 隐藏物品叠加数量
            }
        }
        index++;
    }
}

Effect
Insert image description here

4. Add items

Inventory implements the function of adding and clearing items

//添加物品
public int AddItem(Item item, int amount)
{
    
    
    // 检查已有物品槽中是否有空余位置
    foreach (ItemSlotInfo i in items)
    {
    
    
        if (i.item != null)
        {
    
    
            if (i.item.GiveName() == item.GiveName())
            {
    
    
                if (amount > i.item.MaxStacks() - i.stacks)
                {
    
    
                    amount -= i.item.MaxStacks() - i.stacks;
                    i.stacks = i.item.MaxStacks();
                }

                else
                {
    
    
                    i.stacks += amount;
                    //如果背包菜单处于激活状态,刷新背包显示
                    if (inventoryMenu.activeSelf) RefreshInventory();
                    return 0;
                }

            }
        }

    }

    //将剩余的物品放入空的物品槽中
    foreach (ItemSlotInfo i in items)
    {
    
    
        if (i.item == null)
        {
    
    
            if (amount > item.MaxStacks())
            {
    
    
                i.item = item;
                i.stacks = item.MaxStacks();
                amount -= item.MaxStacks();
            }
            else
            {
    
    
                i.item = item;
                i.stacks = amount;
                //如果背包菜单处于激活状态,刷新背包显示
                if (inventoryMenu.activeSelf) RefreshInventory();
                return 0;
            }

        }

    }
    Debug.Log("库存中没有空间:" + item.GiveName());
    //如果背包菜单处于激活状态,刷新背包显示
    if (inventoryMenu.activeSelf) RefreshInventory();
    return amount;
}

//清空指定物品槽中的物品和叠加数量
public void ClearSlot(ItemSlotInfo slot)
{
    
    
    slot.item = null;
    slot.stacks = 0;
}

Add the first item, the wood script, inherit the Item base class, and re-correspond to the parameters.

using UnityEngine;
public class WoodItem : Item
{
    
    
    public override string GiveName()// 获取物品名称
    {
    
    
        return "Wood";
    }
    public override int MaxStacks()// 获取每个物品槽的最大堆叠数量
    {
    
    
        return 10;
    }
    public override Sprite GiveItemImage()// 获取物品图片
    {
    
    
        return Resources.Load<Sprite>("UI/Item Images/Wood Icon");
    }
}

Add 40 pieces of wood to the library for testing

public class Inventory : MonoBehaviour
{
    
    
    void Start()
    {
    
    
        // 。。。
        AddItem(new WoodItem(), 40);
    }
}

Effect
Insert image description here

5. Drag and drop functional items for exchange

First implement the pointer to follow the mouse and add a new script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class Mouse : MonoBehaviour
{
    
    
    public GameObject mouseItemUI; // 鼠标上的物品UI
    public Image mouseCursor; // 鼠标光标
    public ItemSlotInfo itemSlot; // 物品槽信息
    public Image itemImage; // 物品图像
    public TextMeshProUGUI stacksText; // 叠加数量文本

    void Update()
    {
    
    
        // 将鼠标指针位置设置为当前鼠标位置
        transform.position = Input.mousePosition;
        
        // 如果鼠标被锁定
        if (Cursor.lockState == CursorLockMode.Locked)
        {
    
    
            mouseCursor.enabled = false; // 隐藏鼠标光标
            mouseItemUI.SetActive(false); // 隐藏鼠标上的物品UI
        }
        else
        {
    
    
            mouseCursor.enabled = true; // 显示鼠标光标
            
            // 如果物品槽中有物品
            if (itemSlot.item != null)
            {
    
    
                mouseItemUI.SetActive(true); // 显示鼠标上的物品UI
            }
            else
            {
    
    
                mouseItemUI.SetActive(false); // 隐藏鼠标上的物品UI
            }
        }
    }
    public void SetUI()
    {
    
    
        stacksText.text = "" + itemSlot.stacks; // 设置叠加数量文本
        itemImage.sprite = itemSlot.item.GiveItemImage(); // 设置物品图像
    }
    public void EmptySlot()
    {
    
    
        itemSlot = new ItemSlotInfo(null, 0);// 清空物品槽
    }
}

Add a new drag-and-drop UI effect that follows the mouse display
Insert image description here
, which is consistent with a grid effect.
Insert image description here
Mount the mouse script to the Mouse, and add the Canvas Group component. Set the blocksRaycasts property of this component to false, which means that in the entire area where we just started dragging During the process, the mouse will no longer treat this UI object as an obstruction, including all UI objects of its sub-objects
Insert image description here
ps: Of course, the same can be achieved by selecting to remove the ray casting target in each sub-component Image. Effect
Insert image description here

Remember to hide the item list container under mouse by default first
Insert image description here
. Modify the ItemPanel script to implement item dragging and swapping.

using UnityEngine;
using UnityEngine.UI;
using TMPro;
using UnityEngine.EventSystems;

public class ItemPanel : MonoBehaviour, IPointerEnterHandler, IPointerDownHandler, IPointerUpHandler, IDragHandler, IDropHandler
{
    
    
    public Inventory inventory; // 背包脚本引用
    public ItemSlotInfo itemSlot; // 物品槽信息
    public Image itemImage; // 物品图像组件
    public TextMeshProUGUI stacksText; // 堆叠数量文本组件
    private bool click; // 当前是否点击
    private Mouse mouse; // 鼠标

    // 当鼠标进入时调用的方法
    public void OnPointerEnter(PointerEventData eventData)
    {
    
    
        eventData.pointerPress = this.gameObject;
    }

    // 当鼠标按下时调用的方法
    public void OnPointerDown(PointerEventData eventData)
    {
    
    
        click = true;
    }

    // 当鼠标抬起时调用的方法
    public void OnPointerUp(PointerEventData eventData)
    {
    
    
        if (click)
        {
    
    
            OnClick();
            click = false;
        }
    }

    // 在拖拽结束时调用
    public void OnDrop(PointerEventData eventData)
    {
    
    
        OnClick();
        click = false;
    }
    // 在拖拽过程中连续调用
    public void OnDrag(PointerEventData eventData)
    {
    
    
        if (click)
        {
    
    
            OnClick();
            click = false;
            OnDrop(eventData);
        }
    }

    // 将物品拾取到鼠标槽位
    public void PickupItem()
    {
    
    
        mouse.itemSlot = itemSlot;
        mouse.SetUI();
    }

    // 物品面板淡出效果
    public void Fadeout()
    {
    
    
        itemImage.CrossFadeAlpha(0.3f, 0.05f, true);//0.05 秒itemImage透明度渐变到0.3
    }

    // 将物品放下到当前物品面板上
    public void DropItem()
    {
    
    
        itemSlot.item = mouse.itemSlot.item;
        itemSlot.stacks = mouse.itemSlot.stacks;
        inventory.ClearSlot(mouse.itemSlot);
    }

    // 交换两个物品槽位的物品
    public void SwapItem(ItemSlotInfo slotA, ItemSlotInfo slotB)
    {
    
    
        // 暂存槽位A的物品信息
        ItemSlotInfo tempItem = new ItemSlotInfo(slotA.item, slotA.stacks);
        // 将槽位B的物品信息赋值给槽位A
        slotA.item = slotB.item;
        slotA.stacks = slotB.stacks;
        // 将暂存的物品信息赋值给槽位B
        slotB.item = tempItem.item;
        slotB.stacks = tempItem.stacks;
    }

    // 当物品面板被点击时调用的方法
    void OnClick()
    {
    
    
        if (inventory != null)
        {
    
    
            mouse = inventory.mouse;
            // 如果鼠标槽位为空,将物品拾取到鼠标槽位
            if (mouse.itemSlot.item == null)
            {
    
    
                if (itemSlot.item != null)
                {
    
    
                    PickupItem();
                    Fadeout();
                }
            }
            else
            {
    
    
                // 点击的是原始槽位
                if (itemSlot == mouse.itemSlot)
                {
    
    
                    inventory.RefreshInventory();
                }
                // 点击的是空槽位
                else if (itemSlot.item == null)
                {
    
    
                    DropItem();
                    inventory.RefreshInventory();
                }
                // 点击的是不同物品类型的已占用槽位
                else if (itemSlot.item.GiveName() != mouse.itemSlot.item.GiveName())
                {
    
    
                    SwapItem(itemSlot, mouse.itemSlot);
                    inventory.RefreshInventory();
                }
            }
        }
    }
}

Modify Inventory and initialize to clear the mouse item slot

public Mouse mouse;

void Update()
{
    
    
    // 按下 Tab 键显示或隐藏背包界面
    if (Input.GetKeyDown(KeyCode.Tab))
    {
    
    
        if (inventoryMenu.activeSelf)
        {
    
    
            //。。。
            mouse.EmptySlot();
        }
        else
        {
    
    
            //。。。
        }
    }
}
//刷新背包
public void RefreshInventory()
{
    
    
	//。。。
	mouse.EmptySlot();
}

In order to facilitate exchange testing, we have added a stone item script

using UnityEngine;
public class StoneItem : Item
{
    
    
    public override string GiveName()// 获取物品名称
    {
    
    
        return "Stone";
    }
    public override int MaxStacks()// 获取每个物品槽的最大堆叠数量
    {
    
    
        return 5;
    }
    public override Sprite GiveItemImage()// 获取物品图片
    {
    
    
        return Resources.Load<Sprite>("UI/Item Images/Stone Icon");
    }
}

Generate in Inventory

void Start()
{
    
    
    //。。。
    AddItem(new WoodItem(), 40);
    AddItem(new StoneItem(), 40);
}

running result
Insert image description here

Fix the problem. The basic drag and swap functions are ready, but you will find that the transparency of the item is not restored when you drop it. That is because we called the Fadeout method when dragging to achieve the fade-out effect of the item panel and the transparency changes. For 0.3, we did not restore the item panel transparency when placing items

Add code to Inventory

//刷新背包
public void RefreshInventory()
{
    
    
	//。。。
	foreach (ItemSlotInfo i in items)
    {
    
    
    	//。。。
		if (panel != null)
        {
    
    
        	//。。。
			if (i.item != null)
            {
    
    
				//。。。
				panel.itemImage.CrossFadeAlpha(1, 0.05f, true);//0.05 秒itemImage透明度渐变到1完全不透明
			}
			//。。。
		}
	}
}

Effect
Insert image description here

6. Item splitting

Realize the effect of splitting items with the wheel and splitting items in half with shift

Modify the Mouse code to implement wheel splitting of items

public ItemPanel sourceItemPanel; // 源物品面板对象
public int splitSize; // 拆分数量

void Update()
{
    
    
    // ...

    if (itemSlot.item != null) // 如果物品槽中有物品
    {
    
    
        if (Input.GetAxis("Mouse ScrollWheel") > 0 && splitSize < itemSlot.stacks)
        {
    
    
            // 当鼠标向上滚动并且拆分数量小于物品槽剩余堆叠数量时
            splitSize++; // 增加拆分数量
        }
        
        if (Input.GetAxis("Mouse ScrollWheel") < 0 && splitSize > 1)
        {
    
    
            // 当鼠标向下滚动并且拆分数量大于1时
            splitSize--; // 减少拆分数量
        }

        stacksText.text = "" + splitSize; // 在UI中显示拆分数量
        
        if (splitSize == itemSlot.stacks)// 如果拆分数量等于物品的堆叠数量
        {
    
     
            // 将源物品面板的堆叠数量文本组件设置为不可见
            sourceItemPanel.stacksText.gameObject.SetActive(false);  
        }
        else
        {
    
    
            sourceItemPanel.stacksText.gameObject.SetActive(true);
            // 在文本组件中显示物品的剩余堆叠数量
            sourceItemPanel.stacksText.text = "" + (itemSlot.stacks - splitSize);
        }
    }
}   

public void SetUI()
{
    
    
    // stacksText.text = "" + itemSlot.stacks; // 设置叠加数量文本
    stacksText.text = "" + splitSize;// 在UI中显示拆分数量
    itemImage.sprite = itemSlot.item.GiveItemImage();
} 

Modify ItemPanel to achieve the effect of shifting items in half

// 将物品拾取到鼠标槽位
public void PickupItem()
{
    
    
    mouse.itemSlot = itemSlot;
    mouse.sourceItemPanel = this;
    if (Input.GetKey(KeyCode.LeftShift) && itemSlot.stacks > 1)
    {
    
    
        mouse.splitSize = itemSlot.stacks / 2;
    }
    else
    {
    
    
        mouse.splitSize = itemSlot.stacks;
    }
    mouse.SetUI();
}
// 将物品放下到当前物品面板上
public void DropItem()
{
    
    
    itemSlot.item = mouse.itemSlot.item;
    if (mouse.splitSize < mouse.itemSlot.stacks)
    {
    
    
        itemSlot.stacks = mouse.splitSize;
        mouse.itemSlot.stacks -= mouse.splitSize;
        mouse.EmptySlot();
    }
    else
    {
    
    
        itemSlot.stacks = mouse.itemSlot.stacks;
        inventory.ClearSlot(mouse.itemSlot);
    }
}

Effect
Insert image description here

7. Item stacking

Modify the ItemPanel code and add a new item stacking method

//物品堆叠
public void StackItem(ItemSlotInfo source, ItemSlotInfo destination, int amount)
{
    
    
    // 计算目标物品槽中可用的堆叠空间
    int slotsAvailable = destination.item.MaxStacks() - destination.stacks;
    
    // 如果目标物品槽没有可用的堆叠空间,则直接返回
    if (slotsAvailable == 0) return;

    if (amount > slotsAvailable)
    {
    
    
        // 堆叠数量超过可用空间时,从源物品槽中减去可用空间
        source.stacks -= slotsAvailable;
        // 目标物品槽的堆叠数量设置为最大堆叠数
        destination.stacks = destination.item.MaxStacks();
    }
    if (amount <= slotsAvailable)
    {
    
    
        // 堆叠数量小于可用空间时,将堆叠数量加到目标物品槽中
        destination.stacks += amount;
        // 如果源物品槽中剩余的堆叠数量等于堆叠数量(即所有物品都被堆叠完),则清空源物品槽
        if (source.stacks == amount) inventory.ClearSlot(source);
        // 否则,从源物品槽中减去堆叠数量
        else source.stacks -= amount;  
    }
}

// 当物品面板被点击时调用的方法
void OnClick()
{
    
    
	//。。。
	
	// 点击的是同物品类型的已占用槽位
    else if (itemSlot.stacks < itemSlot.item.MaxStacks()){
    
    
        StackItem(mouse.itemSlot, itemSlot, mouse.splitSize);
        inventory.RefreshInventory();
    }
}

running result
Insert image description here

8. Drag and drop to restore

Implementation of restoring items by pressing when dragging items and modifying the Inventory 鼠标右键code

void Update()
{
    
    
	//。。。
	
    //拖拽物品时按鼠标右键还原物品
    if (Input.GetKeyDown(KeyCode.Mouse1) && mouse.itemSlot.item != null)
    {
    
    
        RefreshInventory();
    }
}

Effect
Insert image description here

9. Introduce dictionary to store data

Create a dictionary allItemsDictionary to store all items

The allItemsDictionary dictionary is used to facilitate finding corresponding item objects based on item names. Normally, when you need to add an item, you first need to get the corresponding item object from the dictionary according to the item name, and then add it to the items list.

The advantage of using a dictionary is that the corresponding item object can be quickly indexed by the item name without traversing the entire items list. This improves performance and efficiency when processing large amounts of items.

Modify Inventory code

// 创建一个用于存储所有物品的字典,其中键为物品名称,值为对应的物品对象
Dictionary<string, Item> allItemsDictionary = new Dictionary<string, Item>();

void Start()
{
    
    
    // 初始化物品列表并赋值为 null
    for (int i = 0; i < inventorySize; i++)
    {
    
    
        items.Add(new ItemSlotInfo(null, 0));
    }

    // 获取所有可用的物品,并将它们添加到物品字典中
    List<Item> allItems = GetAllItems().ToList();
    string itemsInDictionary = "字典条目:";
    foreach (Item i in allItems)
    {
    
    
        if (!allItemsDictionary.ContainsKey(i.GiveName()))
        {
    
    

            allItemsDictionary.Add(i.GiveName(), i);
            itemsInDictionary += "," + i.GiveName();
        }
        else
        {
    
    
            // 如果字典中已存在同名的物品,则输出调试信息
            Debug.Log("" + i + "已存在于与之共享名称的字典中 " + allItemsDictionary[i.GiveName()]);
        }

    }

    itemsInDictionary += ".";
    Debug.Log(itemsInDictionary);

    // 添加一些初始物品
    AddItem("Wood", 40);
    AddItem("Stone", 40);
}

// 获取所有可用的物品
IEnumerable<Item> GetAllItems()
{
    
    
    List<Item> allItems = new List<Item>();

    // 获取当前应用程序域中的所有程序集
    Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();

    // 遍历每个程序集
    foreach (Assembly assembly in assemblies)
    {
    
    
        // 获取程序集中定义的所有类型
        Type[] types = assembly.GetTypes();

        // 遍历每个类型
        foreach (Type type in types)
        {
    
    
            // 检查类型是否是 Item 类的子类
            if (type.IsSubclassOf(typeof(Item)))
            {
    
    
                // 创建该类型的实例,并将其转换为 Item 对象
                Item item = Activator.CreateInstance(type) as Item;

                // 将物品添加到列表中
                allItems.Add(item);
            }
        }
    }

    return allItems;
}   

//添加物品
public int AddItem(string itemName, int amount)
{
    
    
    //查找要添加的项目
    Item item = null;
    allItemsDictionary.TryGetValue(itemName, out item);
    //如果未找到任何项,则退出方法
    if (item == null)
    {
    
    
        Debug.Log("无法在字典中找到要添加到库存中的物品");
        return amount;
    }
	
	//。。。
}

10. Pick up items

Added script for picking up items

using UnityEngine;
using TMPro;

//物品拾取脚本
public class ItemPickup : MonoBehaviour
{
    
    
    public string itemToDrop;   // 需要拾取的物品名称
    public int amount = 1;      // 物品数量,默认为1
    private TextMeshPro text;   //物品文本
    Inventory playerInventory;  //玩家的背包组件

    void Start()
    {
    
    
        text = transform.GetComponentInChildren<TextMeshPro>();
        text.text = amount.ToString();
    }
    void Update()
    {
    
    
        if (Input.GetKeyDown(KeyCode.C))
        {
    
    
            PickUpItem();
        }
    }

    // 当碰撞体进入触发器时调用
    private void OnTriggerStay2D(Collider2D other)
    {
    
    
        if (other.tag == "Player")
        {
    
    
            // 获取玩家的背包组件
            playerInventory = other.GetComponent<Inventory>();
        }
    }

    //当碰撞体离开触发器时调用
    private void OnTriggerExit2D(Collider2D other){
    
    
        if (other.tag == "Player")
        {
    
    
            // 获取玩家的背包组件
            playerInventory = null;
        }
    }

    // 拾取物品的方法
    public void PickUpItem()
    {
    
    
        // 如果玩家背包组件存在,则拾取物品
        if (playerInventory == null) return;

        // 将物品添加到背包,并返回剩余的物品数量
        amount = playerInventory.AddItem(itemToDrop, amount);

        // 如果数量小于1,销毁该拾取物品的游戏对象
        if (amount < 1)
        {
    
    
            Destroy(this.gameObject);
        }
        else
        {
    
    
            //更新text
            text.text = amount.ToString();
        }
    }
}

Create a Player protagonist and pickup items
Insert image description here

Insert image description here
Add the Player tag to the Player and move the Inventory script under the Player.
Insert image description here
Add scripts to pick up items and configure parameters.
Insert image description here

Effect
Insert image description here

11. Discarded items

Draw the discarded item prefab
Insert image description here
and mount the ItemPickup script
Insert image description here

Modify Inventory code

public GameObject dropObject;//丢弃物品预制体

//丢弃物品
public void DropItem(string itemName)
{
    
    
    Item item = null;
    // 从字典中查找物品
    allItemsDictionary.TryGetValue(itemName, out item);
    if (item == null)
    {
    
    
        Debug.Log("在字典中找不到要添加到掉落的物品");
        return;
    }

    // 在当前位置实例化一个掉落物体
    GameObject droppedItem = Instantiate(dropObject, transform.position, Quaternion.identity);

    //修改图片
    droppedItem.GetComponent<SpriteRenderer>().sprite = item.GiveItemImage();

    ItemPickup ip = droppedItem.GetComponent<ItemPickup>();

    if (ip != null)
    {
    
    
        // 设置掉落物品的属性
        ip.itemToDrop = itemName;
        ip.amount = mouse.splitSize;
        mouse.itemSlot.stacks -= mouse.splitSize;//更新物品槽中该物品的剩余数量,及减去将要丢弃的物品数量
    }

    if (mouse.itemSlot.stacks < 1) ClearSlot(mouse.itemSlot);// 清空物品槽
    
    mouse.EmptySlot();// 清空鼠标上的物品
    RefreshInventory();// 刷新背包显示
}

Called in Update

void Update()
{
    
    
    //控制丢弃物品 EventSystem.current.IsPointerOverGameObject():该条件判断鼠标当前是否位于UI元素之上
    if (Input.GetKeyDown(KeyCode.Mouse0) && mouse.itemSlot.item != null && !EventSystem.current.IsPointerOverGameObject())
    {
    
    
        DropItem(mouse.itemSlot.item.GiveName());
    }
}

Effect
Insert image description here

final effect

Insert image description here

Source code

I'll put it up after I've sorted it out

end

Gifts of roses, hand a fragrance! If the content of the article is helpful to you, please don't be stingy with your 点赞评论和关注feedback so that I can receive feedback as soon as possible. Your every feedback 支持is the biggest motivation for me to continue creating. The more likes, the faster the updates will be! Of course, if you find 存在错误something in the article 更好的解决方法, please feel free to comment and send me a private message!

Okay, I am 向宇, https://xiangyu.blog.csdn.net

A developer who has been working quietly in a small company recently started studying Unity by himself out of interest. If you encounter any problems, you are also welcome to comment and send me a private message. Although I may not necessarily know some of the problems, I will check the information from all parties and try to give the best suggestions. I hope to help more people who want to learn programming. People, encourage each other~
Insert image description here

Guess you like

Origin blog.csdn.net/qq_36303853/article/details/133021338