下载地址:
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);
}
}
}
}