[3D游戏编程]基于UGUI的背包系统界面

一、界面简介

本次项目实现的是一个游戏的背包系统界面,用户在打开背包系统之后,就可以进行查看背包物品的操作。

二、实现功能

  • 界面可以显示物品基本信息,详细信息
  • 界面可以关闭
  • 点击删除物品等按钮可以在控制台发出提示

三、项目效果

基于【unity UGUI】的游戏背包系统UI界面

 

四、项目设计

1、前端设计

正所谓,“一千个人眼中有一千个哈姆雷特”,前端设计往往体现的是人的审美观,每个人都有自己的想法。本文只会简要介绍前端设计,会介绍一些基本的设计步骤和方法。至于如何设计界面,则是需要每个人发挥想象力啦。

1.1 逻辑结构

场景结构如下

PackagePanel的结构如下

可以看到,整个PackagePanel是被分成几个部分的,接下来将具体介绍每个部分是怎样设计的。

1.2 具体设计

首先新建一个空对象,命名为GameManager,用于挂载脚本。然后创建一个Canvas,Canvas用于建立背包界面。

Background

新建UI -> Image,设置参数如下(颜色是475F7B)

需要注意的是,锚点的设置,选择完全伸展(按住Alt,选择右下角)。

锚点的设置虽然不是必须的,却可以简化我们的工作,将锚点设置在合适的位置,以后在该组件下添加子组件,位置就会更加好设置。

方位设置

每个方位都是先添加一个Empty对象,并将锚点设定为合适的位置(TopCenter设置如下,注意这里没有按Alt)

如果添加Empty对象时不是Rect Transform,就需要在Inspector窗口下的Add Component添加Rect Transform。

Button设置

以Left -> Button为例,在Source Image中拖入Icon,Icon是从素材包中引入的Texture 2D文件(也可以自己ps一个,保存为.png),最后一定一定记得,点Set Native Size,就可以自动显示为原来图片的大小。

图片的大小可以根据分辨率确定,本项目是1920*1080,在Game视图中选Full HD

Menus设置

在TopCenter中有一个Menus,是用于存放顶部的图标,Menus是空对象,里面添加了水平排序和自适应宽度的组件,用于图标自动排序。

同样在Center -> Scroll View -> Viewport -> Content中,也会添加这两个组件,用于自动排序物品。

Text设置

本项目采用的都是UI -> Legacy -> Text,因为可以直接使用中文,而UI -> Text - TextMeshPro使用中文的时候会出现乱码。

可以通过Font Style设置文字样式(粗体),Font Size设置文字大小,Horizontal Overflow如果设置成Overflow,突出的文字就会进入下一行。

滚动框设置

在Center中需要使用Scroll View,用于实现物品的展示功能,结构如下:

Viewport中是要显示的内容,新建空对象命名为Content,用于存储要显示的物品。

2、代码实现

2.1 类图

2.2 代码

BasePanel.cs

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

// BasePanel 类是所有 UI 面板的基类,提供了基本的面板管理功能
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);

        // 销毁面板的 GameObject
        Destroy(gameObject);

        // 从 UIManager 的面板字典中移除对应的记录
        if (UIManager.Instance.panelDict.ContainsKey(name))
        {
            UIManager.Instance.panelDict.Remove(name);
        }
    }
}

PackagePanel.cs

该脚本需要挂载在PackagePanel对象上

其中RefreshScroll是最重要的,用于刷新滚动区域的数据,从而能每次重新打开游戏都能显示玩家现有物品数据。

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

// PackagePanel 类继承自 BasePanel,负责管理背包界面的显示和交互逻辑
public class PackagePanel : BasePanel
{
    // UI元素的引用
    private Transform UIMenu;
    private Transform UIMenuWeapon;
    private Transform UIMenuFood;
    private Transform UITabName;
    private Transform UICloseBtn;
    private Transform UICenter;
    private Transform UIScrollView;
    private Transform UIDetailPanel;
    private Transform UILeftBtn;
    private Transform UIRightBtn;
    private Transform UIDeletePanel;
    private Transform UIDeleteBackBtn;
    private Transform UIDeleteInfoText;
    private Transform UIDeleteConfirmBtn;
    private Transform UIBottomMenus;
    private Transform UIDeleteBtn;
    private Transform UIDetailBtn;

    // PackageUIItemPrefab 是用于实例化背包物品项的预制体
    public GameObject PackageUIItemPrefab;

    // 在 Awake 方法中初始化 UI 元素
    override protected void Awake()
    {
        base.Awake();
        InitUI();
    }

    // 在 Start 方法中刷新 UI
    private void Start()
    {
        RefreshUI();
    }

