当前位置:网站首页>Unity 高級背包系統

Unity 高級背包系統

2022-06-11 04:20:00 海 月

前言

之前實現了一個初級的背包系統,它沒有對物品進行分類。

這一次新增了物品的分類存儲與顯示。

Asset的結構

為了對物品進行分類管理,在ScriptableObject中使用列錶存儲三個類型的物品,分別是武器、食物以及材料。這個列錶中的元素是一個特別的類,它包含了這類物品的名字,以及存儲這類物品的列錶。在物品配置錶中,存儲的是Item類對象,在背包物品數據錶中,存儲的是InventoryItem對象,它們的差异是,InventoryItem類的對象多了一個數量的屬性。

物品的編號

101~199 是武器

201~299 是食物

301~399 是材料

判斷物品的類型,用物品的 index / 100 即可。

代碼

物品配置錶

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu]
public class ItemsConfigurationAdvanced : ScriptableObject
{
    [Header("物品分類列錶")]
    public List<ItemList> lists;
}

[System.Serializable]
public class ItemList
{
    public string listName;
    public List<Item> items;
}

背包物品配置錶

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu]
public class InventoryConfigurationAdvanced : ScriptableObject
{
    [Header("玩家持有物品的分類列錶")]
    public List<InventoryItemList> lists;
}

[System.Serializable]
public class InventoryItemList
{
    public string listName;
    public List<InventoryItem> items;

    public InventoryItemList(string name)
    {
        listName = name;
        items = new List<InventoryItem>();
    }
}

背包物品類

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[Serializable]
public class InventoryItem : Item
{
    public int num;

    public InventoryItem(Item item, int num) : base(item)
    {
        this.num = num;
    }
}

注:背包物品類的構造函數調用了基類的拷貝構造函數

物品類

using System;
using UnityEngine;
using UnityEngine.UI;

[Serializable]
public class Item
{
    public int id;
    public string name;
    public string description;
    public Texture2D icon;
    public GameObject model;

    public Item(Item item)
    {
        id = item.id;
        name = item.name;
        description = item.description;
        icon = item.icon;
        model = item.model;
    }
}

物品數據管理器

using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 提供物品配置錶與背包物品
/// </summary>
public class BackpackManagerAdvanced : Singleton<BackpackManagerAdvanced>
{
    public ItemsConfigurationAdvanced itemsConfiguration = Resources.Load<ItemsConfigurationAdvanced>("Configurations/Items Configuration Advanced");
    public InventoryConfigurationAdvanced inventoryConfiguration = Resources.Load<InventoryConfigurationAdvanced>("Configurations/Inventory Configuration Advanced");

    /// <summary>
    /// 從背包中獲取指定編號的物品
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    InventoryItem Contains(int index)
    {
        if (inventoryConfiguration.lists == null)
        {
            inventoryConfiguration.lists = new List<InventoryItemList>();
        }

        if(inventoryConfiguration.lists[index / 100 - 1] == null)
        {
            inventoryConfiguration.lists[index / 100 - 1] = new InventoryItemList(itemsConfiguration.lists[index / 100 - 1].listName);
        }

        foreach (var i in inventoryConfiguration.lists[index / 100 - 1].items)
        {
            if (i.id == index)
                return i;
        }
        return null;
    }

    /// <summary>
    /// 保存指定編號的物品到背包
    /// </summary>
    /// <param name="index"></param>
    public void SaveItemToInventory(int index)
    {
        InventoryItem temp = Contains(index);

        if (temp != null)
            temp.num++;
        else
            inventoryConfiguration.lists[index / 100 - 1].items.Add(new InventoryItem(GetItem(index), 1));
    }

    /// <summary>
    /// 從物品配置錶中獲取指定編號的物品
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    public Item GetItem(int index)
    {
        foreach (var i in itemsConfiguration.lists[index / 100 - 1].items)
        {
            if (i.id == index)
                return i;
        }
        return null;
    }
}

背包面板類

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

public class BackpackPanel : BasePanel
{
    static readonly string path = "Prefabs/UI/BackpackPanel";

    public BackpackPanel() : base(new PanelType(path)) { }

    /*-----------可配置的參數-----------*/

    public int column = 5;                  //列數
    public float itemSize = 280;            //物品格子大小
    public float interval = 20;             //格子之間的間隙
    public float viewPortHeight = 1500;      //窗口的高度

    //記錄上一次顯示的最值索引,以便移除看不見的格子
    int lastMinDisplayIndex;
    int lastMaxDisplayIndex;
    //滑動列錶的容器
    public RectTransform content;
    //存儲當前顯示的格子及編號
    Dictionary<int, GameObject> curDisplayGrids = new Dictionary<int, GameObject>();

    public Item selectedItem;//當前選中的物品
    public override void OnEnter()
    {
        panelBindingTool.GetOrAddComponentInChildren<Button>("關閉").onClick.AddListener(() =>
        {
            panelStack.Pop();
        }
        );

        panelBindingTool.GetOrAddComponentInChildren<Button>("詳情").onClick.AddListener(() =>
        {
            panelStack.Push(new ItemDetailPanel(selectedItem));
        }
        );

        panelBindingTool.GetOrAddComponentInChildren<Button>("武器").onClick.AddListener(() =>
        {
            listIndex = 1;
            InitThisTypeOfBackpack();
        }
        );

        panelBindingTool.GetOrAddComponentInChildren<Button>("食物").onClick.AddListener(() =>
        {
            listIndex = 2;
            InitThisTypeOfBackpack();
        }
        );

        panelBindingTool.GetOrAddComponentInChildren<Button>("材料").onClick.AddListener(() =>
        {
            listIndex = 3;
            InitThisTypeOfBackpack();
        }
        );

        InitThisTypeOfBackpack();

        OrbitCamera.Instance.work = false;
    }

