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

下载地址:

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

        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[分享]STM32G070 串口 乱码 解决方法

硬件 NUCLEO-G070RB 工具 cubemx 解决方法 7bit 改为 8bit printf 配置方法 添加头文件 #include <stdio.h> 添加重定向代码 #ifdef __GNUC__#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)#else#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)#endi…

网络安全(黑客)常用工具(附配套资料+工具安装包)

几十年来&#xff0c;攻击方、白帽和安全从业者的工具不断演进&#xff0c;成为网络安全长河中最具技术特色的灯塔&#xff0c;并在一定程度上左右着网络安全产业发展和演进的方向&#xff0c;成为不可或缺的关键要素之一。 话不多说&#xff0c;2022年全球白帽常用工具排行榜…

解决Windows:Call to undefined function exif_imagetype()

很明显,是php安装时没有打开某些扩展,以致不能执行exif_imagetype()这个方法,因此需要打开。 网上很多人说需要打开下面这两个扩展: extension=php_exif.dll extension=php_mbstring.dll 但只说对了一半,我一开始也按照网上文章说的打开这两个扩展,但是还是同样错误。…

Leetcode-每日一题【剑指 Offer 14- II. 剪绳子 II】

题目 2、3、3的三段&#xff0c;此时得到的最大乘积是18。 答案需要取模 1e97&#xff08;1000000007&#xff09;&#xff0c;如计算初始结果为&#xff1a;1000000008&#xff0c;请返回 1。 示例 1&#xff1a; 输入: 2输出: 1解释: 2 1 1, 1 1 1 示例 2: 输入: 10输出…

Tensorflow2-初识

TensorFlow2是一个深度学习框架&#xff0c;可以理解为一个工具&#xff0c;有谷歌的全力支持&#xff0c;具有易用、灵活、可扩展、性能优越、良好的社区资源等优点。 1、环境的搭建 1.1 Anaconda3的安装 https://www.anaconda.com/ Python全家桶&#xff0c;包括Python环境和…

无涯教程-Perl - int函数

描述 此函数返回EXPR的整数元素,如果省略则返回$_。 int函数不进行舍入。如果需要将值四舍五入为整数,则应使用sprintf。 语法 以下是此函数的简单语法- int EXPRint返回值 此函数返回EXPR的整数部分。 例 以下是显示其基本用法的示例代码- #!/usr/bin/perl$int_valint…

[保研/考研机试] KY180 堆栈的使用 吉林大学复试上机题 C++实现

题目链接&#xff1a; 堆栈的使用_牛客题霸_牛客网 描述 堆栈是一种基本的数据结构。堆栈具有两种基本操作方式&#xff0c;push 和 pop。其中 push一个值会将其压入栈顶&#xff0c;而 pop 则会将栈顶的值弹出。现在我们就来验证一下堆栈的使用。 输入描述&#xff1a; 对于…

springboot项目get请求下划线转驼峰@JsonProperty注解失效问题

问题&#xff1a;解决sprigboot项目get请求中有下划线的入参参数&#xff0c;如&#xff1a;first_name&#xff0c;希望在项目中将下划线格式转成firstName&#xff0c;用JsonProperty注解发现失效问题 1.核查&#xff1a;JsonProperty注解对应包是否正确 正确包&#xff1a…

虹科新闻 | 虹科与Power-MI正式建立合作伙伴关系

近日&#xff0c;虹科与Power-MI正式建立合作伙伴关系&#xff0c;双方就工业预测性维护领域进行深入的交流与合作&#xff0c;未来将共同致力于为亚洲市场提供完整的、更高质量的预测性维护解决方案&#xff0c;解决亚洲客户的工业自动化挑战。 虹科与Power-MI都表示十分期待…

14-矩阵相乘及其运算法则

矩阵与向量的乘法 在这一篇文章中我们就将基于上一篇重新审视矩阵的这个视点来理解矩阵的乘法&#xff0c;那么在这一篇&#xff0c;我们主要来看一下矩阵和向量的乘法。这里这个线性方程组是上一小节给大家举的模拟的一个非常简单的小型经济系统的例子&#xff0c;我们可以把…

