Unity背包系统与存档(附下载链接)

news2024/12/27 14:42:48

下载地址:

https://download.csdn.net/download/qq_58804985/88184776

视频演示:

功能:

拖动物品在背包中自由移动,当物品拖动到其他物品上时,和其交换位置.基于EPPlus的背包数据与位置保存

原理:

给定一个道具池表格与一个背包表格

道具池表格负责存储所有道具的信息

背包表格负责存储将玩家背包的档案储存

当增删道具时,从道具池表格中检索对应的道具写入背包表格

优化方案拓展:当道具数量众多时,在增删物品时可以将物品分类存储到不同的道具池表格,根据Type检索对应表格的数据

效果:

 

 

 代码:

背包系统核心

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using OfficeOpenXml;
using System.IO;
using UnityEngine.Networking;
using UnityEngine.UI;
using Random = UnityEngine.Random;
 

public class BagSystem : MonoBehaviour
{
    public static string ReadingExcel;//正在读取的表格
    [Header("表格文件夹")]
    public string URL = Application.streamingAssetsPath + $"\\Bag";
    [Header("存放背包EXCEL的表格名称")]
    public string BagExcelURL="Bag";
    [Header("存放道具EXCEL的表格名称")]
    public string ItemExcelURL="Item";

    /// <summary>
    /// 背包是否处于打开状态
    /// </summary>
    public static bool IsOpening;

    [Header("存放Sprite的文件夹(依赖resource)")] public string SpriteURL ="Bag";
    public static List<BagItem> MyBag= new List<BagItem>();//当前背包
    public static List<BagItem> ItemPool= new List<BagItem>();//道具池
    private static bool m_loaded;
    
    public virtual void OnEnable()
    {
        initialization();
        IsOpening = true;
    }

    //初始化
    public void initialization()
    {
        if (!m_loaded)
        {
            LoadExcel();
            m_loaded = true;

        } 

    }
    
    public class BagItem
    {
        public string Name;//物品名称
        public string Num;//物品数量
        public string Image;//图片地址
        public string x;//位置X
        public string y;//位置Y
    }

