【Unity实战】从零手戳一个库存背包系统

news2024/10/1 12:23:10

文章目录

  • 前言
  • 素材
  • 开始
    • 一、绘制背包UI
    • 二、背包开启关闭
    • 三、初始化背包网格
    • 四、 添加物品
    • 五、 拖拽交换功能物品
    • 六、 物品拆分
    • 七、 物品堆叠
    • 八、 拖拽还原
    • 九、 引入字典存储数据
    • 十、 拾取物品
    • 十一、 丢弃物品
  • 最终效果
  • 源码
  • 完结

前言

库存背包系统是大多数游戏的关键部分,几乎在每种类型的游戏都可能会用到,今天我将带你从零实现一个能够进行拖放的库存拆分、堆叠和丢弃的背包系统,你可以将它轻松的移植到你的游戏中。

老粉丝应该知道我之前有做过一个背包系统,当时做的比较简单,很多功能都没有实现,所以这次算一个重置版,当然你有兴趣可以看看之前实现的背包系统:https://blog.csdn.net/qq_36303853/article/details/129962414

先来看看实现的最终效果
在这里插入图片描述

素材

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

开始

一、绘制背包UI

在这里插入图片描述
物品列表网格添加Grid Layout Group组件控制物品格子排序
在这里插入图片描述
效果
在这里插入图片描述

二、背包开启关闭

物品槽信息类,用于存储每个物品槽的信息

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

库存系统

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;// 显示光标并限制在屏幕内部移动
            }
        }
    }
}

挂载Inventory 脚本在canvas,配置数据
在这里插入图片描述

运行效果
在这里插入图片描述

三、初始化背包网格

新建物品容器脚本

using UnityEngine;
using UnityEngine.UI;
using TMPro;

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

挂载代码
在这里插入图片描述

新建物品抽象类,所有物品类型都需要继承此类

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新增刷新背包功能,每次打开背包时调用RefreshInventory();

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++;
    }
}

效果
在这里插入图片描述

四、 添加物品

Inventory实现添加和清除物品功能

//添加物品
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;
}

新增第一个物品,木头脚本,继承Item基类,重新对应参数

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");
    }
}

添加40个木头进库测试

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

效果
在这里插入图片描述

五、 拖拽交换功能物品

先实现指针跟随鼠标,新增脚本

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);// 清空物品槽
    }
}

新增拖拽,跟随鼠标显示的UI
在这里插入图片描述
效果,就和一个格子效果一致
在这里插入图片描述
给Mouse挂载mouse脚本,并添加Canvas Group组件,将这个组件的blocksRaycasts属性设置为false,表示在我们刚开始拖拽的整个过程当中,鼠标不会再去把这个UI物品当作一个阻挡物来看待,包括他的子物体的所有的UI对象
在这里插入图片描述
ps:当然,选择去除各个子组件Image里的射线投射目标,也能实现相同的效果
在这里插入图片描述

记得默认先隐藏mouse下的物品列表容器
在这里插入图片描述
修改ItemPanel脚本实现物品拖拽和交换

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();
                }
            }
        }
    }
}

修改Inventory,初始化清空鼠标物品槽

public Mouse mouse;

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

为了方便交换测试,我们新增一个石头的物品脚本

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");
    }
}

在Inventory中生成

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

运行效果
在这里插入图片描述

修复问题,基本拖到和交换功能是做好了,但是你会发现物品放下时物品透明的并没有还原,那是因为前面我们拖动时调用了Fadeout方法,实现了物品面板淡出效果,透明度变为了0.3,我们放置物品时没有还原物品面板透明度

在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完全不透明
			}
			//。。。
		}
	}
}

效果
在这里插入图片描述

六、 物品拆分

实现滚轮拆分物品,shift对半分物品效果

修改Mouse代码,实现滚轮拆分物品

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();
} 

修改ItemPanel,实现shift对半分物品效果

// 将物品拾取到鼠标槽位
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);
    }
}

效果
在这里插入图片描述

七、 物品堆叠

修改ItemPanel代码,新增物品堆叠方法

//物品堆叠
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();
    }
}

运行效果
在这里插入图片描述

八、 拖拽还原

实现拖拽物品时按鼠标右键还原物品
修改Inventory代码

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

效果
在这里插入图片描述

九、 引入字典存储数据

创建一个用于存储所有物品的字典allItemsDictionary

allItemsDictionary 字典是为了方便根据物品名称来查找对应的物品对象。通常情况下,当你需要添加某个物品时,首先需要根据物品名称从字典中获取对应的物品对象,然后再将其添加到 items 列表中。

