赞
踩
对于背包系统来说,我们首先需要实现几个关键的功能:
1.物品数据的持久化存储
2.对于物品的清晰显示
3.对于物品的便捷管理,能够增加删除物品
4.如何在场景中拾取物品
要实现物品数据的持久存储是背包系统所必须的,你也不想玩家再次打开游戏时发现自己的东西消失不见吧。
在UNITY中,想要持久存储数据有以下几种方式:
1.PlayerPrefs: Unity自带的一种简单的键值存储系统。
2.ScriptableObject: Unity中最灵活的数据管理工具。
3.JSON: 轻量级的数据交换格式。
4.XML:一种可扩展标记语言。
5.数据库:存储大量数据时使用的一种方法。
PlayerPrefs 不太适合存储大量数据,故不使用。
ScriptableObject 虽然能够持久化存储但是只能够在编辑模式当中,打包后其值在每次启动时都会还原成初始值,故不使用。
最终决定采用数据库来存储数据,学习下新内容。
这里为了方便我选择了Navicat Premium,可以免费试用14天,对于暂时的使用来说已经足够,我们只在开始的时候需要软件来查看数据
在下载好软件之后,使用软件新建一个db文件,选择Sqlite3
我将文件放置在了 Assets\StreamingAssets\SqLite\ 之中
在开始写代码之前我们需要向UNITY中导入以下三个dll文件
在Unity的Editor安装目录下“ Editor\Data\MonoBleedingEdge\lib\mono\unityjit-win32\Mono.Data.Sqlite.dll”
在Unity的Editor安装目录下“ Editor\Data\MonoBleedingEdge\lib\mono\2.0System.Data.dll”
在Sqlite的官网下载对应的版本即可“ https://www.sqlite.org/download.html ”
注意,如若Mono.Data.Sqlite.dll与UNITY版本不符合会报错Loading assembly failed “Assets/Plugins/Mono.Data.Sqlite.dll,此文件在mono文件夹中有很多个,请更换合适的版本。
实现对于Sqlite的更新,插入,删除,查找
- /// <summary>
- /// 数据库连接
- /// </summary>
- private SqliteConnection SqlConnection;
- /// <summary>
- /// 数据库命令
- /// </summary>
- private SqliteCommand SqlCommand;
- /// <summary>
- /// 数据库读取
- /// </summary>
- private SqliteDataReader SqlDataReader;
- /// <summary>
- /// 数据库路径
- /// </summary>
- private string SqlitePath = "URI=file:" + Application.streamingAssetsPath + "/SqLite/GameDataSQLite.db";
-
- private Hashtable dataHashTable = new Hashtable();
要注意数据库路径需要加上文件的后缀名,笔者在这里耽搁了些时间。
- /// <summary>
- /// 建立数据库连接
- /// </summary>
- public void SqlDataLink()
- {
- try
- {
- SqlConnection = new SqliteConnection(SqlitePath);
- SqlConnection.Open();
- SqlCommand = SqlConnection.CreateCommand();
- }
- catch (System.Exception e)
- {
- #if UNITY_EDITOR
- Debug.Log(e.ToString());
- #endif
- }
- }
在这里创建了一个名为"ItemSys "的表,其中包含两个字段:id、number。
对于物品的设定信息并没有放进去,我将物品设定信息存储在ScriptableObject中,使用时只需要依据ID进行读取就可以了(读取CSV文件并存放)
- public void SqlCreatTable()
- {
- //创建了一个名为"ItemSys "的表,其中包含两个字段:id、number。
- //创建背包表
- SqlCommand.CommandText = "CREATE TABLE IF NOT EXISTS ItemSys (id TEXT, number INTEGER)";
- SqlCommand.ExecuteNonQuery();
- }
- public void SqlInsertItemData(string id, int number)
- {
- SqlCommand.CommandText = "INSERT INTO ItemSys (id, number) VALUES (@id, @number)";
- SqlCommand.Parameters.AddWithValue("@id", id);
- SqlCommand.Parameters.AddWithValue("@number", number);
- }
- public void SqlClose()
- {
- if (SqlCommand != null)
- {
- SqlCommand.Dispose();
- SqlCommand = null;
- }
-
- if (SqlDataReader != null)
- {
- SqlDataReader.Close();
- SqlDataReader = null;
- }
-
- if (SqlConnection != null)
- {
- SqlConnection.Close();
- SqlConnection = null;
- }
- }
新建一个SqLiteManager文件,把两个文件都挂载到空物体上
- using System.Text;
- using UnityEngine;
- using static Unity.VisualScripting.Dependencies.Sqlite.SQLite3;
-
- public class SqLiteManager : MonoBehaviour
- {
- private void Start()
- {
- SqLite sqlite = gameObject.GetComponent<SqLite>();
- sqlite.SqlDataLink();
- sqlite.SqlCreatTable();
- sqlite.SqlInsertItemData("wp0001",12);
- sqlite.SqlClose();
-
- }
- }
运行一下代码,我们打开Navicat Premium,再次选择新建连接,类型选择现有数据库文件,用户名密码留空。
注意不要直接打开之前未移动的文件,我们更改的是移动到UNITY中的文件。
打开之后我们会发现数据库中成功新建了一张表,同时也成功写入了指定数据。
趁热打铁,完成剩余的部分
- /// <summary>
- ///
- /// </summary>
- /// <param name="tableName">表名字</param>
- /// <param name="_KEY">关键值1</param>
- /// <param name="key">关键值2</param>
- public void SqlDelete(string tableName, string _KEY, string key)
- {
- // DELETE FROM table_name WHERE some_column = some_value;
- StringBuilder stringBuilder =new StringBuilder();
- stringBuilder.Append("delete from ");
- stringBuilder.Append(tableName);
- stringBuilder.Append(" where ");
- stringBuilder.Append(_KEY);
- stringBuilder.Append(" = '");
- stringBuilder.Append(key);
- stringBuilder.Append("'");
- SqlCommand.CommandText= stringBuilder.ToString();
- SqlCommand.ExecuteNonQuery();
- }
SQLite 的 SELECT 语句的基本语法如下:
SELECT column1, column2, columnN FROM table_name;
在这里,column1, column2...是表的字段,他们的值即是要获取的。如果想获取所有可用的字段,那么可以使用下面的语法:
SELECT * FROM table_name;
- /// <summary>
- /// 查找
- /// </summary>
- /// <param name="key"></param>
- /// <returns></returns>
- public bool SQL_Select(string key, string tableName)
- {
- StringBuilder stringBuilder = new StringBuilder();
- stringBuilder.Append("select ");
- stringBuilder.Append(key);
- stringBuilder.Append(" from ");
- stringBuilder.Append(tableName);
- try
- {
- SqlCommand.CommandText = stringBuilder.ToString();
- SqlDataReader = SqlCommand.ExecuteReader();
- if (SqlDataReader != null)
- {
- while (SqlDataReader.Read())
- {
- var id = SqlDataReader.GetString(0);
- var number = SqlDataReader.GetInt32(1);
-
- Debug.LogFormat("id: {0}, number: {1}", id, number);
- }
- return true;
- }
- }
- catch (System.Exception e)
- {
- Debug.LogError(e.ToString());
- }
- return false;
- }
结果如图
UPDATE 查询的基本语法如下:
- UPDATE table_name
- SET column1 = value1, column2 = value2...., columnN = valueN
- WHERE [condition];
- /// <summary>
- /// 更新表中数据
- /// </summary>
- /// <param name="tableName">表名字</param>
- /// <param name="_VALUE_STRING">目标列名字</param>
- /// <param name="value">新的值</param>
- /// <param name="_KEY">目标行名字</param>
- /// <param name="key">目标行的值</param>
- public void SqlUpdata(string tableName, string _VALUE_STRING, int value, string _KEY, string key)
- {
- // UPDATE table_name SET column1 = value1, column2 = value2,... WHERE some_column = some_value;
- StringBuilder stringBuilder = new StringBuilder();
- stringBuilder.Append("update ");
- stringBuilder.Append(tableName);
- stringBuilder.Append(" set ");
- stringBuilder.Append(_VALUE_STRING);
- stringBuilder.Append("=");
- stringBuilder.Append(value);
- stringBuilder.Append(" where ");
- stringBuilder.Append(_KEY);
- stringBuilder.Append("= '");
- stringBuilder.Append(key);
- stringBuilder.Append("'; ");
- SqlCommand.CommandText = stringBuilder.ToString();
- #if UNITY_EDITOR
- SqlDataReader = SqlCommand.ExecuteReader();
- Debug.Log(SqlDataReader);
- #endif
- }
对此代码的使用范例:
现在建立有表如图,要将wp0034所在行的number值更变为5。
运行以下代码:
- public class SqLiteManager : MonoBehaviour
- {
- private void Start()
- {
- SqLite sqlite = gameObject.GetComponent<SqLite>();
- sqlite.SqlDataLink();
- sqlite.SqlUpdata("ItemSys", "number", 5, "id", "wp0034");
- sqlite.SqlClose();
- }
- }
再次打开软件查看,数据被成功更改,结果如下:
至此,SqLite的基本代码书写完毕,但是使用过于繁琐,不能满足我们的实际需求。
接下来将基于这些代码进行再封装,正式开始背包系统的代码
在真正使用当中,我们并不直接对数据库进行读写,而是在游戏加载时将数据库数据搬移到HashTable当中,以加快数据的查找速度。
在Scripts文件夹中新建一个脚本文件继承SqLite,定义一些变量
- public class ItemSystem : SqLite
- {
- private Hashtable dataHashTable = new Hashtable();
- }
注意,每次读取数据之后要关闭DataReader,不然会报错
- private void LoadItemData()
- {
- SqlDataLink();
- if (SQL_Select("*", "ItemSys") == false)
- {
- //没有数据则返回
- //建立表格放在新建存档的位置,不做多存档的话可以就在这里放创建表格
- return;
- }
- SqlDataReader.Close();
- SqlCommand.CommandText = "select * from ItemSys";
- SqlDataReader = SqlCommand.ExecuteReader();
- while (SqlDataReader.Read())
- {
- string key = SqlDataReader.GetString(0);
- dataHashTable[key] = SqlDataReader.GetInt32(1);
- }
- SqlDataReader.Close();
- SqlClose();
- //查看数据是否成功导入
- Debug.Log(dataHashTable["wp0001"]);
- }
运行之后能看见数据成功导入,数据正常显示了
- /// <summary>
- /// 背包添加物品
- /// </summary>
- /// <param name="id">物品id</param>
- /// <param name="num">添加的数量</param>
- public void ItemSys_Add(string id,int num)
- {
- //待添加判断条件,是否小于此物品的最大堆叠数量
- dataHashTable[id] = (int)dataHashTable[id] + num;
- }
-
-
- /// <summary>
- /// 背包删除物品
- /// </summary>
- /// <param name="id">物品id</param>
- /// <param name="num">删除的数量</param>
- /// <returns>是否成功,数量不足则不成功</returns>
- public bool ItemSys_Del(string id, int num)
- {
- int temp = (int)dataHashTable[id] - num;
- if (temp > 0)
- {
- dataHashTable[id] = temp;
- return true;
- }
- else if (temp == 0)
- {
- //将物品移除
- dataHashTable.Remove(id);
- return true;
- }
- return false;
- }
之前的增加删除都是基于哈希表的,我们还需要将变化同步到数据库当中。
由于我的数据量较少,采用完全备份,数据量大可以差异备份,这个我后面再写
- /// <summary>
- /// 同步数据到数据库
- /// </summary>
- void Synchronizedata()
- {
- SqlDataLink();
- foreach (string key in dataHashTable.Keys)//遍历key
- {
- SqlInsertItemData(key, (int)dataHashTable[key]);
- }
- SqlClose();
- }
在显示信息之前我们先制作一下GUI,使用unity自带的ui组件可以制作一个简单的自适应滚动的物品表。
右键选择UI,新建一个滚动视图,命名为“ItemSysUI”
制作一个物品显示框的IyemSlot预制体(这里我从uintry商店找了个),放在ItemSysUI的Content下
为Content添加Vertical Layout Group组件
测试显示效果如下:
UI准备完毕后开始编写代码:
由于我在数据库中只存放了物品ID和数量,在生成界面时还需要根据ID调用对应的信息。这里部分代码阅读起来可能比较困难,但其实就是从数组中取数据,这样理解就简单很多了。
- /// <summary>
- /// 显示背包系统GUI
- /// </summary>
- /// <param name="dis_status">是否显示,true or false</param>
- public void ItemSys_GUI(bool dis_status)
- {
- //注意在初始化时是否加载GUI,这里只是启用,记得要写
- GameObject gui =GameObject.Find("ItemSysUI");
- GameObject ItemContent = GameObject.Find("ItemContent");
- GameObject itemSlot = Resources.Load<GameObject>("UI/Prefabs/ItemSlot");
- ItemManager itemData = Resources.Load<ItemManager>("DataAssets/Item");
- CreatItemHashTable();
- gui.SetActive(dis_status);
- if (!dis_status)
- return;
- foreach (string key in dataHashTable.Keys)//遍历key
- {
- //为每个物品生成显示框
- GameObject slot = Instantiate(itemSlot, transform.position, Quaternion.identity);
- slot.transform.SetParent(ItemContent.transform);
-
- slot.transform.Find("Text/Name").GetComponent<Text>().text = itemData.dataArray[(int)array_id[key]].itemName;
- slot.transform.Find("Text/Description").GetComponent<Text>().text = itemData.dataArray[(int)array_id[key]].itemDescription;
- slot.transform.Find("Icon/Stack").GetComponent<Text>().text = dataHashTable[key].ToString();
- }
- }
测试能够正常显示数据库中的数据及根据ID得到的数据,因为至少测试我并没有添加太多的信息,后续还可以指定图片,调用方法等等。
一键整理(自动化排布)
物品分类
拾取物品添加到背包中
转轮选取工具
待续...
Unity 报错Loading assembly failed “Assets/Plugins/Mono.Data.Sqlite.dll“
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。