前言:
? ? ? ? 我們在開發(fā)一些小游戲的時(shí)候,不可能將所有的數(shù)據(jù)都上傳到服務(wù)器里去儲存,有很多數(shù)據(jù)是需要儲存到用戶本地的。比如一些簡單的用戶設(shè)置,一些只需要打開一次的用戶提示記錄等等。當(dāng)所需儲存的數(shù)據(jù)比較少的時(shí)候,我們可以直接用PlayerPrefs.SetString直接來儲存,但是這種方式每變化一次就需要執(zhí)行一次邏輯寫一行代碼,而且儲存的東西稍微多一點(diǎn)之后key就多了,對自己,對多人協(xié)同開發(fā)都是很麻煩的一件事。因此我們引入一套用戶的儲存類去儲存用戶數(shù)據(jù),將用戶的數(shù)據(jù)通過序列化的方式以json的格式儲存在用戶本地。接下來就是正文,我們將詳細(xì)介紹。
正文:
? ? ? ? 首先我們創(chuàng)建三個腳本:
????????DBManager(繼承自Unity的MonoBehaviour類,主要用于儲存因?yàn)樾枰玫経nity的生命周期函數(shù))
? ? ? ? DBUser(用戶儲存的主類,包括創(chuàng)建、讀取、儲存等方法)
? ? ? ? UserData(用于儲存用戶數(shù)據(jù)的結(jié)構(gòu)體,我們就是通過序列化這個類來儲存數(shù)據(jù))
第一步:先編寫一些DBUser的邏輯,上代碼:
public class DB_User
{
#region 實(shí)例Inst
private static DB_User _inst;
public static DB_User Inst
{
get { return _inst; }
private set { _inst = value; }
}
#endregion
private string savePath = string.Empty;
public DBManager dbManager;
//構(gòu)造函數(shù)
public DB_User()
{
_inst = this;
InitDB();
dbManager = new GameObject("DB").AddComponent<DBManager>();
}
private void InitDB()
{
CreateDBForder();
}
private void CreateDBForder()
{
string localPath = $"file://{Application.persistentDataPath}";
savePath = localPath + "/gameDB/";
try
{
if (Directory.Exists(savePath) == false)
{
Directory.CreateDirectory(savePath);
}
}
catch { }
}
}
????????這里主要就是完成DB的初始化問題,包括創(chuàng)建儲存的文件路徑,以及實(shí)例出DBManager。我們需要在游戲啟動時(shí)在適當(dāng)?shù)臅r(shí)候?qū)嵗鯠BUser即可。
private void Start()
{
new DBUser();
}
? ? ? ? 第二部:完成我們的UserData類。直接上代碼:
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UserData
{
public static string type = "userdata";
[NonSerialized]
public bool save = false;
#region 實(shí)例Inst
private static UserData _inst;
public static UserData Inst
{
get { return _inst; }
set { _inst = value; }
}
#endregion
#region 一些方法
public void InitUserData()
{
//TODO : 執(zhí)行一些新用戶需要執(zhí)行的方法
}
public string ToJson()
{
string str = string.Empty;
str = JsonConvert.SerializeObject(this, Formatting.None);
return str;
}
public UserData() { }
#endregion
private int _glod = 2000;
//******************************************************************************//
//******** 注意:增加字段,一定要【設(shè)默認(rèn)值】且數(shù)組【不能賦值】 **********//
//******** 增加字段,private, 不要直接增加public **********//
//******** 按照當(dāng)前的標(biāo)準(zhǔn)處理.否則可能無法存儲 **********//
//******************************************************************************//
//用戶的金幣數(shù)量
public int glod { get { return _glod; } set { _glod = value; save = true; } }
}
????????稍微解釋下:
????????string type這個變量主要是區(qū)分儲存的類型的,這里是"userdata"主要就是本地儲存用戶數(shù)據(jù)的,將來可能還有數(shù)據(jù)庫儲存的類型,這里就不展開說了,本文只介紹本地儲存。覺著沒用的把它刪了就行,其他腳本里用到相關(guān)類型的一起改一下就好,覺得麻煩的就留著也沒有什么影響。
????????至于這個bool save這個變量主要是控制是否需要儲存的,我們每次修改值也就是Set的時(shí)候?qū)ave設(shè)為true,這樣在每次保存數(shù)據(jù)的時(shí)候如果沒有值的改變我們就不需要儲存數(shù)據(jù),這是提升性能的一個小技巧。
? ? ? ? ToJson這個方法就是將這個類序列化,返回一個字符串,這里我用的是Newtonsoft.Json。大家自己在github上找吧,我這里就不貼了。
? ? ? ? 我們這里不僅可儲存int、string、bool等基礎(chǔ)類型,也可以儲存List、Dictionary等數(shù)組、字典。也可以自己創(chuàng)建結(jié)構(gòu)體去儲存。可以說擴(kuò)展性非常的強(qiáng)。
? ? ? ? 第三部:有了我們的數(shù)據(jù)儲存類,就繼續(xù)完成我們的DBUser的讀取與儲存邏輯:
public class DB_User
{
#region 實(shí)例Inst
private static DB_User _inst;
public static DB_User Inst
{
get { return _inst; }
private set { _inst = value; }
}
#endregion
private const string PLAYKEY = "db_";
private string savePath = string.Empty;
public DBManager dbManager;
public DB_User()
{
_inst = this;
InitDB();
dbManager = new GameObject("DB").AddComponent<DBManager>();
}
public void SaveUser()
{
string queryModel = UserData.Inst.ToJson();
Save(queryModel, UserData.type);
}
private void InitDB()
{
CreateDBForder();
InitUserdata();
}
private void CreateDBForder()
{
string localPath = $"file://{Application.persistentDataPath}";
savePath = localPath + "/gameDB/";
try
{
if (Directory.Exists(savePath) == false)
{
Directory.CreateDirectory(savePath);
}
}
catch { }
}
private void InitUserdata()
{
string queryModel = Read(UserData.type);
Debug.Log("UserData : " + queryModel);
if (!string.IsNullOrEmpty(queryModel))
{
UserData.Inst = JsonConvert.DeserializeObject<UserData>(queryModel);
}
else
{
// 無數(shù)據(jù)就創(chuàng)建新用戶
UserData.Inst = new UserData();
UserData.Inst.InitUserData();
}
}
private string Read(string type)
{
string data = string.Empty;
string name = PLAYKEY + type + ".dat";
string filename = string.Format("{0}/{1}", savePath, name);
if (FileExists(filename))
{
try
{
data = StreamReader(filename);
}
catch
{
Debug.LogError("存檔文件失敗 : " + filename);
}
}
return data;
}
private void Save(string data, string type)
{
string name = PLAYKEY + type + ".dat";
try
{
string filename = string.Format("{0}/{1}", savePath, name);
StreamWriter(filename, data);
}
catch
{
Debug.LogError("存檔文件保存失?。? + name);
}
}
#region Common
/// <summary>
/// 判斷文件是否存在
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private bool FileExists(string path)
{
path = ReplaceFileStart(path);
return System.IO.File.Exists(path);
}
/// <summary>
/// 替換FILE
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private string ReplaceFileStart(string path)
{
if (path.StartsWith("file://"))
{
path = path.Replace("file://", string.Empty);
}
return path;
}
/// <summary>
/// 讀取文件
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private string StreamReader(string path)
{
path = ReplaceFileStart(path);
if (FileExists(path))
{
try
{
System.IO.StreamReader sr = new System.IO.StreamReader(path);
string jsonStr = sr.ReadToEnd();
sr.Close();
return jsonStr;
}
catch
{
Debug.LogError("讀取文件失敗 : " + path);
}
}
return string.Empty;
}
/// <summary>
/// 寫入儲存文件
/// </summary>
/// <param name="path"></param>
/// <param name="data"></param>
private void StreamWriter(string path, string data)
{
path = ReplaceFileStart(path);
try
{
string forder = GetFileDirectory(path);
bool exists = System.IO.Directory.Exists(forder);
if (!exists)
{
System.IO.Directory.CreateDirectory(forder);
}
System.IO.StreamWriter sw = new System.IO.StreamWriter(path);
sw.Write(data);
//關(guān)閉StreamWriter
sw.Close();
}
catch (System.Exception ee)
{
Debug.Log("文件寫入失敗:" + path + " Error:" + ee.Message);
}
}
/// <summary>
/// 替換格式
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private string GetFileDirectory(string path)
{
path = path.Replace("\\", "/");
path = ReplaceFileStart(path);
return System.IO.Path.GetDirectoryName(path);
}
#endregion
}
(數(shù)據(jù)加密這里我就不展開說了,這里只介紹儲存方法)?
? ? ? ? 最后就是處理DBManager了?:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DBManager : MonoBehaviour
{
private float saveTimeout = 0;
/// <summary>
/// 用戶數(shù)據(jù)自動儲存時(shí)間
/// </summary>
public const float AUTOSAVETIME = 60f;
private void Start()
{
DontDestroyOnLoad(this);
}
private void Update()
{
AutoSave();
}
private void OnApplicationFocus(bool focus)
{
if (!focus)
{
SaveData();
}
}
private void SaveData()
{
if (UserData.Inst == null || DB_User.Inst == null) return;
if (UserData.Inst.save)
{
DB_User.Inst.SaveUser();
UserData.Inst.save = false;
}
}
private void AutoSave()
{
if (Time.time > saveTimeout + AUTOSAVETIME)
{
saveTimeout = Time.time;
SaveData();
}
}
}
????????這里就是每隔60s對用戶數(shù)據(jù)進(jìn)行一次本地的寫入儲存,如果用戶有脫離游戲焦點(diǎn)的行為是強(qiáng)制儲存一次。
結(jié)尾:
? ? ? ? 如何使用我們這個數(shù)據(jù)儲存模塊呢?
? ? ? ? 在正確的初始化之后,我們直接調(diào)用UserData就可以了。
UserData.Inst.glod = 100;
? ? ? ? 再次進(jìn)入游戲之后就可看到在控臺輸出一個json:文章來源:http://www.zghlxwxcb.cn/news/detail-413514.html
{
"glod": 96010
}
? ? ? ? 以上就是一個在本地進(jìn)行用戶數(shù)據(jù)儲存的一個模塊,歡迎大家一起討論。文章來源地址http://www.zghlxwxcb.cn/news/detail-413514.html
到了這里,關(guān)于我的框架-Unity3d中的用戶數(shù)據(jù)儲存模塊UserDB的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!