使用字典的好处是可以通过物品名称快速索引到对应的物品对象,而不需要遍历整个 items 列表。这在处理大量物品的时候可以提高性能和效率。

修改Inventory代码

// 创建一个用于存储所有物品的字典,其中键为物品名称,值为对应的物品对象
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;
    }
	
	//。。。
}

十、 拾取物品

新增可拾取物品脚本

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();
        }
    }
}

创建一个Player主角和可拾取物品
在这里插入图片描述

在这里插入图片描述
给Player添加Player标签,并把Inventory脚本移到Player下
在这里插入图片描述
可拾取物品添加脚本,配置参数
在这里插入图片描述

效果
在这里插入图片描述

十一、 丢弃物品

绘制丢弃物品预制体
在这里插入图片描述
挂载ItemPickup脚本
在这里插入图片描述

修改Inventory代码

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();// 刷新背包显示
}

Update中调用

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

效果
在这里插入图片描述

最终效果

在这里插入图片描述

源码

整理好后,我会放上来

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。点赞越多,更新越快哦!当然,如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1024999.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

富金通管理U盾不轻松,用了USB Server如沐清风

富金通网络科技服务有限公司是一家专注于金融科技服务的公司&#xff0c;因为拥有多个银行账户&#xff0c;也就有了U盾数量过多、管理极为不便的问题&#xff0c;具体表现为易丢失、易损坏、操作繁琐、需要插拔、不便携带、威胁金融安全等。 近期&#xff0c;朝天椒USB Serve…

【TCP】确认应答 与 超时重传

确认应答 与 超时重传 一. 确认应答机制二. 超时重传机制 一. 确认应答机制 确认应答: 保障可靠传输的核心机制。 可靠传输: 不是指传输过去的数据不出错, 也不是指数据一定能传输过去&#xff0c;而是指发送方能够知道接收方是否接收到了数据。确认应答的关键就是接收方收到数…

java:asm实现ResultSet结果映射到实体类

java&#xff1a;asm实现ResultSet结果映射到实体类 1 前言 Spring-core包中提供了许多方便的工具类&#xff0c;其中org.springframework.cglib.beans下的BeanCopier工具类&#xff0c;主要用于bean之间的属性拷贝&#xff0c;性能上优于Spring-beans包下的org.springframew…

面试官:你了解Axios的原理吗?有看过它的源码吗?

&#x1f3ac; 岸边的风&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 一、axios的使用 二、实现一个简易版axios 三、源码分析 小结 一、axios的使用 关于axios的基本使用&#xff0…

暨南大学旅游管理《乡村振兴战略下传统村落文化旅游设计》校友许少辉—2023学生开学季辉少许

暨南大学旅游管理《乡村振兴战略下传统村落文化旅游设计》校友许少辉——2023学生开学季辉少许

软文发布是推动企业发展的无形动力 | 媒介启航

同样是销售产品&#xff0c;为什么以故事的形式呈现要比直接讲产品功效更易让消费者认同和销售呢&#xff1f;这就是软文的魅力&#xff0c;它极好的运用了人作为情感动物的喜好。因此&#xff0c;各大小企业纷纷做软文&#xff0c;比如溯源啊、初心啊、情怀啊、创业经历啊等等…

Java集成微信支付实现企业付款到零钱和商家转账到零钱的功能

Java集成微信支付实现企业付款到零钱和商家转账到零钱的功能 文章目录 [toc] 1.企业付款到零钱和商家转账到零钱的区别1.1 申请要求不同1.2 API接口不同1.3 用户收款限制1.4 商户付款额度1.5 派发方式不同1.6 打款方式不同 2.集成实现2.1 v2版本集成2.2 依赖2.3 配置2.3.1 naco…

java多线程学习笔记一

一、线程的概述 1.1 线程的相关概念 1.1.1 进程&#xff08;Process&#xff09; 进程&#xff08;Process&#xff09;是计算机的程序关于某数据集合上的一次运行活动&#xff0c;是操作系统进行资源分配与调度的基本单位。 可以把进程简单的理解为操作系统中正在有运行的一…

插入排序代码及时间空间复杂度

插入排序&#xff08;Insertion Sort&#xff09;是一种简单的排序算法&#xff0c;它将一个数组分成已排序和未排序两部分&#xff0c;然后逐步将未排序部分的元素插入已排序部分的正确位置。以下是插入排序的代码示例以及时间和空间复杂度分析&#xff0c;希望对大家有所帮助…

