基于 项目02《游戏-06-开发》Unity3D ,
接下来做UI框架的逻辑系统,管理器和UI背包,
首先闯将UI框架的两个重要脚本 BasePanel.cs 和 UIManager.cs ,

双击BasePanel.cs脚本修改代码:

using UnityEngine;
 public class BasePanel : MonoBehaviour{
     protected bool isRemove = false;
     protected new string name;
     protected virtual void Awake() { }
     public virtual void SetActive(bool active){
         gameObject.SetActive(active);
     }
     public virtual void OpenPanel(string name){
         this.name = name;
         SetActive(true);
     }
     public virtual void ClosePanel(){
         isRemove = true;
         SetActive(false);
         Destroy(gameObject);
         //移除缓存 表示界面未打开
         if (UIManager.Instance.panelDict.ContainsKey(name))
             UIManager.Instance.panelDict.Remove(name);
     }
 }
双击UIManager.cs脚本修改代码:

using System.Collections.Generic;
 using UnityEngine;
 public class UIManager{
     static UIManager _instance;
     Transform _uiRoot;
     //路径配置字典
     Dictionary<string, string> pathDict;
     //预制体缓存字典
     Dictionary<string, GameObject> prefabDict;
     //已打开界面的缓存字典
     public Dictionary<string, BasePanel> panelDict;
     public static UIManager Instance{
         get{
             if (_instance == null)
                 _instance = new UIManager();
             return _instance;
         }
     }
     public Transform UIRoot{
         get{
             if (_uiRoot == null){
                 if (GameObject.Find("Canvas"))
                     _uiRoot = GameObject.Find("Canvas").transform;
                 else
                     _uiRoot = new GameObject("Canvas").transform;
             };
             return _uiRoot;
         }
     }
     UIManager(){
         InitDicts();
     }
     void InitDicts(){
         prefabDict = new Dictionary<string, GameObject>();
         panelDict = new Dictionary<string, BasePanel>();
         pathDict = new Dictionary<string, string>(){
             //{ UIConst.PackagePanel,"Package/PackagePanel"},//**
         };
     }
     public BasePanel GetPanel(string name){
         BasePanel panel = null;
         //检查是否已打开
         if (panelDict.TryGetValue(name, out panel))
             return panel;
         return null;
     }
     public BasePanel OpenPanel(string name){
         BasePanel panel = null;
         //检查是否已打开
         if (panelDict.TryGetValue(name, out panel)){
             Debug.Log($"界面已打开 {name}");
             return null;
         }
         //检查路径是否配置
         string path = "";
         if (!pathDict.TryGetValue(name, out path)){
             Debug.Log($"界面名称错误 或未配置路径 {name}");
             return null;
         }
         //使用缓存的预制体
         GameObject panelPrefab = null;
         if (!prefabDict.TryGetValue(name, out panelPrefab)){
             string realPath = "Prefabs/Panel/" + path;
             panelPrefab = Resources.Load<GameObject>(realPath) as GameObject;
             prefabDict.Add(name, panelPrefab);
         }
         //打开界面
         GameObject panelObject = GameObject.Instantiate(panelPrefab, UIRoot, false);
         panel = panelObject.GetComponent<BasePanel>();
         panelDict.Add(name, panel);
         panel.OpenPanel(name);
         return panel;
     }
     //关闭界面
     public bool ClosePanel(string name){
         BasePanel panel = null;
         if (!panelDict.TryGetValue(name, out panel)){
             Debug.LogError($"界面未打开 {name}");
             return false;
         }
         panel.ClosePanel();
         return true;
     }
     public class UIConst{
         //public const string PackagePanel = "PackagePanel";//**
     }
 }
 接下来就是使用这个框架,
首先配置这个框架的常量,在UIManger.cs修改代码:

新增PackagePanel这个常量后,接下来配置这个界面的路径,