    int listIndex = 1;//當前顯示的物品分類 100~199 武器 200~299 食物 300~399 材料
    void InitThisTypeOfBackpack()
    {
        DestroyCurDisplayGrids();

        content = panelBindingTool.GetOrAddComponentInChildren<RectTransform>("Content");       //獲取容器的組件
        content.sizeDelta = new Vector2(0, Mathf.CeilToInt(BackpackManagerAdvanced.Instance.inventoryConfiguration.lists[listIndex-1].items.Count / column) * (itemSize + interval));      //根據物品數目計算容器的高度(向上取整)

        GameManager.Instance.listIndex = listIndex;
        GameManager.Instance.MethodField = DisplayBackpackGridAdvanced;      //將DisplayBagItem函數注入GameManager的Update中,實現實時更新

        //初始顯示第一個物品
        DisplayItemBeief(BackpackManagerAdvanced.Instance.inventoryConfiguration.lists[listIndex-1].items[0]);
        selectedItem = BackpackManagerAdvanced.Instance.inventoryConfiguration.lists[listIndex-1].items[0];
    }

    void DestroyCurDisplayGrids()
    {
        for(int i = 0;i<curDisplayGrids.Count;i++)
        {
            GameObject.Destroy(curDisplayGrids[i]);
        }
        curDisplayGrids.Clear();
        lastMinDisplayIndex = 0;
        lastMaxDisplayIndex = 0;
    }
    //銷毀正在顯示的格子並初始化相關參數

    public override void OnExit()
    {
        GameManager.Instance.NonMonoUpdateMethod = null;      //取消注入
        GameManager.Instance.MethodField = null;      //取消注入
        panelManager.DestroyPanel(this.panelType);

        OrbitCamera.Instance.work = true;
    }

    public override void OnPause()
    {
        panelBindingTool.GetOrAddComponent<CanvasGroup>().blocksRaycasts = false;
    }

    public override void OnResume()
    {
        panelBindingTool.GetOrAddComponent<CanvasGroup>().blocksRaycasts = true;
    }

    public void DisplayItemBeief(Item item)
    {
        panelBindingTool.GetOrAddComponentInChildren<Text>("Item Name").text = item.name;
        panelBindingTool.GetOrAddComponentInChildren<Text>("Item Description").text = item.description;
        panelBindingTool.GetOrAddComponentInChildren<Image>("Item Image").sprite = Sprite.Create(item.icon, new Rect(0, 0, item.icon.width, item.icon.height), new Vector2(0.5f, 0.5f));
    }

    public void DisplayBackpackGridAdvanced(int listIndex)
    {
        /*-----------計算可見範圍-----------*/

        int minDisplayIndex = (int)(content.anchoredPosition.y / (itemSize + interval)) * column;      //向下取整: 0,0 190,3 950,15
        int maxDisplayIndex = (int)((content.anchoredPosition.y + viewPortHeight) / (itemSize + interval)) * column + column; // 下面一欄物品,露出一點點也需要顯示,所以需要多顯示一行

        /*-----------越界的不顯示-----------*/

        if (minDisplayIndex < 0)
            minDisplayIndex = 0;

        if (maxDisplayIndex > BackpackManagerAdvanced.Instance.inventoryConfiguration.lists[listIndex-1].items.Count)
            maxDisplayIndex = BackpackManagerAdvanced.Instance.inventoryConfiguration.lists[listIndex-1].items.Count;

        /*---------顯示可見範圍內的格子------*/

        for (int i = minDisplayIndex; i < maxDisplayIndex; i++)
        {
            if (curDisplayGrids.ContainsKey(i))                 //已顯示的格子,不再重複創建
                continue;
            else
            {
                GameObject obj = PoolManager.Instance.getObject("BackpackGrid", "Prefabs/UI/BackpackGrid");       //未顯示的格子,從池中獲取
                obj.transform.SetParent(content);
                obj.transform.localPosition = new Vector3(i % column * (itemSize + interval), i / column * (itemSize + interval) * (-1), 0);          //將格子放到正確的比特置上
                obj.GetComponent<BackpackGrid>().InitInfo(BackpackManagerAdvanced.Instance.inventoryConfiguration.lists[listIndex-1].items[i]);                 //初始化格子信息
                obj.GetComponent<BackpackGrid>().OnClick(this, BackpackManagerAdvanced.Instance.inventoryConfiguration.lists[listIndex-1].items[i]);
                curDisplayGrids[i] = obj;                                                               //將當前顯示的格子按照編號錄入字典
            }
        }

        /*----------移除不可見的格子---------*/

        for (int i = lastMaxDisplayIndex; i > maxDisplayIndex; i--)
        {
            if (curDisplayGrids.ContainsKey(i))
            {
                PoolManager.Instance.recycleObject("BackpackGrid", curDisplayGrids[i]);
                curDisplayGrids.Remove(i);
            }
        }

        for (int i = lastMinDisplayIndex; i < minDisplayIndex; i++)
        {
            if (curDisplayGrids.ContainsKey(i))
            {
                PoolManager.Instance.recycleObject("BackpackGrid", curDisplayGrids[i]);
                curDisplayGrids.Remove(i);
            }
        }

        lastMaxDisplayIndex = maxDisplayIndex;
        lastMinDisplayIndex = minDisplayIndex;
    }
}

效果

原网站

版权声明
本文为[海 月]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/162/202206110411057857.html