当前位置:   article > 正文

基于SqLite存储的背包系统+场景内拾取物体功能全流程_sqlitemanager unity

sqlitemanager unity

零、功能分析

对于背包系统来说,我们首先需要实现几个关键的功能:

        1.物品数据的持久化存储

        2.对于物品的清晰显示

        3.对于物品的便捷管理,能够增加删除物品

        4.如何在场景中拾取物品

壹、基于SqLite的持久化存储

要实现物品数据的持久存储是背包系统所必须的,你也不想玩家再次打开游戏时发现自己的东西消失不见吧。

UNITY中,想要持久存储数据有以下几种方式:

1.PlayerPrefs: Unity自带的一种简单的键值存储系统。

2.ScriptableObject: Unity中最灵活的数据管理工具。

3.JSON: 轻量级的数据交换格式。

4.XML:一种可扩展标记语言。

5.数据库:存储大量数据时使用的一种方法。

PlayerPrefs 不太适合存储大量数据,故不使用。

        ScriptableObject 虽然能够持久化存储但是只能够在编辑模式当中,打包后其值在每次启动时都会还原成初始值,故不使用。

        最终决定采用数据库来存储数据,学习下新内容。

1.下载SqLite查看软件

        这里为了方便我选择了Navicat Premium,可以免费试用14天,对于暂时的使用来说已经足够,我们只在开始的时候需要软件来查看数据

新建db文件

在下载好软件之后,使用软件新建一个db文件,选择Sqlite3

f6c60c12b3274b3cb886320fb14f0a3d.png

转移db文件到unity中

        我将文件放置在了 Assets\StreamingAssets\SqLite\ 之中

2.导入DLL文件

在开始写代码之前我们需要向UNITY中导入以下三个dll文件

Mono.Data.Sqlite.dll

在Unity的Editor安装目录下“ Editor\Data\MonoBleedingEdge\lib\mono\unityjit-win32\Mono.Data.Sqlite.dll

System.Data.dll

在Unity的Editor安装目录下“ Editor\Data\MonoBleedingEdge\lib\mono\2.0System.Data.dll

Sqlite3.dll

在Sqlite的官网下载对应的版本即可“ https://www.sqlite.org/download.html ”

注意,如若Mono.Data.Sqlite.dll与UNITY版本不符合会报错Loading assembly failed “Assets/Plugins/Mono.Data.Sqlite.dll,此文件在mono文件夹中有很多个,请更换合适的版本。

3.编写SqLite代码

实现对于Sqlite的更新,插入,删除,查找

定义关键变量

  1. /// <summary>
  2. /// 数据库连接
  3. /// </summary>
  4. private SqliteConnection SqlConnection;
  5. /// <summary>
  6. /// 数据库命令
  7. /// </summary>
  8. private SqliteCommand SqlCommand;
  9. /// <summary>
  10. /// 数据库读取
  11. /// </summary>
  12. private SqliteDataReader SqlDataReader;
  13. /// <summary>
  14. /// 数据库路径
  15. /// </summary>
  16. private string SqlitePath = "URI=file:" + Application.streamingAssetsPath + "/SqLite/GameDataSQLite.db";
  17. private Hashtable dataHashTable = new Hashtable();

要注意数据库路径需要加上文件的后缀名,笔者在这里耽搁了些时间。

初始化代码

  1. /// <summary>
  2. /// 建立数据库连接
  3. /// </summary>
  4. public void SqlDataLink()
  5. {
  6. try
  7. {
  8. SqlConnection = new SqliteConnection(SqlitePath);
  9. SqlConnection.Open();
  10. SqlCommand = SqlConnection.CreateCommand();
  11. }
  12. catch (System.Exception e)
  13. {
  14. #if UNITY_EDITOR
  15. Debug.Log(e.ToString());
  16. #endif
  17. }
  18. }

创建一张表 

在这里创建了一个名为"ItemSys "的表,其中包含两个字段:id、number。