整体修改代码为:
using System.Collections.Generic;
 using UnityEngine;
 public class UIManager{
     static UIManager _instance;
     Transform _uiRoot;
     //路径配置字典
     Dictionary<string, string> pathDict;
     //预制体缓存字典
     Dictionary<string, GameObject> prefabDict;
     //已打开界面的缓存字典
     public Dictionary<string, BasePanel> panelDict;
     public static UIManager Instance{
         get{
             if (_instance == null)
                 _instance = new UIManager();
             return _instance;
         }
     }
     public Transform UIRoot{
         get{
             if (_uiRoot == null){
                 if (GameObject.Find("Canvas"))
                     _uiRoot = GameObject.Find("Canvas").transform;
                 else
                     _uiRoot = new GameObject("Canvas").transform;
             };
             return _uiRoot;
         }
     }
     UIManager(){
         InitDicts();
     }
     void InitDicts(){
         prefabDict = new Dictionary<string, GameObject>();
         panelDict = new Dictionary<string, BasePanel>();
         pathDict = new Dictionary<string, string>(){
             { UIConst.PackagePanel,"Package/PackagePanel"},//**
         };
     }
     public BasePanel GetPanel(string name){
         BasePanel panel = null;
         //检查是否已打开
         if (panelDict.TryGetValue(name, out panel))
             return panel;
         return null;
     }
     public BasePanel OpenPanel(string name){
         BasePanel panel = null;
         //检查是否已打开
         if (panelDict.TryGetValue(name, out panel)){
             Debug.Log($"界面已打开 {name}");
             return null;
         }
         //检查路径是否配置
         string path = "";
         if (!pathDict.TryGetValue(name, out path)){
             Debug.Log($"界面名称错误 或未配置路径 {name}");
             return null;
         }
         //使用缓存的预制体
         GameObject panelPrefab = null;
         if (!prefabDict.TryGetValue(name, out panelPrefab)){
             string realPath = "Prefabs/Panel/" + path;
             panelPrefab = Resources.Load<GameObject>(realPath) as GameObject;
             prefabDict.Add(name, panelPrefab);
         }
         //打开界面
         GameObject panelObject = GameObject.Instantiate(panelPrefab, UIRoot, false);
         panel = panelObject.GetComponent<BasePanel>();
         panelDict.Add(name, panel);
         panel.OpenPanel(name);
         return panel;
     }
     //关闭界面
     public bool ClosePanel(string name){
         BasePanel panel = null;
         if (!panelDict.TryGetValue(name, out panel)){
             Debug.LogError($"界面未打开 {name}");
             return false;
         }
         panel.ClosePanel();
         return true;
     }
     public class UIConst{
         //配置常量
         public const string PackagePanel = "PackagePanel";//**
     }
 }
 回到unity编辑器中新创建一个脚本文件,PackagePanel.cs脚本,
功能是处理背包界面相关的逻辑处理,

双击PackagPanel.cs脚本修改代码:
它是继承BasePanel.cs脚本的,具体逻辑先不写,

public class PackagePanel : BasePanel{
}
 保存后绑定在unity编辑器中的PackagePanel对象身上,

为了测试背包数据是否正确运行,
我们需要在修改器GMCmd.cs脚本中添加一个打开背包界面的方法,

using System;
 using System.Collections.Generic;
 using UnityEditor;
 using UnityEngine;
 using static UIManager;
 public class GMCmd{
     [MenuItem("CMCmd/读取表格")]
     public static void ReadTable(){
         PackageTable packageTable = Resources.Load<PackageTable>("TableData/PackageTable");
         foreach (PackageTableItem packageItem in packageTable.dataList)
             Debug.Log(string.Format($"[id] {packageItem.id} [name] {packageItem.name}"));
     }
     [MenuItem("CMCmd/创建背包测试数据")]
     public static void CreateLocalPackageData(){
         //保存数据
         PackageLocalData.Instance.items = new List<PackageLocalItem>();
         for (int i = 1; i < 9; i++){
             PackageLocalItem packageLocalItem = new(){
                 uid = Guid.NewGuid().ToString(),
                 id = i,
                 num = i,
                 level = i,
                 isNew = i % 2 == i
             };
             PackageLocalData.Instance.items.Add(packageLocalItem);
         }
         PackageLocalData.Instance.SavaPackage();
     }
     [MenuItem("CMCmd/读取背包测试数据")]
     public static void ReadLocalPackageData(){
         //读取数据
         List<PackageLocalItem> readItems = PackageLocalData.Instance.LoadPackage();
         foreach (PackageLocalItem item in readItems)
             Debug.Log(item);
     }
     [MenuItem("CMCmd/打开背包主界面")]
     public static void OpenPackagePanel(){
         UIManager.Instance.OpenPanel(UIConst.PackagePanel);
     }
 }
 回到unity编辑器中,先把PackagePanel保存在预制体中,然后选择隐藏PackagePanel对象,

运行项目点击修改器GMCmd打开背包即可实现背包的打开,

这样框架已经初步完成,下面开始界面初始化,
界面初始化的第一步就是拿到这些东西,首先在PackagePanel.cs脚本中属性初始化,