HTTP——十一、Web的攻击技术

HTTP 一、针对Web的攻击技术1、HTTP 不具备必要的安全功能2、在客户端即可篡改请求3、针对Web应用的攻击模式 二、因输出值转义不完全引发的安全漏洞1、跨站脚本攻击2、SQL 注入攻击3、OS命令注入攻击4、HTTP首部注入攻击5、邮件首部注入攻击6、目录遍历攻击7、远程文件包含漏洞…

树状结构数据,筛选指定数据

问题描述&#xff1a; 应用场景和需求&#xff1a;对一个树状结构的数据&#xff0c;进行CRUD 时&#xff0c;想筛选出 树状结构数据中存在变动的部分。 操作步骤 准备需要的数据&#xff1a; 1.先拿到 你原来的树状结构数据 2.再筛选出 需要保留的数据集合id&#xff0c;也…

Spring Cloud Gateway过滤器GlobalFilter详解

一、过滤器的场景 在springCloud架构中&#xff0c;网关是必不可少的组件&#xff0c;它用于服务路由的转发。对客户端进行屏蔽微服务的具体细节&#xff0c;客户端只需要和网关进行交互。所以网关顾名思义&#xff0c;就是网络的一个关卡。它就是一座城的城门守卫。所以这个守…

ElasticSearch:全文检索及倒排索引原理

1.从全文检索说起 首先介绍一下结构化与非结构化数据&#xff1a; 结构化数据将数据具有的特征事先以结构化的形式定义好&#xff0c;数据有固定的格式或有限的长度。典型的结构化数据就是传统关系型数据库的表结构&#xff0c;数据特征直接体现在表结构的字段上&#xff0c;…

内网隧道—HTTP\DNS\ICMP

本文仅限于安全研究和学习&#xff0c;用户承担因使用此工具而导致的所有法律和相关责任&#xff01; 作者不承担任何法律和相关责任&#xff01; HTTP隧道 Neo-reGeorg Neo-reGeorg 是一个旨在积极重构 reGeorg 的项目&#xff0c;目的是&#xff1a; 提高可用性&#xff0…

springBoot整合RabbitMq实现手动确认消息

如何保证消息的可靠性投递&#xff1f; 1.保证生产者向broke可靠性投递&#xff0c;开启ack投递成功确认&#xff0c;如果失败的话进行消息补偿 /*** author yueF_L* date 2023-08-10 01:32* ConfirmCallback&#xff1a;消息只要被 RabbitMQ broker 接收到就会触发confirm方…

tomcat7.exe 启动闪退解决

标题tomcat7.exe 启动闪退解决 双击tomcat7.exe启动&#xff0c;但是出现闪退问题&#xff0c;无法启动tomcat 解决&#xff1a; 1.解决 tomcat7.exe 启动闪退解决 第一步&#xff1a;双击打开tomcat7w.exe 文件 如果出现 “指定的服务未安装。 Unable to open the service ‘…

FFmpeg常见命令行(三):FFmpeg转码

前言 在Android音视频开发中&#xff0c;网上知识点过于零碎&#xff0c;自学起来难度非常大&#xff0c;不过音视频大牛Jhuster提出了《Android 音视频从入门到提高 - 任务列表》。本文是Android音视频任务列表的其中一个&#xff0c; 对应的要学习的内容是&#xff1a;如何使…

vue项目中Uncaught runtime errors:怎样关闭

原文链接&#xff1a; yvue项目中Uncaught runtime errors:怎样关闭_笑毅的博客-CSDN博客https://blog.csdn.net/qq_36877078/article/details/131175355是webpack-dev-server弄出来的 解决办法 在vue.config.js中添加如下配置 module.exports defineConfig({...devServer:…

php代码审计,php漏洞详解

文章目录 1、输入验证和输出显示2、命令注入(Command Injection)3、eval 注入(Eval Injection)4、跨网站脚本攻击(Cross Site Scripting, XSS)5、SQL 注入攻击(SQL injection)6、跨网站请求伪造攻击(Cross Site Request Forgeries, CSRF)7、Session 会话劫持(Session Hijacking…