对于物品的设定信息并没有放进去,我将物品设定信息存储在ScriptableObject中,使用时只需要依据ID进行读取就可以了(读取CSV文件并存放

  1. public void SqlCreatTable()
  2. {
  3. //创建了一个名为"ItemSys "的表,其中包含两个字段:id、number。
  4. //创建背包表
  5. SqlCommand.CommandText = "CREATE TABLE IF NOT EXISTS ItemSys (id TEXT, number INTEGER)";
  6. SqlCommand.ExecuteNonQuery();
  7. }

向表中插入数据

  1. public void SqlInsertItemData(string id, int number)
  2. {
  3. SqlCommand.CommandText = "INSERT INTO ItemSys (id, number) VALUES (@id, @number)";
  4. SqlCommand.Parameters.AddWithValue("@id", id);
  5. SqlCommand.Parameters.AddWithValue("@number", number);
  6. }

关闭数据库

  1. public void SqlClose()
  2. {
  3. if (SqlCommand != null)
  4. {
  5. SqlCommand.Dispose();
  6. SqlCommand = null;
  7. }
  8. if (SqlDataReader != null)
  9. {
  10. SqlDataReader.Close();
  11. SqlDataReader = null;
  12. }
  13. if (SqlConnection != null)
  14. {
  15. SqlConnection.Close();
  16. SqlConnection = null;
  17. }
  18. }

测试代码

新建一个SqLiteManager文件,把两个文件都挂载到空物体上

  1. using System.Text;
  2. using UnityEngine;
  3. using static Unity.VisualScripting.Dependencies.Sqlite.SQLite3;
  4. public class SqLiteManager : MonoBehaviour
  5. {
  6. private void Start()
  7. {
  8. SqLite sqlite = gameObject.GetComponent<SqLite>();
  9. sqlite.SqlDataLink();
  10. sqlite.SqlCreatTable();
  11. sqlite.SqlInsertItemData("wp0001",12);
  12. sqlite.SqlClose();
  13. }
  14. }

运行一下代码,我们打开Navicat Premium,再次选择新建连接,类型选择现有数据库文件,用户名密码留空。

注意不要直接打开之前未移动的文件,我们更改的是移动到UNITY中的文件。

99b959f3377a4003bcd3a2e03ef9dac9.png

打开之后我们会发现数据库中成功新建了一张表,同时也成功写入了指定数据。

08397c1497484cbc9c0335b1fba951aa.png

478ecee020cc4254b0c8c3b4cf6dab71.png

删除表中数据

趁热打铁,完成剩余的部分

  1. /// <summary>
  2. ///
  3. /// </summary>
  4. /// <param name="tableName">表名字</param>
  5. /// <param name="_KEY">关键值1</param>
  6. /// <param name="key">关键值2</param>
  7. public void SqlDelete(string tableName, string _KEY, string key)
  8. {
  9. // DELETE FROM table_name WHERE some_column = some_value;
  10. StringBuilder stringBuilder =new StringBuilder();
  11. stringBuilder.Append("delete from ");
  12. stringBuilder.Append(tableName);
  13. stringBuilder.Append(" where ");
  14. stringBuilder.Append(_KEY);
  15. stringBuilder.Append(" = '");
  16. stringBuilder.Append(key);
  17. stringBuilder.Append("'");
  18. SqlCommand.CommandText= stringBuilder.ToString();
  19. SqlCommand.ExecuteNonQuery();
  20. }

 查找表中数据

SQLite 的 SELECT 语句的基本语法如下:

SELECT column1, column2, columnN FROM table_name;

在这里,column1, column2...是表的字段,他们的值即是要获取的。如果想获取所有可用的字段,那么可以使用下面的语法:

SELECT * FROM table_name;
  1. /// <summary>
  2. /// 查找
  3. /// </summary>
  4. /// <param name="key"></param>
  5. /// <returns></returns>
  6. public bool SQL_Select(string key, string tableName)
  7. {
  8. StringBuilder stringBuilder = new StringBuilder();
  9. stringBuilder.Append("select ");
  10. stringBuilder.Append(key);
  11. stringBuilder.Append(" from ");
  12. stringBuilder.Append(tableName);
  13. try
  14. {
  15. SqlCommand.CommandText = stringBuilder.ToString();
  16. SqlDataReader = SqlCommand.ExecuteReader();
  17. if (SqlDataReader != null)
  18. {
  19. while (SqlDataReader.Read())
  20. {
  21. var id = SqlDataReader.GetString(0);
  22. var number = SqlDataReader.GetInt32(1);
  23. Debug.LogFormat("id: {0}, number: {1}", id, number);
  24. }
  25. return true;
  26. }
  27. }
  28. catch (System.Exception e)
  29. {
  30. Debug.LogError(e.ToString());
  31. }
  32. return false;
  33. }

 结果如图

252a307197eb48fa8fe77a4a78316567.png

更新表中数据

UPDATE 查询的基本语法如下:

  1. UPDATE table_name
  2. SET column1 = value1, column2 = value2...., columnN = valueN
  3. WHERE [condition];
  1. /// <summary>
  2. /// 更新表中数据
  3. /// </summary>
  4. /// <param name="tableName">表名字</param>
  5. /// <param name="_VALUE_STRING">目标列名字</param>
  6. /// <param name="value">新的值</param>
  7. /// <param name="_KEY">目标行名字</param>
  8. /// <param name="key">目标行的值</param>
  9. public void SqlUpdata(string tableName, string _VALUE_STRING, int value, string _KEY, string key)
  10. {
  11. // UPDATE table_name SET column1 = value1, column2 = value2,... WHERE some_column = some_value;
  12. StringBuilder stringBuilder = new StringBuilder();
  13. stringBuilder.Append("update ");
  14. stringBuilder.Append(tableName);
  15. stringBuilder.Append(" set ");
  16. stringBuilder.Append(_VALUE_STRING);
  17. stringBuilder.Append("=");
  18. stringBuilder.Append(value);
  19. stringBuilder.Append(" where ");
  20. stringBuilder.Append(_KEY);
  21. stringBuilder.Append("= '");
  22. stringBuilder.Append(key);
  23. stringBuilder.Append("'; ");
  24. SqlCommand.CommandText = stringBuilder.ToString();
  25. #if UNITY_EDITOR
  26. SqlDataReader = SqlCommand.ExecuteReader();
  27. Debug.Log(SqlDataReader);
  28. #endif
  29. }

 对此代码的使用范例:

现在建立有表如图,要将wp0034所在行的number值更变为5。

b5b08c361e9f48d0bfa684057c05a2f3.png

运行以下代码:

  1. public class SqLiteManager : MonoBehaviour
  2. {
  3. private void Start()
  4. {
  5. SqLite sqlite = gameObject.GetComponent<SqLite>();
  6. sqlite.SqlDataLink();
  7. sqlite.SqlUpdata("ItemSys", "number", 5, "id", "wp0034");
  8. sqlite.SqlClose();
  9. }
  10. }

 再次打开软件查看,数据被成功更改,结果如下:

2157ecf92ac94d68a374fccdf16f6226.png

本段总结

至此,SqLite的基本代码书写完毕,但是使用过于繁琐,不能满足我们的实际需求。

接下来将基于这些代码进行再封装,正式开始背包系统的代码

贰、背包系统基本读写代码

在真正使用当中,我们并不直接对数据库进行读写,而是在游戏加载时将数据库数据搬移到HashTable当中,以加快数据的查找速度。

定义关键变量

在Scripts文件夹中新建一个脚本文件继承SqLite,定义一些变量

  1. public class ItemSystem : SqLite
  2. {
  3. private Hashtable dataHashTable = new Hashtable();
  4. }

 读取数据库数据到HashTable

  注意,每次读取数据之后要关闭DataReader,不然会报错

  1. private void LoadItemData()
  2. {
  3. SqlDataLink();
  4. if (SQL_Select("*", "ItemSys") == false)
  5. {
  6. //没有数据则返回
  7. //建立表格放在新建存档的位置,不做多存档的话可以就在这里放创建表格
  8. return;
  9. }
  10. SqlDataReader.Close();
  11. SqlCommand.CommandText = "select * from ItemSys";
  12. SqlDataReader = SqlCommand.ExecuteReader();
  13. while (SqlDataReader.Read())
  14. {
  15. string key = SqlDataReader.GetString(0);
  16. dataHashTable[key] = SqlDataReader.GetInt32(1);
  17. }
  18. SqlDataReader.Close();
  19. SqlClose();
  20. //查看数据是否成功导入
  21. Debug.Log(dataHashTable["wp0001"]);
  22. }

 运行之后能看见数据成功导入,数据正常显示了

221aea3fcce741869d1b6e30d4e69798.png

 向背包中加入或是删除物品

  1. /// <summary>
  2. /// 背包添加物品
  3. /// </summary>
  4. /// <param name="id">物品id</param>
  5. /// <param name="num">添加的数量</param>
  6. public void ItemSys_Add(string id,int num)
  7. {
  8. //待添加判断条件,是否小于此物品的最大堆叠数量
  9. dataHashTable[id] = (int)dataHashTable[id] + num;
  10. }
  11. /// <summary>
  12. /// 背包删除物品
  13. /// </summary>
  14. /// <param name="id">物品id</param>
  15. /// <param name="num">删除的数量</param>
  16. /// <returns>是否成功,数量不足则不成功</returns>
  17. public bool ItemSys_Del(string id, int num)
  18. {
  19. int temp = (int)dataHashTable[id] - num;
  20. if (temp > 0)
  21. {
  22. dataHashTable[id] = temp;
  23. return true;
  24. }
  25. else if (temp == 0)
  26. {
  27. //将物品移除
  28. dataHashTable.Remove(id);
  29. return true;
  30. }
  31. return false;
  32. }

同步数据到数据库

之前的增加删除都是基于哈希表的,我们还需要将变化同步到数据库当中。

由于我的数据量较少,采用完全备份,数据量大可以差异备份,这个我后面再写

  1. /// <summary>
  2. /// 同步数据到数据库
  3. /// </summary>
  4. void Synchronizedata()
  5. {
  6. SqlDataLink();
  7. foreach (string key in dataHashTable.Keys)//遍历key
  8. {
  9. SqlInsertItemData(key, (int)dataHashTable[key]);
  10. }
  11. SqlClose();
  12. }

显示物品信息

在显示信息之前我们先制作一下GUI,使用unity自带的ui组件可以制作一个简单的自适应滚动的物品表。

右键选择UI,新建一个滚动视图,命名为“ItemSysUI”

制作一个物品显示框的IyemSlot预制体(这里我从uintry商店找了个),放在ItemSysUI的Content下

2c1a04050af84000b3d127c4e0b8fec3.png

为Content添加Vertical Layout Group组件

434816b1262144219b2271c91015dcb7.png

测试显示效果如下:

81c7a4456fa14428b921f40e7dab18c3.png

UI准备完毕后开始编写代码:

由于我在数据库中只存放了物品ID和数量,在生成界面时还需要根据ID调用对应的信息。这里部分代码阅读起来可能比较困难,但其实就是从数组中取数据,这样理解就简单很多了。

  1. /// <summary>
  2. /// 显示背包系统GUI
  3. /// </summary>
  4. /// <param name="dis_status">是否显示,true or false</param>
  5. public void ItemSys_GUI(bool dis_status)
  6. {
  7. //注意在初始化时是否加载GUI,这里只是启用,记得要写
  8. GameObject gui =GameObject.Find("ItemSysUI");
  9. GameObject ItemContent = GameObject.Find("ItemContent");
  10. GameObject itemSlot = Resources.Load<GameObject>("UI/Prefabs/ItemSlot");
  11. ItemManager itemData = Resources.Load<ItemManager>("DataAssets/Item");
  12. CreatItemHashTable();
  13. gui.SetActive(dis_status);
  14. if (!dis_status)
  15. return;
  16. foreach (string key in dataHashTable.Keys)//遍历key
  17. {
  18. //为每个物品生成显示框
  19. GameObject slot = Instantiate(itemSlot, transform.position, Quaternion.identity);
  20. slot.transform.SetParent(ItemContent.transform);
  21. slot.transform.Find("Text/Name").GetComponent<Text>().text = itemData.dataArray[(int)array_id[key]].itemName;
  22. slot.transform.Find("Text/Description").GetComponent<Text>().text = itemData.dataArray[(int)array_id[key]].itemDescription;
  23. slot.transform.Find("Icon/Stack").GetComponent<Text>().text = dataHashTable[key].ToString();
  24. }
  25. }

测试能够正常显示数据库中的数据及根据ID得到的数据,因为至少测试我并没有添加太多的信息,后续还可以指定图片,调用方法等等。

c2709e1b47ba472fb83f1bf28c3a75cb.png

肆、额外功能

一键整理(自动化排布)

物品分类

拾取物品添加到背包中

转轮选取工具

待续...

 参考文章:

Unity存储游戏数据的几种方法_unity存储数据 

Unity数据存储Sqlite的使用

Unity 报错Loading assembly failed “Assets/Plugins/Mono.Data.Sqlite.dll“

SQLite 教程 

SQL SqlDataReader是否需要手动关闭和释放

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号