using UnityEngine;
 using UnityEngine.UI;
 public class PackagePanel : BasePanel{
     Transform UIMenu;
     Transform UIMenuWeapon;
     Transform UIMenuFood;
     Transform UITabName;
     Transform UICloseBtn;
     Transform UICenter;
     Transform UIScrollView;
     Transform UIDetailPanel;
     Transform UILeftBtn;
     Transform UIRightBtn;
     Transform UIDeletePanel;
     Transform UIDeleteBackBtn;
     Transform UIDeleteInfoText;
     Transform UIDeleteConfirmBtn;
     Transform UIBottomMenus;
     Transform UIDeleteBtn;
     Transform UIDetailBtn;
    override protected void Awake(){
         base.Awake();
         InitUI();
     }
     void InitUI(){
         InitUIName();
         InitClick();
     }
     void InitUIName(){
         UIMenu = transform.Find("TopCenter/Menu");
         UIMenuWeapon = transform.Find("TopCenter/Menus/Weapon");
         UIMenuFood = transform.Find("TopCenter/Menus/Food");
         UITabName = transform.Find("LeftTop/TabName");
         UICloseBtn = transform.Find("RightTop/Close");
         UICenter = transform.Find("Center");
         UIScrollView = transform.Find("Center/Scroll View");
         UIDetailPanel = transform.Find("Center/DetailPanel");
         UILeftBtn = transform.Find("Left/Button");
         UIRightBtn = transform.Find("Right/Button");
        UIDeletePanel = transform.Find("Bottom/DeletePanel");
         UIDeleteBackBtn = transform.Find("Bottom/DeletePanel/Back");
         UIDeleteInfoText = transform.Find("Bottom/DeletePanel/InfoText");
         UIDeleteConfirmBtn = transform.Find("Bottom/DeletePanel/ConfirmBtn");
         UIBottomMenus = transform.Find("Bottom/BottomMenus");
         UIDeleteBtn = transform.Find("Bottom/BottomMenus/DeleteBtn");
         UIDetailBtn = transform.Find("Bottom/BottomMenus/DetailBtn");
        UIDeletePanel.gameObject.SetActive(false);
         UIBottomMenus.gameObject.SetActive(true);
     }
     void InitClick(){
         UIMenuWeapon.GetComponent<Button>().onClick.AddListener(OnClickWeapon);
         UIMenuFood.GetComponent<Button>().onClick.AddListener(OnClickFood);
         UICloseBtn.GetComponent<Button>().onClick.AddListener(OnClickClose);
         UILeftBtn.GetComponent<Button>().onClick.AddListener(OnClickLeft);
         UIRightBtn.GetComponent<Button>().onClick.AddListener(OnClickRight);
        UIDeleteBackBtn.GetComponent<Button>().onClick.AddListener(OnDeleteBack);
         UIDeleteConfirmBtn.GetComponent<Button>().onClick.AddListener(OnDeleteConfirm);
         UIDeleteBtn.GetComponent<Button>().onClick.AddListener(OnDelete);
         UIDetailBtn.GetComponent<Button>().onClick.AddListener(OnDetail);
     }
    void OnDetail(){
         print(">>>>>>> OnDetail()");
     }
     void OnDelete(){
         print(">>>>>>> OnDelete()");
     }
     void OnDeleteConfirm(){
         print(">>>>>>> OnDeleteConfirm()");
     }
     void OnDeleteBack(){
         print(">>>>>>> OnDeleteBack()");
     }
     void OnClickRight(){
         print(">>>>>>> OnClickRight()");
     }
     void OnClickLeft(){
         print(">>>>>>> OnClickLeft()");
     }
     void OnClickWeapon(){
         print(">>>>>>> OnClickWeapon()");
     }
     void OnClickFood(){
         print(">>>>>>> OnClickFood()");
     }
     void OnClickClose(){
         print(">>>>>>> OnClickClose()");
         ClosePanel();
     }
 }
 接下来添加脚本PackageCell.cs脚本用来处理具体道具,

双击PackageCell.cs脚本修改代码:

using UnityEngine;
 public class PackageCell : MonoBehaviour{
     Transform UIIcon;
     Transform UIHead;
     Transform UINew;
     Transform UISelect;
     Transform UILevel;
     Transform UIStars;
     Transform UIDeleteSelect;
    PackageLocalItem packageLocalData;
     PackageTableItem packageTableItem;
     PackagePanel uiParent;
    void Awake(){
         InitUIName();
     }
     void InitUIName(){
         UIIcon = transform.Find("Top/Icon");
         UIHead = transform.Find("Top/Head");
         UINew = transform.Find("Top/New");
         UILevel = transform.Find("Bottom/LevelText");
         UIStars = transform.Find("Bottom/Stars");
         UISelect = transform.Find("Select");
         UIDeleteSelect = transform.Find("DeleteSelect");
        UIDeleteSelect.gameObject.SetActive(false);
     }
 }
 保存代码将PackageCell.cs脚本绑定在unity编辑器的PackageItem对象身上,

解压缩PackagePanel,将PackagePanel对象和PackageItem对象重新放入自己的预制体包中,
检查层级是否正确,

检查是否按键都添加了Button按钮,


回到unity场景中重设PackagePanel对象和PackageItem对象的预制体,
运行项目,打开背包界面,如果没有报错,证明已成功连接,


接下来做控制器逻辑,
也就是说取到动态数据,再配合静态数据,对滚动容器进行初始化,

所以现在要做的就是获取数据,
我们采用一个中间管理器来统一处理这些数据,
修改MainGame.cs脚本:

using System.Collections.Generic;
 using UnityEngine;
 using static UIManager;
 public class MainGame : MonoBehaviour{
     public static Player player;
     void Awake(){
         player = GameObject.Find("Player").GetComponent<Player>();
         //背包系统
         _instance = this;
         DontDestroyOnLoad(gameObject);
     }
     //背包系统
     static MainGame _instance;
     PackageTable packageTable;
     public static MainGame Instance{
         get{
             return _instance;
         }
     }
     void Start(){
         UIManager.Instance.OpenPanel(UIConst.PackagePanel);
     }
     //对静态数据加载
     public PackageTable GetPackageTable(){
         if (packageTable == null)
             packageTable = Resources.Load<PackageTable>("TableData/PackageTable");
         return packageTable;
     }
     //对动态数据加载
     public List<PackageLocalItem> GetPackageLocalData(){
         return PackageLocalData.Instance.LoadPackage();
     }
     //根据ID去表格中拿到指定的数据
     public PackageTableItem GetPackageItemById(int id){
         List<PackageTableItem> packageDataList = GetPackageTable().dataList;
         foreach (PackageTableItem item in packageDataList){
             if (item.id == id)
                 return item;
         }
         return null;
     }
     //根据uid去本地数据中拿到动态数据
     public PackageLocalItem GetPackageLocalItemByUId(string uid){
         List<PackageLocalItem> packageDataList = GetPackageLocalData();
         foreach (PackageLocalItem item in packageDataList){
             if (item.uid == uid)
                 return item;
         }
         return null;
     }
     public List<PackageLocalItem> GetSortPackageLocalData(){
         List<PackageLocalItem> localItems = PackageLocalData.Instance.LoadPackage();
         //localItems.Sort(new PackageItemComparer());
         return localItems;
     }
     public class PackageItemComparer : IComparer<PackageLocalItem>{
         public int Compare(PackageLocalItem a, PackageLocalItem b){
             PackageTableItem x = MainGame.Instance.GetPackageItemById(a.id);
             PackageTableItem y = MainGame.Instance.GetPackageItemById(b.id);
             //首先按star从大到小排序
             int starComparison = y.star.CompareTo(x.star);
             //如果star相同,则按id从大到小排序
             if (starComparison == 0){
                 int idComparison = y.id.CompareTo(x.id);
                 if (idComparison == 0)
                     return b.level.CompareTo(a.level);
                 return idComparison;
             }
             return starComparison;
         }
     }
 }
 修改PackagePanel.cs脚本:添加一个子物体的预制体,

这样在PackagePanel预制体中就可以看到一个公开的属性,
我们将PackageItem预制体拖拽进去,

下一步是添加背包页面PackagePanel.cs的背包滚动容器部分,
把这部分逻辑添加在Start()函数中,
再添加两个方法,

具体代码如下:
using UnityEngine;
 using UnityEngine.UI;
 public class PackagePanel : BasePanel{
     Transform UIMenu;
     Transform UIMenuWeapon;
     Transform UIMenuFood;
     Transform UITabName;
     Transform UICloseBtn;
     Transform UICenter;
     Transform UIScrollView;
     Transform UIDetailPanel;
     Transform UILeftBtn;
     Transform UIRightBtn;
     Transform UIDeletePanel;
     Transform UIDeleteBackBtn;
     Transform UIDeleteInfoText;
     Transform UIDeleteConfirmBtn;
     Transform UIBottomMenus;
     Transform UIDeleteBtn;
     Transform UIDetailBtn;
    //添加
     public GameObject PackageUIItemPrefab;
    override protected void Awake(){
         base.Awake();
         InitUI();
     }
     //添加1
     void Start(){
         RefreshUI();
     }
     //添加1
     void RefreshUI(){
         RefreshScroll();
     }
     //添加1
     void RefreshScroll(){
         //清理滚动容器中原本的物品
         RectTransform scrollContent = UIScrollView.GetComponent<ScrollRect>().content;
         for (int i = 0; i < scrollContent.childCount; i++)
             Destroy(scrollContent.GetChild(i).gameObject);
         //获取本地数据的方法拿到自己身上背包数据 并且根据背包数据初始化滚动容器
         foreach (PackageLocalItem localData in MainGame.Instance.GetSortPackageLocalData()){
             Transform PackageUIItem = Instantiate(PackageUIItemPrefab.transform, scrollContent) as Transform;
            PackageCell packageCell = PackageUIItem.GetComponent<PackageCell>();
             //packageCell.Refresh(localData, this);
         }
     }
     void InitUI(){
         InitUIName();
         InitClick();
     }
     void InitUIName(){
         UIMenu = transform.Find("TopCenter/Menu");
         UIMenuWeapon = transform.Find("TopCenter/Menus/Weapon");
         UIMenuFood = transform.Find("TopCenter/Menus/Food");
         UITabName = transform.Find("LeftTop/TabName");
         UICloseBtn = transform.Find("RightTop/Close");
         UICenter = transform.Find("Center");
         UIScrollView = transform.Find("Center/Scroll View");
         UIDetailPanel = transform.Find("Center/DetailPanel");
         UILeftBtn = transform.Find("Left/Button");
         UIRightBtn = transform.Find("Right/Button");
        UIDeletePanel = transform.Find("Bottom/DeletePanel");
         UIDeleteBackBtn = transform.Find("Bottom/DeletePanel/Back");
         UIDeleteInfoText = transform.Find("Bottom/DeletePanel/InfoText");
         UIDeleteConfirmBtn = transform.Find("Bottom/DeletePanel/ConfirmBtn");
         UIBottomMenus = transform.Find("Bottom/BottomMenus");
         UIDeleteBtn = transform.Find("Bottom/BottomMenus/DeleteBtn");
         UIDetailBtn = transform.Find("Bottom/BottomMenus/DetailBtn");
        UIDeletePanel.gameObject.SetActive(false);
         UIBottomMenus.gameObject.SetActive(true);
     }
     void InitClick(){
         UIMenuWeapon.GetComponent<Button>().onClick.AddListener(OnClickWeapon);
         UIMenuFood.GetComponent<Button>().onClick.AddListener(OnClickFood);
         UICloseBtn.GetComponent<Button>().onClick.AddListener(OnClickClose);
         UILeftBtn.GetComponent<Button>().onClick.AddListener(OnClickLeft);
         UIRightBtn.GetComponent<Button>().onClick.AddListener(OnClickRight);
        UIDeleteBackBtn.GetComponent<Button>().onClick.AddListener(OnDeleteBack);
         UIDeleteConfirmBtn.GetComponent<Button>().onClick.AddListener(OnDeleteConfirm);
         UIDeleteBtn.GetComponent<Button>().onClick.AddListener(OnDelete);
         UIDetailBtn.GetComponent<Button>().onClick.AddListener(OnDetail);
     }
    void OnDetail(){
         print(">>>>>>> OnDetail()");
     }
     void OnDelete(){
         print(">>>>>>> OnDelete()");
     }
     void OnDeleteConfirm(){
         print(">>>>>>> OnDeleteConfirm()");
     }
     void OnDeleteBack(){
         print(">>>>>>> OnDeleteBack()");
     }
     void OnClickRight(){
         print(">>>>>>> OnClickRight()");
     }
     void OnClickLeft(){
         print(">>>>>>> OnClickLeft()");
     }
     void OnClickWeapon(){
         print(">>>>>>> OnClickWeapon()");
     }
     void OnClickFood(){
         print(">>>>>>> OnClickFood()");
     }
     void OnClickClose(){
         print(">>>>>>> OnClickClose()");
         ClosePanel();
     }
 }
 回到unity编辑器中,运行项目可见背包出现8个道具说明背包数量初始化成功,