    //获取当前背包内的所有物品
    public static List<BagItem> GetItemList()
    {
        return MyBag;
    }
/// <summary>
/// 从玩家背包获取指定物品数量
/// </summary>
/// <param name="name">物品名称</param>
/// <returns></returns>
    public static int GetItem(string name)
    {
        foreach (var VARIABLE in MyBag)
        {
            if (VARIABLE.Name==name)
            {
                return Convert.ToInt32(VARIABLE.Num);
            }
        }

        Debug.LogWarning($"你试图找{name},但是没有找到");
        return 0;
    }

/// <summary>
/// 向背包添加指定物体
/// </summary>
/// <param name="name">物体名称</param>
/// <param name="num">物体数量</param>
/// <param name="X">坐标X</param>
/// <param name="Y">坐标Y</param>
public static void AddItem(string name, int num=1,int X=50,int Y=50)
    {
        foreach (var VARIABLE in ItemPool)
        {
            if (VARIABLE.Name==name)
            {
                foreach (var bagItem in MyBag)
                {
                    if (bagItem.Name==name)
                    {
                        bagItem.Num = Convert.ToInt32(Convert.ToInt32(bagItem.Num) + num).ToString();
                        return;
                    }
                }
                MyBag.Add(new BagItem(){Name = VARIABLE.Name,Num = num.ToString(),Image = VARIABLE.Image,x=X.ToString(),y=Y.ToString()});
                Debug.Log($"添加了{name}");
                return;
            }
        }
        Debug.LogWarning($"你试图添加道具{name},但是没有找到.excel路径{Application.streamingAssetsPath+$"\\Bag"}");
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="name">目标物体</param>
    /// <param name="num">删除数量</param>
    /// <returns>删除成功?</returns>
    public static bool RemoveItem(string name, int num=1)
    {
        if (GetItem(name)>=num)
        {
            foreach (var VARIABLE in MyBag)
            {
                if (VARIABLE.Name==name)
                {
                    VARIABLE.Num = (Convert.ToInt32(VARIABLE.Num) - num).ToString();
                    if (VARIABLE.Num=="0")
                    {
                    
                    }
                }
            }
            return true;
        }

        return false;
    }
    
    
    
    
    //初始化_读取背包EXCEL
    void LoadExcel()
    {

        //获取Excel文件的信息
        foreach (var VARIABLE in ReadFile())
        {

            FileInfo fileInfo = new FileInfo(VARIABLE);
            //加载背包信息
            if (VARIABLE.Contains(BagExcelURL))
            {

                //通过Excel表格的文件信息,打开Excel表格
                //使用using(){}语句命令,在结束时自动关闭文件
                using (ExcelPackage excelPackage = new ExcelPackage(fileInfo))
                {
                    //读取Excel中的第一张表, 注意EPPlus的索引值是从1开始的

                    ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets[1];
                    //取得第一行第一列的数据
//                    Debug.Log("行数"+worksheet.Dimension.End.Row + 1);
                    for (int Left = 2; Left < worksheet.Dimension.End.Row + 1; Left++) //根据行数遍历
                    {

                        BagItem Q = new BagItem();
                        if (worksheet.Cells[Left, 1].Value.ToString().Length>0)
                        {  
                            Q.Name = worksheet.Cells[Left, 1].Value.ToString();
                            Q.Num = worksheet.Cells[Left, 2].Value.ToString();
                            Q.Image = worksheet.Cells[Left, 3].Value.ToString();
                            Q.x = worksheet.Cells[Left, 4].Value.ToString();
                            Q.y = worksheet.Cells[Left, 5].Value.ToString();
                            MyBag.Add(Q);
                            
                        }
                     
                    }
                }


            }
            
            //加载物品信息
            if (VARIABLE.Contains(ItemExcelURL))
            {
                //通过Excel表格的文件信息,打开Excel表格
                //使用using(){}语句命令,在结束时自动关闭文件
                using (ExcelPackage excelPackage = new ExcelPackage(fileInfo))
                {
                    //读取Excel中的第一张表, 注意EPPlus的索引值是从1开始的

                    ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets[1];
                    //取得第一行第一列的数据
                    for (int Left = 2; Left < worksheet.Dimension.End.Row + 1; Left++) //根据行数遍历
                    {
//                        Debug.Log(worksheet.Dimension.End.Row + 1);
                        BagItem Q = new BagItem();
                        Q.Name = worksheet.Cells[Left, 1].Value.ToString();
                        Q.Image = worksheet.Cells[Left, 2].Value.ToString();
                        ItemPool.Add(Q);
                    }
                }
            }
        }

    }
    
    //将背包数据写入EXCEL
    void SaveExcel()
    {
        foreach (var VARIABLE in ReadFile())
        {

            if (VARIABLE.Contains(BagExcelURL))
            {
                FileInfo fileInfo = new FileInfo(VARIABLE);

                using (ExcelPackage excelPackage = new ExcelPackage(fileInfo))
                {
                    ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets[1];

                    for (int i = 0; i < MyBag.Count; i++)
                    {
                        worksheet.Cells[i+2, 1].Value = MyBag[i].Name;
                        worksheet.Cells[i+2, 2].Value = MyBag[i].Num;
                        worksheet.Cells[i+2, 3].Value = MyBag[i].Image;
                        worksheet.Cells[i+2, 4].Value = MyBag[i].x;
                        worksheet.Cells[i+2, 5].Value = MyBag[i].y;
//                        Debug.Log(i);
                    }
                    excelPackage.Save();
                }
                

            }
        }
        
    }

 
    List<string> ReadFile()
    {
        List<string> files = GetFiles(URL, "*.xlsx");


        List<string> GetFiles(string directory, string pattern)
        {
            List<string> files = new List<string>();
            foreach (var item in Directory.GetFiles(directory, pattern))
            {
                files.Add(item);
            }

            foreach (var item in Directory.GetDirectories(directory))
            {
                files.AddRange(GetFiles(item, pattern));
            }

            return files;
        }

        return files;
    }

    public virtual void OnDisable()
    {
        SaveExcel();
        IsOpening = false;
    }
}

物品拖动:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
using UnityEngine;
using UnityEngine.EventSystems;

/*
 * 这个脚本负责拖拽物品UI
 */
[RequireComponent(typeof(CanvasGroup),typeof(RectTransform),typeof(Rigidbody))]
[RequireComponent(typeof(BoxCollider))]
public class ItemDrag : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
 //存储坐标
 public Vector2 XY;
 private RectTransform rectTransform;
 private CanvasGroup canvasGroup;

 public Vector2 SaveXY;
 private Vector2 offset;
 [Header("拖拽时物品的透明度")]
 public  float AlphaOnDrag=0.6f;

