Unity 背包的实现

物品类

using System;
using UnityEngine;
using UnityEngine.UI;

[Serializable]
public class Item
{
    public int id;
    public int num;
    public string name;
    public string description;
    public Texture2D icon;
}

物品配置类

在Project中右键 Create -  Items Configuration ,可以生成配置文件

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

[CreateAssetMenu]
public class ItemsConfiguration : ScriptableObject
{
    public List<Item> items;
}

生成配置文件之后,就可以配置相关参数了

背包管理器

读取配置文件到对象,然后从对象的列表中依次对其中包含的物品进行深拷贝,然后加入到背包管理器的物品列表中。

using System.Collections.Generic;
using UnityEngine;

public class BackpackManager: Singleton<BackpackManager>
{
    public List<Item> items = new List<Item>();

    public void ReadItems()
    {
        if (items.Count != 0) return;   //测试用

        ItemsConfiguration itemsConfiguration = Resources.Load<ItemsConfiguration>("Configurations/Items Configuration");
        foreach(var i in itemsConfiguration.items)
        {
            Item item = new Item();
            item.id = i.id;
            item.name = i.name;
            item.num = i.num;
            item.description = i.description;
            item.icon = i.icon;
            items.Add(item);
        }
    }
}

单例类

各种Manager类继承此类之后,可以方便地通过单例获取到该Manager类里的成员

public class Singleton<T> where T : new()
{
    private static T _instance;
    public static T Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new T();
            }
            return _instance;
        }
    }
}

背包格子类

挂载到背包格子的预制体上

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

public class BackpackGrid : MonoBehaviour
{
    public void InitInfo(Item item)
    {
        //更新图标
        GetComponent<Image>().sprite = Sprite.Create(item.icon, new Rect(0, 0, item.icon.width, item.icon.height), new Vector2(0.5f, 0.5f));

        //更新道具数量
        GetComponentInChildren<Text>().text = item.num.ToString();
    }

    public void OnClick(BackpackPanel panel,Item item)
    {
        //添加点击事件
        GetComponent<Button>().onClick.AddListener(() => { panel.DisplayItemBeief(item); });    //问:怎么获取上一级面板 一种解决方法:传进来
    }
}

背包面板类

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 void DisplayBackpackGrid()
    {
        /*-----------计算可见范围-----------*/
        
        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 >= BackpackManager.Instance.items.Count)
            maxDisplayIndex = BackpackManager.Instance.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(BackpackManager.Instance.items[i]);                 //初始化格子信息
                obj.GetComponent<BackpackGrid>().OnClick(this,BackpackManager.Instance.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;
    }

    public override void OnEnter()
    {
        BackpackManager.Instance.ReadItems();                                                //生成格子的演示数据
        content = panelBindingTool.GetOrAddComponentInChildren<RectTransform>("Content");       //获取容器的组件
        content.sizeDelta = new Vector2(0, Mathf.CeilToInt(BackpackManager.Instance.items.Count / column) * (itemSize + interval));      //根据物品数目计算容器的高度(向上取整)

        panelBindingTool.GetOrAddComponentInChildren<Button>("关闭").onClick.AddListener( ()=>
        {
            panelStack.Pop();
        }
        );

        GameManager.instance.NonMonoUpdateMethod = DisplayBackpackGrid;      //将DisplayBagItem函数注入GameManager的Update中,实现实时更新
    }

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

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

}

效果

  • 4
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值