修改PackageCell.cs脚本,


using UnityEngine;
 using UnityEngine.UI;
 public class PackageCell : MonoBehaviour{
     Transform UIIcon;
     Transform UIHead;
     Transform UINew;
     Transform UISelect;
     Transform UILevel;
     Transform UIStars;
     Transform UIDeleteSelect;
    //动态数据
     PackageLocalItem packageLocalData;
     //静态数据
     PackageTableItem packageTableItem;
     //父物体也就是PackagePanel本身
     PackagePanel uiParent;
    void Awake(){
         InitUIName();
     }
     void InitUIName(){
         UIIcon = transform.Find("Top/Icon");
         UIHead = transform.Find("Top/Head");
         UINew = transform.Find("Top/New");
         UILevel = transform.Find("Bottom/LevelText");
         UIStars = transform.Find("Bottom/Stars");
         UISelect = transform.Find("Select");
         UIDeleteSelect = transform.Find("DeleteSelect");
        UIDeleteSelect.gameObject.SetActive(false);
     }
     //刷新
     public void Refresh(PackageLocalItem packageLocalData, PackagePanel uiParent){
         //数据初始化
         this.packageLocalData = packageLocalData;
         this.packageTableItem = MainGame.Instance.GetPackageItemById(packageLocalData.id);
         this.uiParent = uiParent;
         //等级信息
         UILevel.GetComponent<Text>().text = "Lv." + this.packageLocalData.level.ToString();
         //是否是新获得?
         UINew.gameObject.SetActive(this.packageLocalData.isNew);
         Debug.Log("ImagePath: " + this.packageTableItem.imagePath);
         //物品的图片
         Texture2D t = (Texture2D)Resources.Load(this.packageTableItem.imagePath);
         if (t != null){
             Sprite temp = Sprite.Create(t, new Rect(0, 0, t.width, t.height), new Vector2(0, 0));
             // 继续处理 Sprite 对象
             UIIcon.GetComponent<Image>().sprite = temp;
         }
         else{
             // 处理纹理加载失败的情况
             Debug.LogError("Failed to load texture.");
         }
         //刷新星级
         RefreshStars();
     }
     //刷新星级
     public void RefreshStars(){
         for (int i = 0; i < UIStars.childCount; i++){
             Transform star = UIStars.GetChild(i);
             if (this.packageTableItem.star > i)
                 star.gameObject.SetActive(true);
             else
                 star.gameObject.SetActive(false);
         }
     }
 }
 最后总结代码:

using System;
 using System.Collections.Generic;
 using UnityEditor;
 using UnityEngine;
 using static UIManager;
 public class GMCmd{
     [MenuItem("CMCmd/读取表格")]
     public static void ReadTable(){
         PackageTable packageTable = Resources.Load<PackageTable>("TableData/PackageTable");
         foreach (PackageTableItem packageItem in packageTable.dataList)
             Debug.Log(string.Format($"[id] {packageItem.id} [name] {packageItem.name}"));
     }
     [MenuItem("CMCmd/创建背包测试数据")]
     public static void CreateLocalPackageData(){
         //保存数据
         PackageLocalData.Instance.items = new List<PackageLocalItem>();
         for (int i = 1; i < 9; i++){
             PackageLocalItem packageLocalItem = new(){
                 uid = Guid.NewGuid().ToString(),
                 id = i,
                 num = i,
                 level = i,
                 isNew = i % 2 == i
             };
             PackageLocalData.Instance.items.Add(packageLocalItem);
         }
         PackageLocalData.Instance.SavaPackage();
     }
     [MenuItem("CMCmd/读取背包测试数据")]
     public static void ReadLocalPackageData(){
         //读取数据
         List<PackageLocalItem> readItems = PackageLocalData.Instance.LoadPackage();
         foreach (PackageLocalItem item in readItems)
             Debug.Log(item);
     }
     [MenuItem("CMCmd/打开背包主界面")]
     public static void OpenPackagePanel(){
         UIManager.Instance.OpenPanel(UIConst.PackagePanel);
     }
 }