 private Transform parent;
 private Transform save_parent;
 private void OnEnable()
 {
  GetComponent<Rigidbody>().useGravity = false;
  GetComponent<BoxCollider>().isTrigger = true;
  GetComponent<BoxCollider>().size=Vector3.one;


  XY = GetComponent<RectTransform>().anchoredPosition;
  rectTransform = GetComponent<RectTransform>();
  canvasGroup = GetComponent<CanvasGroup>();
 }

 public void OnBeginDrag(PointerEventData eventData)
 {
  SaveXY = XY;
  


  // 设置拖拽中UI元素的透明度
  canvasGroup.alpha = AlphaOnDrag;
  canvasGroup.blocksRaycasts = false;
 }

 private void OnTriggerStay(Collider other)
 {
  Debug.Log(other.name);
  if (isEmptyPlace(other))
  {
   if (transform.parent==other.transform.parent)
   {
    transform.parent = other.transform;
   }
   
   XY = other.transform.position;
   save_parent = other.transform;
  }
 }

 private void OnTriggerExit(Collider other)
 {
  if (isEmptyPlace(other))
  {
   XY = Vector2.zero;
   save_parent = null;
  }
 }

 //判断是否是空道具栏位?
 bool isEmptyPlace(Collider other)
 {
  if (!other.name.Contains("Empty"))
  {
   return false;
  }
  

  return true;
 }
 
 public void OnDrag(PointerEventData eventData)
 {
  transform.position = Input.mousePosition;
  Vector2 position = eventData.position;
  RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform.parent as RectTransform, position, eventData.pressEventCamera, out position);
  rectTransform.anchoredPosition = position - offset;
  transform.parent.SetAsLastSibling();
 }

 public void OnEndDrag(PointerEventData eventData)
 {
  // 恢复透明度和射线检测
  canvasGroup.alpha = 1f;
  canvasGroup.blocksRaycasts = true;

  // 拖拽结束时,如果没有拖拽到有效位置,则恢复到初始位置
  if (XY==Vector2.zero)
  {
   transform.position = SaveXY;
   XY = SaveXY;
  }
  else
  {

   //为空,设置为子物体.否则交换两个背包格子的位置
   if (save_parent.transform.childCount==0)
   {
    transform.position = XY;
    SaveXY = XY;
    transform.parent = save_parent;
   }
   else
   {
    Vector3 tempPosition = save_parent.GetChild(0).transform.position;
    save_parent.GetChild(0).transform.position = SaveXY;
    save_parent.GetChild(0).transform.parent = transform.parent;
    transform.parent = save_parent;
    transform.position = tempPosition;
    save_parent.SetAsLastSibling();
    transform.parent.SetAsLastSibling();
   }

   for (int i = 0; i < BagSystem.MyBag.Count; i++)
   {
    if (name.Contains(BagSystem.MyBag[i].Name))
    {
     BagSystem.MyBag[i].x = XY.x.ToString(CultureInfo.InvariantCulture);
     BagSystem.MyBag[i].y = XY.y.ToString(CultureInfo.InvariantCulture);
    }

   }


  }
 }
}

示例:

using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UI;

/*
 * 示例用代码
 */

public class Bag_Demo : BagSystem
{
    [Header("空格子的预设体")]
    public GameObject PlacePrefab;

    public override void OnEnable()
    {

        URL = Application.streamingAssetsPath + $"\\Excels";
        base.OnEnable();

        #region 根据背包生成对应物体

        foreach (var VARIABLE in MyBag)
        {
            #region 创建模板.正式应用建议使用prefab

            if (VARIABLE.Num!="0")
            {
                GameObject item = new GameObject();
                item.AddComponent<Image>().sprite=Resources.Load<Sprite>($"Sprite/{VARIABLE.Image}");
                item.transform.position =
                    new Vector2(float.Parse(VARIABLE.x), float.Parse(VARIABLE.y));
                item.transform.parent = transform.Find("Place");

                item.AddComponent<ItemDrag>();

                GameObject Num = Instantiate(new GameObject(), item.transform);
                Num.name = "Num";
                Num.AddComponent<Text>();
                Num.GetComponent<Text>().font = Resources.GetBuiltinResource<Font>("Arial.ttf");;
                Num. GetComponent<Text>().text = VARIABLE.Num;
                Num.GetComponent<Text>().color=Color.magenta;
            
                item.name = VARIABLE.Name;

            }
            
         
            #endregion

            
        }

        #endregion

    }

    /// <summary>
    /// 重加载
    /// </summary>
    IEnumerator BagReset()
    {

        OnDisable();
        OnEnable();
        yield break;
    }

