物品类
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));
}
}
效果