using System.Collections.Generic;
 using UnityEngine;
 [CreateAssetMenu(menuName = "Water/PackageTable", fileName = "PackageTable")]
 public class PackageTable : ScriptableObject{
     public List<PackageTableItem> dataList = new List<PackageTableItem>();
 }
 [System.Serializable]
 public class PackageTableItem{
     public int id;
     public int type;
     public int star;
     public string name;
     public string description;
     public string skillDescription;
     public string imagePath;
 }
using UnityEngine;
 using UnityEngine.UI;
 public class PackageCell : MonoBehaviour{
     Transform UIIcon;
     Transform UIHead;
     Transform UINew;
     Transform UISelect;
     Transform UILevel;
     Transform UIStars;
     Transform UIDeleteSelect;
    //动态数据
     PackageLocalItem packageLocalData;
     //静态数据
     PackageTableItem packageTableItem;
     //父物体也就是PackagePanel本身
     PackagePanel uiParent;
    void Awake(){
         InitUIName();
     }
     void InitUIName(){
         UIIcon = transform.Find("Top/Icon");
         UIHead = transform.Find("Top/Head");
         UINew = transform.Find("Top/New");
         UILevel = transform.Find("Bottom/LevelText");
         UIStars = transform.Find("Bottom/Stars");
         UISelect = transform.Find("Select");
         UIDeleteSelect = transform.Find("DeleteSelect");
        UIDeleteSelect.gameObject.SetActive(false);
     }
     //刷新
     public void Refresh(PackageLocalItem packageLocalData, PackagePanel uiParent){
         //数据初始化
         this.packageLocalData = packageLocalData;
         this.packageTableItem = MainGame.Instance.GetPackageItemById(packageLocalData.id);
         this.uiParent = uiParent;
         //等级信息
         UILevel.GetComponent<Text>().text = "Lv." + this.packageLocalData.level.ToString();
         //是否是新获得?
         UINew.gameObject.SetActive(this.packageLocalData.isNew);
         Debug.Log("ImagePath: " + this.packageTableItem.imagePath);
         //物品的图片
         Texture2D t = (Texture2D)Resources.Load(this.packageTableItem.imagePath);
         if (t != null){
             Sprite temp = Sprite.Create(t, new Rect(0, 0, t.width, t.height), new Vector2(0, 0));
             // 继续处理 Sprite 对象
             UIIcon.GetComponent<Image>().sprite = temp;
         }
         else{
             // 处理纹理加载失败的情况
             Debug.LogError("Failed to load texture.");
         }
         //刷新星级
         RefreshStars();
     }
     //刷新星级
     public void RefreshStars(){
         for (int i = 0; i < UIStars.childCount; i++){
             Transform star = UIStars.GetChild(i);
             if (this.packageTableItem.star > i)
                 star.gameObject.SetActive(true);
             else
                 star.gameObject.SetActive(false);
         }
     }
 }