    // 初始化 UI 元素
    private void InitUI()
    {
        InitUIName();
        InitClick();
    }

    // 刷新整个 UI
    private void RefreshUI()
    {
        RefreshScroll();
    }

    // 刷新滚动区域
    private void RefreshScroll()
    {
        // 清理滚动容器中原本的物品
        RectTransform scrollContent = UIScrollView.GetComponent<ScrollRect>().content;
        for (int i = 0; i < scrollContent.childCount; i++)
        {
            Destroy(scrollContent.GetChild(i).gameObject);
        }

        // 遍历排序后的背包数据,实例化并刷新每个 PackageUIItem
        foreach (PackageLocalItem localData in GameManager.Instance.GetSortPackageLocalData())
        {
            Transform PackageUIItem = Instantiate(PackageUIItemPrefab.transform, scrollContent) as Transform;
            PackageCell packageCell = PackageUIItem.GetComponent<PackageCell>();
            Debug.Log(packageCell);
            packageCell.Refresh(localData, this);
        }
    }

    // 初始化 UI 元素的名称
    private 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);
    }

    // 初始化按钮的点击事件
    private 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);
    }

    // 按钮点击事件
    private void OnClickWeapon()
    {
        print("OnClickWeapon");
    }

    private void OnClickFood()
    {
        print("OnClickFood");
    }

    private void OnClickClose()
    {
        print("OnClickClose");
        ClosePanel();
    }

    private void OnClickLeft()
    {
        print("OnClickLeft");
    }

    private void OnClickRight()
    {
        print("OnClickRight");
    }

    private void OnDeleteBack()
    {
        print("OnDeleteBack");
    }

    private void OnDeleteConfirm()
    {
        print("OnDeleteConfirm");
    }

    private void OnDelete()
    {
        print("OnDelete");
    }

    private void OnDetail()
    {
        print("OnDetail");
    }
}

GameManager.cs

GameManager需要挂载在GameManager上

这里定义了PackageLocalItem对象的排序规则,按星级、ID、等级排序。

using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;
using UnityEngine;

// GameManager 类负责管理游戏中的全局数据和逻辑
public class GameManager : MonoBehaviour
{
    private static GameManager _instance;
    private PackageTable packageTable;

    // 在 Awake 方法中进行单例的初始化和对象的不销毁设置
    private void Awake()
    {
        _instance = this;
        DontDestroyOnLoad(gameObject);
    }

    // 获取 GameManager 的单例实例
    public static GameManager Instance
    {
        get
        {
            return _instance;
        }
    }

    // 游戏开始时调用,打开初始界面并输出背包本地数据和包裹表数据的数量
    void Start()
    {
        UIManager.Instance.OpenPanel(UIConst.PackagePanel);
        //print(GetPackageLocalData().Count);
        //print(GetPackageTable().DataList.Count);
    }

    // 获取数据,数据存储在本地
    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;
    }

    // 根据唯一标识符获取背包本地数据中的物品数据
    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;
    }
}

// PackageItemComparer 类实现了 IComparer 接口,用于比较 PackageLocalItem 对象的排序规则
public class PackageItemComparer : IComparer<PackageLocalItem>
{
    // 比较方法,首先按照包裹表中的星级、ID和等级进行排序
    public int Compare(PackageLocalItem a, PackageLocalItem b)
    {
        PackageTableItem x = GameManager.Instance.GetPackageItemById(a.id);
        PackageTableItem y = GameManager.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)
            {
                // 如果 id 也相同,则按等级从大到小排序
                return b.level.CompareTo(a.level);
            }
            return idComparison;
        }

        return starComparison;
    }
}

UIManager.cs

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

// UIManager 类负责管理游戏中的 UI 界面
public class UIManager
{
    private static UIManager _instance;
    private Transform _uiRoot;

    // 路径配置字典,用于存储界面名称与资源路径的映射关系
    private Dictionary<string, string> pathDict;

    // 预制件缓存字典,用于存储已加载的界面预制件
    private Dictionary<string, GameObject> prefabDict;

    // 已打开界面的缓存字典,用于存储已打开的界面实例
    public Dictionary<string, BasePanel> panelDict;