Markdown 文档标题序号重排版(WebUI Tool)

Markdown 标题重编号 1. 项目背景 在日常写 Markdown 时&#xff0c;我们可能会遇到这样的情况&#xff1a; 文档的迁移与整合&#xff1a;在迁移或整合文档时&#xff0c;可能会让原本的标题编号混乱文档的重构&#xff1a;在重构文档时&#xff0c;例如仅仅修改了一处标题&…

malloc与free

目录 前提须知&#xff1a; malloc&#xff1a; 大意&#xff1a; 头文件&#xff1a; 申请空间&#xff1a; 判断是否申请成功&#xff1a; 使用空间&#xff1a; 结果&#xff1a; 整体代码&#xff1a; malloc申请的空间怎么回收呢? 注意事项&#xff1a; free:…

uniapp级联菜单地点区域使用label值,web端el-cascader绑定的value

效果图 一、uniapp uniapp级联菜单地点区域使用label值 1.ui使用 <uni-forms-item label="地址" name="userArea" required><view class="" style="height: 100%;display: flex;align-items: center;">

神经网络 03(参数初始化)

一、参数初始化 对于某一个神经元来说&#xff0c;需要初始化的参数有两类&#xff1a;一类是权重W&#xff0c;还有一类是偏置b&#xff0c;偏置b初始化为0即可。而权重W的初始化比较重要&#xff0c;我们着重来介绍常见的初始化方式。 &#xff08;1&#xff09;随机初始化 …

zabbix监控告警邮箱提醒,钉钉提醒

一、注册网易邮箱及其配置邮箱 1、开启POP3/SMTP/IMAP 二、service端配置邮件服务 1.安装 mailx dos2unix yum install -y mailx dos2unix mailx&#xff1a;邮件服务 mos2unix&#xff1a;用于转换文本文件格式的实用工具 查看mailx版本 2.配置mailx配置文件 编辑&#xf…

控制理论::带零点的二阶系统时域响应分析

一、系统描述 二、系统分析(分类讨论分析) 1、类型一&#xff08;极点为实数&#xff08;阻尼比>1&#xff09;&#xff0c;零点为负实数&#xff08;τ-1/b<0&#xff09;&#xff09; 1.1 定性分析 1.2 定量分析 有零点二阶系统的动态性能分析 - 豆丁网 (docin.com)

Python WEB框架FastAPI (二)

Python WEB框架FastAPI &#xff08;二&#xff09; 最近一直在使用fastapi&#xff0c;随着使用的深入发现我对于它的了解还是太少了&#xff0c;以至于踩了一些坑。所以在这里记录一下&#xff0c;愿看到的小伙伴不迷路。 路径传参并发问题 一、路径传参 这是对上一个传参…

TTS | 利用Fastspeech训练LJSpeech语音数据集后英文文本生成语音及代码详解

FastSpeech 基于 Transformer 的前馈网络&#xff0c;用于并行生成 TTS 梅尔谱图。 FastSpeech 模型与自回归 Transformer TTS 相比&#xff0c;梅尔谱图生成速度加快了 270 倍&#xff0c;端到端语音合成速度加快了 38 倍。 项目实现 docker cp LJSpeech-1.1.tar.bz2 torch_…

Kibana 安装部署 - Centos7

Kibana 安装部署 - Centos7 本文介绍一下在Centos7上部署和配置Kibana1、下载 直接去官网地址进行下载即可。【注意】&#xff1a; 一定要下载和你的ES版本一致的Kibana。比如我的ES的版本是 7.9.1&#xff0c;所以我下载的kibana就是7.9.1。下载地址 &#xff1a; https://w…

活动报名|如何使用70万预算从头训练千亿语言大模型

王业全 北京智源人工智能研究院认知模型团队负责人&#xff0c;清华大学博士&#xff0c;中国中文信息学会情感计算专委会委员&#xff0c;2022年被评为AI 2000全球最具影响力人工智能学者&#xff08;自然语言处理领域&#xff09;。主要从事语言大模型、自然语言处理方面的研…

Laravel框架 - 中间件篇

什么是中间件&#xff1f; 在 Laravel 框架中&#xff0c;中间件是一种用于处理 HTTP 请求的组件。它允许你在请求进入 路由 处理 之前 或 之后 执行一些代码逻辑。 中间件的优势和功能 处理身份验证&#xff1a;验证用户是否已经登录或者检查用户是否有权限访问特定的路由 记…