using UnityEngine;
 using UnityEngine.UI;
 public class PackagePanel : BasePanel{
     Transform UIMenu;
     Transform UIMenuWeapon;
     Transform UIMenuFood;
     Transform UITabName;
     Transform UICloseBtn;
     Transform UICenter;
     Transform UIScrollView;
     Transform UIDetailPanel;
     Transform UILeftBtn;
     Transform UIRightBtn;
     Transform UIDeletePanel;
     Transform UIDeleteBackBtn;
     Transform UIDeleteInfoText;
     Transform UIDeleteConfirmBtn;
     Transform UIBottomMenus;
     Transform UIDeleteBtn;
     Transform UIDetailBtn;
    //添加
     public GameObject PackageUIItemPrefab;
    override protected void Awake(){
         base.Awake();
         InitUI();
     }
     //添加1
     void Start(){
         RefreshUI();
     }
     //添加1
     void RefreshUI(){
         RefreshScroll();
     }
     //添加1
     void RefreshScroll(){
         //清理滚动容器中原本的物品
         RectTransform scrollContent = UIScrollView.GetComponent<ScrollRect>().content;
         for (int i = 0; i < scrollContent.childCount; i++)
             Destroy(scrollContent.GetChild(i).gameObject);
         //获取本地数据的方法拿到自己身上背包数据 并且根据背包数据初始化滚动容器
         foreach (PackageLocalItem localData in MainGame.Instance.GetSortPackageLocalData()){
             Transform PackageUIItem = Instantiate(PackageUIItemPrefab.transform, scrollContent) as Transform;
            PackageCell packageCell = PackageUIItem.GetComponent<PackageCell>();
             //添加2
             packageCell.Refresh(localData, this);
         }
     }
     void InitUI(){
         InitUIName();
         InitClick();
     }
     void InitUIName(){
         UIMenu = transform.Find("TopCenter/Menu");
         UIMenuWeapon = transform.Find("TopCenter/Menus/Weapon");
         UIMenuFood = transform.Find("TopCenter/Menus/Food");
         UITabName = transform.Find("LeftTop/TabName");
         UICloseBtn = transform.Find("RightTop/Close");
         UICenter = transform.Find("Center");
         UIScrollView = transform.Find("Center/Scroll View");
         UIDetailPanel = transform.Find("Center/DetailPanel");
         UILeftBtn = transform.Find("Left/Button");
         UIRightBtn = transform.Find("Right/Button");
        UIDeletePanel = transform.Find("Bottom/DeletePanel");
         UIDeleteBackBtn = transform.Find("Bottom/DeletePanel/Back");
         UIDeleteInfoText = transform.Find("Bottom/DeletePanel/InfoText");
         UIDeleteConfirmBtn = transform.Find("Bottom/DeletePanel/ConfirmBtn");
         UIBottomMenus = transform.Find("Bottom/BottomMenus");
         UIDeleteBtn = transform.Find("Bottom/BottomMenus/DeleteBtn");
         UIDetailBtn = transform.Find("Bottom/BottomMenus/DetailBtn");
        UIDeletePanel.gameObject.SetActive(false);
         UIBottomMenus.gameObject.SetActive(true);
     }
     void InitClick(){
         UIMenuWeapon.GetComponent<Button>().onClick.AddListener(OnClickWeapon);
         UIMenuFood.GetComponent<Button>().onClick.AddListener(OnClickFood);
         UICloseBtn.GetComponent<Button>().onClick.AddListener(OnClickClose);
         UILeftBtn.GetComponent<Button>().onClick.AddListener(OnClickLeft);
         UIRightBtn.GetComponent<Button>().onClick.AddListener(OnClickRight);
        UIDeleteBackBtn.GetComponent<Button>().onClick.AddListener(OnDeleteBack);
         UIDeleteConfirmBtn.GetComponent<Button>().onClick.AddListener(OnDeleteConfirm);
         UIDeleteBtn.GetComponent<Button>().onClick.AddListener(OnDelete);
         UIDetailBtn.GetComponent<Button>().onClick.AddListener(OnDetail);
     }
    void OnDetail(){
         print(">>>>>>> OnDetail()");
     }
     void OnDelete(){
         print(">>>>>>> OnDelete()");
     }
     void OnDeleteConfirm(){
         print(">>>>>>> OnDeleteConfirm()");
     }
     void OnDeleteBack(){
         print(">>>>>>> OnDeleteBack()");
     }
     void OnClickRight(){
         print(">>>>>>> OnClickRight()");
     }
     void OnClickLeft(){
         print(">>>>>>> OnClickLeft()");
     }
     void OnClickWeapon(){
         print(">>>>>>> OnClickWeapon()");
     }
     void OnClickFood(){
         print(">>>>>>> OnClickFood()");
     }
     void OnClickClose(){
         print(">>>>>>> OnClickClose()");
         ClosePanel();
     }
 }
using System.Collections.Generic;
 using UnityEngine;
 public class UIManager{
     static UIManager _instance;
     Transform _uiRoot;
     //路径配置字典
     Dictionary<string, string> pathDict;
     //预制体缓存字典
     Dictionary<string, GameObject> prefabDict;
     //已打开界面的缓存字典
     public Dictionary<string, BasePanel> panelDict;
     public static UIManager Instance{
         get{
             if (_instance == null)
                 _instance = new UIManager();
             return _instance;
         }
     }
     public Transform UIRoot{
         get{
             if (_uiRoot == null){
                 if (GameObject.Find("Canvas"))
                     _uiRoot = GameObject.Find("Canvas").transform;
                 else
                     _uiRoot = new GameObject("Canvas").transform;
             };
             return _uiRoot;
         }
     }
     UIManager(){
         InitDicts();
     }
     void InitDicts(){
         prefabDict = new Dictionary<string, GameObject>();
         panelDict = new Dictionary<string, BasePanel>();
         pathDict = new Dictionary<string, string>(){
             { UIConst.PackagePanel,"Package/PackagePanel"},//**
         };
     }
     public BasePanel GetPanel(string name){
         BasePanel panel = null;
         //检查是否已打开
         if (panelDict.TryGetValue(name, out panel))
             return panel;
         return null;
     }
     public BasePanel OpenPanel(string name){
         BasePanel panel = null;
         //检查是否已打开
         if (panelDict.TryGetValue(name, out panel)){
             Debug.Log($"界面已打开 {name}");
             return null;
         }
         //检查路径是否配置
         string path = "";
         if (!pathDict.TryGetValue(name, out path)){
             Debug.Log($"界面名称错误 或未配置路径 {name}");
             return null;
         }
         //使用缓存的预制体
         GameObject panelPrefab = null;
         if (!prefabDict.TryGetValue(name, out panelPrefab)){
             string realPath = "Prefabs/Panel/" + path;
             panelPrefab = Resources.Load<GameObject>(realPath) as GameObject;
             prefabDict.Add(name, panelPrefab);
         }
         //打开界面
         GameObject panelObject = GameObject.Instantiate(panelPrefab, UIRoot, false);
         panel = panelObject.GetComponent<BasePanel>();
         panelDict.Add(name, panel);
         panel.OpenPanel(name);
         return panel;
     }
     //关闭界面
     public bool ClosePanel(string name){
         BasePanel panel = null;
         if (!panelDict.TryGetValue(name, out panel)){
             Debug.LogError($"界面未打开 {name}");
             return false;
         }
         panel.ClosePanel();
         return true;
     }
     public class UIConst{
         //配置常量
         public const string PackagePanel = "PackagePanel";//**
     }
 }