    // 获取 UIManager 的单例实例
    public static UIManager Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new UIManager();
            }
            return _instance;
        }
    }

    // 获取或创建 UI 根节点
    public Transform UIRoot
    {
        get
        {
            if (_uiRoot == null)
            {
                if (GameObject.Find("Canvas"))
                {
                    _uiRoot = GameObject.Find("Canvas").transform;
                }
                else
                {
                    _uiRoot = new GameObject("Canvas").transform;
                }
            };
            return _uiRoot;
        }
    }

    // 私有构造函数,初始化路径配置字典和预制件缓存字典
    private UIManager()
    {
        InitDicts();
    }

    // 初始化路径配置字典和预制件缓存字典
    private void InitDicts()
    {
        prefabDict = new Dictionary<string, GameObject>();
        panelDict = new Dictionary<string, BasePanel>();

        pathDict = new Dictionary<string, string>()
        {
            {UIConst.PackagePanel, "Package/PackagePanel Variant"},
        };
    }

    // 根据界面名称获取已打开的界面实例,如果未打开返回 null
    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 = "Prefab/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.Log("界面未打开: " + name);
            return false;
        }

        panel.ClosePanel();
        return true;
    }
}

// UIConst 类用于存储界面名称的常量
public class UIConst
{
    // PackagePanel 界面的名称常量
    public const string PackagePanel = "PackagePanel Variant";
}

PackageCell.cs

PackageCell需要挂载在Package UI Item上

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

// PackageCell 类用于管理背包界面中的每个物品项
public class PackageCell : MonoBehaviour
{
    // UI元素的引用
    private Transform UIIcon;
    private Transform UIHead;
    private Transform UINew;
    private Transform UISelect;
    private Transform UILevel;
    private Transform UIStars;
    private Transform UIDeleteSelect;

    // 包裹本地数据、包裹表数据和 UI 父类的引用
    private PackageLocalItem packageLocalData;
    private PackageTableItem packageTableItem;
    private PackagePanel uiParent;

    // 在 Awake 方法中初始化 UI 元素
    private void Awake()
    {
        InitUIName();
    }

    // 初始化 UI 元素的名称
    private 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 的显示内容
    public void Refresh(PackageLocalItem packageLocalData, PackagePanel uiParent)
    {
        // 数据初始化
        this.packageLocalData = packageLocalData;
        this.packageTableItem = GameManager.Instance.GetPackageItemById(packageLocalData.id);
        this.uiParent = uiParent;

        // 等级信息
        UILevel.GetComponent<Text>().text = "Lv." + this.packageLocalData.level.ToString();
        // 是否是新获得
        UINew.gameObject.SetActive(this.packageLocalData.isNew);
        // 物品的图片
        Texture2D t = (Texture2D)Resources.Load(this.packageTableItem.imagePath);
        Sprite temp = Sprite.Create(t, new Rect(0, 0, t.width, t.height), new Vector2(0, 0));
        UIIcon.GetComponent<Image>().sprite = temp;

        // 刷新星级
        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);
            }
        }
    }
}

PackageLocalData.cs和PackageTable.cs

这两个脚本是用于数据存储的,为了方便项目编写,本项目的数据都存放在本地中,PackageLocalData用于用户的本地数据(即一个用户有什么物品),用户的本地数据会存放到PlayerPref,PackageTable用于游戏的数据(即游戏有什么物品),会挂载在Resources -> TableData -> PackageTable.asset上(TableData需要新建,PackageTable.asset在脚本PackageTable.cs写好保存后,就可以在Create -> My -> PackageTable创建)

using UnityEngine;
using System.Collections.Generic;

// PackageLocalData 类用于管理本地背包数据的保存和加载
public class PackageLocalData
{
    private static PackageLocalData _instance;

    // 获取 PackageLocalData 的单例实例
    public static PackageLocalData Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new PackageLocalData();
            }
            return _instance;
        }
    }

    // 背包中的物品列表
    public List<PackageLocalItem> items;

    // 将背包数据保存到 PlayerPrefs
    public void SavePackage()
    {
        // 将 PackageLocalData 对象转换为 JSON 字符串
        string inventoryJson = JsonUtility.ToJson(this);

        // 保存 JSON 字符串到 PlayerPrefs
        PlayerPrefs.SetString("PackageLocalData", inventoryJson);
        PlayerPrefs.Save();
    }

    // 从 PlayerPrefs 加载背包数据
    public List<PackageLocalItem> LoadPackage()
    {
        // 如果已经加载过数据,直接返回缓存的 items 列表
        if (items != null)
        {
            return items;
        }

        // 如果 PlayerPrefs 中存在背包数据,解析 JSON 字符串并返回物品列表
        if (PlayerPrefs.HasKey("PackageLocalData"))
        {
            string inventoryJson = PlayerPrefs.GetString("PackageLocalData");
            Debug.Log(inventoryJson);
            PackageLocalData packageLocalData = JsonUtility.FromJson<PackageLocalData>(inventoryJson);
            items = packageLocalData.items;
            return items;
        }
        else
        {
            // 如果 PlayerPrefs 中不存在背包数据,创建一个新的空列表并返回
            items = new List<PackageLocalItem>();
            return items;
        }
    }
}