    public void Add_Button(string a)
    {

        AddItem(a);
        if (IsOpening)
        {
            StartCoroutine(BagReset());
        }

        string log = "当前背包里有:\n";
        foreach (var VARIABLE in MyBag)
        {
            log += $"\n{VARIABLE.Num}个{VARIABLE.Name}\n";
        }
        Debug.Log(log);
    }
    public void Remove_Button(string a)
    {

        //当数量为0时,删除处理
        try
        {
            RemoveItem(a);
        }
        catch (InvalidOperationException e)
        {
            foreach (var VARIABLE in transform.Find("Place").GetComponentsInChildren<Transform>())
            {
                if (VARIABLE.name.Contains(a))
                {
                    Destroy(VARIABLE.gameObject);
                }
            }
        }

        if (IsOpening)
        {
            StartCoroutine(BagReset());
        }
    }

    public override void OnDisable()
    {
        base.OnDisable();
        foreach (var VARIABLE in transform.Find("Place").GetComponentsInChildren<Transform>())
        {
            if (VARIABLE.name!="Place"&& !VARIABLE.name.Contains("Empty"))
            {
                Destroy(VARIABLE.gameObject);
            }

        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/845697.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

岩土工程监测仪器多通道振弦传感器信号转换器应用于铁路监测

岩土工程监测仪器多通道振弦传感器信号转换器应用于铁路监测 岩土工程监测是工程建设和运营过程中必不可少的环节&#xff0c;它主要是通过对地下水位、土体应力、变形、固结沉降等参数进行实时监测&#xff0c;以保证工程施工和运营的安全性和稳定性。而多通道振弦传感器信号…

JavaScript数据结构【进阶】

注&#xff1a;最后有面试挑战&#xff0c;看看自己掌握了吗 文章目录 使用 splice() 添加元素使用 slice() 复制数组元素使用展开运算符复制数组使用展开运算符合并数组使用 indexOf() 检查元素是否存在使用 for 循环遍历数组中的全部元素创建复杂的多维数组将键值对添加到对象…

阶段总结(linux基础)

目录 一、初始linux系统 二、基本操作命令 三、目录结构 四、文件及目录管理命令 查看文件内容 创建文件 五、用户与组管理 六、文件权限与压缩管理 七、磁盘管理 八、系统程序与进程管理 管理机制 文件系统损坏 grub引导故障 磁盘资源耗尽 程序与进程的区别 查…

Grafana V10 告警推送

最近项目建设完成&#xff0c;一个城域网项目&#xff0c;相关zabbix和grafana展示已经完&#xff0c;想了想&#xff0c;不想天天看平台去盯网络监控平台&#xff0c;索性对告警进行分类调整&#xff0c;增加告警的推送&#xff0c;和相关部门的提醒&#xff0c;其他部门看不懂…

绿盾用户使用看图软件每次都需要把图片解密之后才能打开查看,怎么才能不用这么麻烦打开就能看

环境: Win10专业版 绿盾控制台7.0 看图软件FastStone Image Viewer 问题描述: 绿盾用户使用看图软件FastStone Image Viewer每次都需要把图片解密之后才能打开查看,怎么才能不用这么麻烦打开就能看,用户说每次都需要把图片解密之后才能使用,实在是影响效率 解决方案…

4、长度最小的子数组

找到一个数组中&#xff0c;有多少个连续元素的和小于某个值&#xff0c;求出连续元素的长度的最小值。 滑动窗口法&#xff1a; 其本质也是快慢指针&#xff0c;一个指针指向窗口的起始位置&#xff0c;另一个指针指向窗口的终止位置。 1.定义快慢指针&#xff1a; 2.更新慢指…

css-3:什么是响应式设计?响应式的原理是什么?如何做?

1、响应式设计是什么&#xff1f; 响应式网站设计&#xff08;Responsive WEB desgin&#xff09;是一个网络页面设计布局&#xff0c;页面的设计与开发应当根据用户行为以及设备环境&#xff08;系统平台、屏幕尺寸、屏幕定向等&#xff09;进行相应的相应和调整。 描述响应式…

Unity 实现字幕打字效果

Text文本打字效果&#xff0c;TextMeshPro可以对应参考&#xff0c;差距不大&#xff0c;改改参数名就能用。改脚本原本被我集成到其他的程序集中&#xff0c;现在已经分离。 效果 实现功能 1.能够设置每行能够容纳的字数和允许的冗余 2.打字效果 3.每行打完上移 4.开头进入&…

项目实战 — 消息队列(5){统一硬盘操作}

前面已经使用数据库管理了交换机、绑定、队列&#xff0c;然后又使用了数据文件管理了消息。 那么&#xff0c;这里就创建一个类&#xff0c;讲之前的两个部分整合起来&#xff0c;对上层提供统一的一套接口&#xff0c;表示硬盘上存储的所有的类的信息。 /* * 用这个类来管理…

C++笔记之enum class和emun的区别

C笔记之enum class和emun的区别 code review! 代码,使用 enum class 的示例&#xff1a; #include <iostream>enum class Month { January, February, March, April, May, June, July, August, September, October, November, December };int main() {Month currentM…

龙迅LT8711H是Type-C/DP1.2转HDMI1.4芯片 -现货来了

1.概述 LT8711H是一款高性能Type-C / DP1.2至HDMI1.4转换器&#xff0c;旨在将USB Type-C源或DP1.2源连接至HDMI1.4接收器。 LT8711H集成了符合DP1.2的接收器和符合HDMI1.4的发送器。此外&#xff0c;还包括两个CC控制器&#xff0c;用于CC通信以实现DP Alt Mode和功率传输功…

Frida 编译(去特征)

Frida 编译&#xff08;去特征&#xff09; 编译最新版server编译往期版server更改特征使用定制库 hluwa本文引用&#xff1a; 本文环境&#xff1a; kali-linux-xfce 编译最新版server 第一步&#xff1a; 下载frida git clone --recurse-submodules https://github.com/fri…

Redis键值设计

1.1、优雅的key结构 Redis的Key虽然可以自定义&#xff0c;但最好遵循下面的几个最佳实践约定&#xff1a; 遵循基本格式&#xff1a;[业务名称]:[数据名]:[id]长度不超过44字节不包含特殊字符 例如&#xff1a;我们的登录业务&#xff0c;保存用户信息&#xff0c;其key可以…

模型训练技术指南

目录 引言 1. 模型训练的重要性 2. 数据预处理 3. 特征工程 4. 模型选择与评估 5. 参数调优 6. 模型集成 7. 过拟合与欠拟合 8. 模型保存与加载 9. 分布式训练与加速 10. 最佳实践与常见问题 引言 模型训练是机器学习领域中至关重要的一步&#xff0c;它决定了模型的…

处理该文件没有与之关联的应用来执行该操作,若已经安装应用,请在“默认应用设置”页面中创建关联

一、晚上在睡觉前接到一个删除了注册表导致的错误消息 二、解决方法一&#xff1a; 桌面新建 txt&#xff0c;把下面的代码复制粘贴到 txt 文件&#xff0c;然后重命名为1.bat&#xff0c;右键以管理员身份运行。 taskkill /f /im explorer.exe reg add "HKEY_LOCAL_MA…

【数据结构与算法】二叉排序树(BST)

二叉排序树&#xff08;BST&#xff09; 需求&#xff1a; 给你一个数列{7,3,10,12,5,1,9}&#xff0c;要求能够高效的完成对数据的查询和添加。 解决方案分析 使用数组 数组未排序&#xff0c;优点&#xff1a;直接在数组尾添加&#xff0c;速度快。缺点&#xff1a;查找速…

了解华为(H3C)网络设备和OSI模型基本概念

目录 一&#xff0c;认识华为 1.华为发展史 2.华为网络设备介绍 3.VRP概述 二&#xff0c;OSI七层模型 1.七层模型详细表格 2.各层的作用 3.数据在各层之间的传递过程 4.OSI四层网络模型 一&#xff0c;认识华为 官网&#xff1a;https://www.huawei.com/cn/ 1.华为发…

记录一个CMD命令异常 文件名、目录名或卷标语法不正确。

由git clone下来导致缺少符号 使用文档格式转换-转为windows-CR LF即可。 当前测试的命令内容 >cs 文件名、目录名或卷标语法不正确。 ho 不是内部或外部命令&#xff0c;也不是可运行的程序 或批处理文件。 系统默认的nodepad好像不能转换&#xff0c;直接新建一个文件&am…

【GTest学习】

1. GTest简介&#xff1a; GTest 就是 Google Test, 它是一个免费开源的测试框架, 用于编写测试用 C语言编写的程序(C 程序也能用, 但是需要用 C编译器编译)。gtest的官方网站是&#xff1a;http://code.google.com/p/googletest/ 2.GTest下载与环境搭建&#xff1a; GTest 下…

【雕爷学编程】Arduino动手做(195)---HT16k33 矩阵 8*8点阵屏模块4

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…