using System.Collections.Generic;
 using UnityEngine;
 using static UIManager;
 public class MainGame : MonoBehaviour{
     public static Player player;
     void Awake(){
         player = GameObject.Find("Player").GetComponent<Player>();
         //背包系统
         _instance = this;
         DontDestroyOnLoad(gameObject);
     }
     //背包系统
     static MainGame _instance;
     PackageTable packageTable;
     public static MainGame Instance{
         get{
             return _instance;
         }
     }
     void Start(){
         UIManager.Instance.OpenPanel(UIConst.PackagePanel);
     }
     //对静态数据加载
     public PackageTable GetPackageTable(){
         if (packageTable == null)
             packageTable = Resources.Load<PackageTable>("TableData/PackageTable");
         return packageTable;
     }
     //对动态数据加载
     public List<PackageLocalItem> GetPackageLocalData(){
         return PackageLocalData.Instance.LoadPackage();
     }
     //根据ID去表格中拿到指定的数据
     public PackageTableItem GetPackageItemById(int id){
         List<PackageTableItem> packageDataList = GetPackageTable().dataList;
         foreach (PackageTableItem item in packageDataList){
             if (item.id == id)
                 return item;
         }
         return null;
     }
     //根据uid去本地数据中拿到动态数据
     public PackageLocalItem GetPackageLocalItemByUId(string uid){
         List<PackageLocalItem> packageDataList = GetPackageLocalData();
         foreach (PackageLocalItem item in packageDataList){
             if (item.uid == uid)
                 return item;
         }
         return null;
     }
     public List<PackageLocalItem> GetSortPackageLocalData(){
         List<PackageLocalItem> localItems = PackageLocalData.Instance.LoadPackage();
         localItems.Sort(new PackageItemComparer());//添加
         return localItems;
     }
     public class PackageItemComparer : IComparer<PackageLocalItem>{
         public int Compare(PackageLocalItem a, PackageLocalItem b){
             PackageTableItem x = MainGame.Instance.GetPackageItemById(a.id);
             PackageTableItem y = MainGame.Instance.GetPackageItemById(b.id);
             //首先按star从大到小排序
             int starComparison = y.star.CompareTo(x.star);
             //如果star相同,则按id从大到小排序
             if (starComparison == 0){
                 int idComparison = y.id.CompareTo(x.id);
                 if (idComparison == 0)
                     return b.level.CompareTo(a.level);
                 return idComparison;
             }
             return starComparison;
         }
     }
 }
using System.Collections.Generic;
 using UnityEngine;
 public class PackageLocalData{
     static PackageLocalData _instance;
     public static PackageLocalData Instance{
         get{
             if (_instance == null)
                 _instance = new PackageLocalData();
             return _instance;
         }
     }
     //存
     public List<PackageLocalItem> items;
     public void SavaPackage(){
         string inventoryJson = JsonUtility.ToJson(this);
         PlayerPrefs.SetString("PackageLocalData", inventoryJson);
         PlayerPrefs.Save();
     }
     //取
     public List<PackageLocalItem> LoadPackage(){
         if (items != null)
             return items;
         if (PlayerPrefs.HasKey("PackageLocalData")){
             string inventoryJson = PlayerPrefs.GetString("PackageLocalData");
             PackageLocalData packageLocalData = JsonUtility.FromJson<PackageLocalData>(inventoryJson);
             items = packageLocalData.items;
             return items;
         }
         else{
             items = new List<PackageLocalItem>();
             return items;
         }
     }
 }
 [System.Serializable]
 public class PackageLocalItem{
     public string uid;
     public int id;
     public int num;
     public int level;
     public bool isNew;
     public override string ToString(){
         return string.Format($"[id] {id} [num] {num}");
     }
 }
using UnityEngine;
 public class BasePanel : MonoBehaviour{
     protected bool isRemove = false;
     protected new string name;
     protected virtual void Awake() { }
     public virtual void SetActive(bool active){
         gameObject.SetActive(active);
     }
     public virtual void OpenPanel(string name){
         this.name = name;
         SetActive(true);
     }
     public virtual void ClosePanel(){
         isRemove = true;
         SetActive(false);
         Destroy(gameObject);
         //移除缓存 表示界面未打开
         if (UIManager.Instance.panelDict.ContainsKey(name))
             UIManager.Instance.panelDict.Remove(name);
     }
 }
 修改PackageTable组件武器编号:



运行项目即实现,

End.