// PackageLocalItem 类表示背包中的单个物品的数据结构
[System.Serializable]
public class PackageLocalItem
{
    // 物品的唯一标识符
    public string uid;
    // 物品的ID
    public int id;
    // 物品的数量
    public int num;
    // 物品的等级
    public int level;
    // 物品是否为新物品
    public bool isNew;
    // 重写 ToString 方法,用于输出物品信息的字符串表示
    public override string ToString()
    {
        return string.Format("[id]:{0} [num]:{1}", uid, num);
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// PackageTable 类是一个 ScriptableObject,用于存储游戏中的包裹信息
[CreateAssetMenu(menuName = "My/PackageTable", fileName = "PackageTable")]
public class PackageTable : ScriptableObject
{
    // DataList 用于存储 PackageTableItem 对象的列表
    public List<PackageTableItem> DataList = new List<PackageTableItem>();
}

// PackageTableItem 类是 PackageTable 中存储的每个包裹项的数据结构
[System.Serializable]
public class PackageTableItem
{
    // 物品的唯一标识符
    public int id;
    // 物品的类型
    public int type;
    // 物品的等级
    public int level;
    // 物品的星级
    public int star;
    // 物品的名称
    public string name;
    // 物品的描述
    public string description;
    // 物品技能的描述
    public string skillDescription;
    // 物品的图片路径
    public string imagePath;
}

3、存储数据

为了模拟游戏玩家拥有一定的游戏物品,本项目使用command创建新数据,代码如下:

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

// GMCmd 类包含一些用于编辑器中的快捷命令的静态方法
public class GMCmd
{
    // 用于在编辑器中创建一个 "读取表格" 的菜单项
    [MenuItem("CMCmd/读取表格")]
    public static void ReadTable()
    {
        // 从Resources加载PackageTable
        PackageTable packageTable = Resources.Load<PackageTable>("TableData/PackageTable");

        // 遍历PackageTable中的每个PackageTableItem并输出信息
        foreach (PackageTableItem packageItem in packageTable.DataList)
        {
            Debug.Log(string.Format("【id】:{0}, 【name】:{1}", packageItem.id, packageItem.name));
        }
    }

   // 用于在编辑器中创建一个 "创建背包测试数据" 的菜单项
   [MenuItem("CMCmd/创建背包测试数据")]
    public static void CreateLocalPackageData()
    {
        // 初始化 PackageLocalData 的实例并设置测试数据
        PackageLocalData.Instance.items = new List<PackageLocalItem>();
        for (int i = 1; i < 9; i++)
        {
            PackageLocalItem packageLocalItem = new PackageLocalItem()
            {
                uid = Guid.NewGuid().ToString(),
                id = UnityEngine.Random.Range(1, 9),
                num = UnityEngine.Random.Range(1, 11),
                level = UnityEngine.Random.Range(1, 30),
                isNew = i % 2 == 1
            };
            PackageLocalData.Instance.items.Add(packageLocalItem);
        }

        // 保存测试数据
        PackageLocalData.Instance.SavePackage();
    }

    // 用于在编辑器中创建一个 "读取背包测试数据" 的菜单项
    [MenuItem("CMCmd/读取背包测试数据")]
    public static void ReadLocalPackageData()
    {
        // 读取 PackageLocalData 中的背包测试数据
        List<PackageLocalItem> readItems = PackageLocalData.Instance.LoadPackage();

        // 遍历读取到的数据并输出信息
        foreach (PackageLocalItem item in readItems)
        {
            Debug.Log(item);
        }
    }

    // 用于在编辑器中创建一个 "打开背包主界面" 的菜单项
    [MenuItem("CMCmd/打开背包主界面")]
    public static void OpenPackagePanel()
    {
        // 使用 UIManager 打开背包主界面
        UIManager.Instance.OpenPanel(UIConst.PackagePanel);
    }
}

添加并保存该脚本后,就可以看到如下图的指令操作。可以通过创建背包测试数据模拟玩家获得物品。

对于PackageTable,需要在Inspector窗口中添加游戏物品信息。在PackageTable.cs中有对子项目的描述,物品的图片路径要注意,本项目的图片是在Assets/Resources/Image/UI/Weapon/中的,但是图片路径只需要写(Image/UI/Weapon/图片名,不用加文件后缀!!!)。

五、项目地址

Ivan53471/Packcage-System: nothing
(github.com)

六、项目亮点

  • 前端背包界面设计精美,实现了基本功能
  • 每次重新启动游戏,玩家拥有的物品不会变化
  • 文件结构组织清晰明确
  • 后端代码实现简单易懂

参考资料

【最全面的游戏背包系统讲解 | 技术原理分析 | 框架逻辑设计| 背包+抽卡+整理一网打尽 | 小棋出品,必属精品】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值