• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

我的框架-Unity3d的用户数据储存模块UserDB

武飞扬头像
魂牵丶梦萦
帮助1

前言:

        我们在开发一些小游戏的时候,不可能将所有的数据都上传到服务器里去储存,有很多数据是需要储存到用户本地的。比如一些简单的用户设置,一些只需要打开一次的用户提示记录等等。当所需储存的数据比较少的时候,我们可以直接用PlayerPrefs.SetString直接来储存,但是这种方式每变化一次就需要执行一次逻辑写一行代码,而且储存的东西稍微多一点之后key就多了,对自己,对多人协同开发都是很麻烦的一件事。因此我们引入一套用户的储存类去储存用户数据,将用户的数据通过序列化的方式以json的格式储存在用户本地。接下来就是正文,我们将详细介绍。

正文:

        首先我们创建三个脚本:

        DBManager(继承自Unity的MonoBehaviour类,主要用于储存因为需要用到Unity的生命周期函数)

        DBUser(用户储存的主类,包括创建、读取、储存等方法)

        UserData(用于储存用户数据的结构体,我们就是通过序列化这个类来储存数据)

第一步:先编写一些DBUser的逻辑,上代码:

  1.  
    public class DB_User
  2.  
    {
  3.  
    #region 实例Inst
  4.  
    private static DB_User _inst;
  5.  
    public static DB_User Inst
  6.  
    {
  7.  
    get { return _inst; }
  8.  
    private set { _inst = value; }
  9.  
    }
  10.  
    #endregion
  11.  
     
  12.  
    private string savePath = string.Empty;
  13.  
     
  14.  
    public DBManager dbManager;
  15.  
     
  16.  
    //构造函数
  17.  
    public DB_User()
  18.  
    {
  19.  
    _inst = this;
  20.  
    InitDB();
  21.  
    dbManager = new GameObject("DB").AddComponent<DBManager>();
  22.  
    }
  23.  
     
  24.  
    private void InitDB()
  25.  
    {
  26.  
    CreateDBForder();
  27.  
    }
  28.  
     
  29.  
    private void CreateDBForder()
  30.  
    {
  31.  
    string localPath = $"file://{Application.persistentDataPath}";
  32.  
    savePath = localPath "/gameDB/";
  33.  
    try
  34.  
    {
  35.  
    if (Directory.Exists(savePath) == false)
  36.  
    {
  37.  
    Directory.CreateDirectory(savePath);
  38.  
    }
  39.  
    }
  40.  
    catch { }
  41.  
    }
  42.  
    }
学新通

        这里主要就是完成DB的初始化问题,包括创建储存的文件路径,以及实例出DBManager。我们需要在游戏启动时在适当的时候实例出DBUser即可。

  1.  
    private void Start()
  2.  
    {
  3.  
    new DBUser();
  4.  
    }

        第二部:完成我们的UserData类。直接上代码:

  1.  
    using Newtonsoft.Json;
  2.  
    using System;
  3.  
    using System.Collections;
  4.  
    using System.Collections.Generic;
  5.  
    using UnityEngine;
  6.  
     
  7.  
    public class UserData
  8.  
    {
  9.  
    public static string type = "userdata";
  10.  
     
  11.  
    [NonSerialized]
  12.  
    public bool save = false;
  13.  
     
  14.  
    #region 实例Inst
  15.  
    private static UserData _inst;
  16.  
    public static UserData Inst
  17.  
    {
  18.  
    get { return _inst; }
  19.  
    set { _inst = value; }
  20.  
    }
  21.  
    #endregion
  22.  
     
  23.  
    #region 一些方法
  24.  
    public void InitUserData()
  25.  
    {
  26.  
    //TODO : 执行一些新用户需要执行的方法
  27.  
    }
  28.  
     
  29.  
    public string ToJson()
  30.  
    {
  31.  
    string str = string.Empty;
  32.  
    str = JsonConvert.SerializeObject(this, Formatting.None);
  33.  
    return str;
  34.  
    }
  35.  
     
  36.  
    public UserData() { }
  37.  
    #endregion
  38.  
     
  39.  
     
  40.  
    private int _glod = 2000;
  41.  
     
  42.  
    //******************************************************************************//
  43.  
    //******** 注意:增加字段,一定要【设默认值】且数组【不能赋值】 **********//
  44.  
    //******** 增加字段,private, 不要直接增加public **********//
  45.  
    //******** 按照当前的标准处理.否则可能无法存储 **********//
  46.  
    //******************************************************************************//
  47.  
     
  48.  
    //用户的金币数量
  49.  
    public int glod { get { return _glod; } set { _glod = value; save = true; } }
  50.  
    }
学新通

        稍微解释下:

        string type这个变量主要是区分储存的类型的,这里是"userdata"主要就是本地储存用户数据的,将来可能还有数据库储存的类型,这里就不展开说了,本文只介绍本地储存。觉着没用的把它删了就行,其他脚本里用到相关类型的一起改一下就好,觉得麻烦的就留着也没有什么影响。

        至于这个bool save这个变量主要是控制是否需要储存的,我们每次修改值也就是Set的时候将save设为true,这样在每次保存数据的时候如果没有值的改变我们就不需要储存数据,这是提升性能的一个小技巧。

        ToJson这个方法就是将这个类序列化,返回一个字符串,这里我用的是Newtonsoft.Json。大家自己在github上找吧,我这里就不贴了。

        我们这里不仅可储存int、string、bool等基础类型,也可以储存List、Dictionary等数组、字典。也可以自己创建结构体去储存。可以说扩展性非常的强。

        第三部:有了我们的数据储存类,就继续完成我们的DBUser的读取与储存逻辑:

  1.  
    public class DB_User
  2.  
    {
  3.  
    #region 实例Inst
  4.  
    private static DB_User _inst;
  5.  
    public static DB_User Inst
  6.  
    {
  7.  
    get { return _inst; }
  8.  
    private set { _inst = value; }
  9.  
    }
  10.  
    #endregion
  11.  
     
  12.  
    private const string PLAYKEY = "db_";
  13.  
     
  14.  
    private string savePath = string.Empty;
  15.  
     
  16.  
    public DBManager dbManager;
  17.  
     
  18.  
    public DB_User()
  19.  
    {
  20.  
    _inst = this;
  21.  
    InitDB();
  22.  
    dbManager = new GameObject("DB").AddComponent<DBManager>();
  23.  
    }
  24.  
     
  25.  
    public void SaveUser()
  26.  
    {
  27.  
    string queryModel = UserData.Inst.ToJson();
  28.  
    Save(queryModel, UserData.type);
  29.  
    }
  30.  
     
  31.  
    private void InitDB()
  32.  
    {
  33.  
    CreateDBForder();
  34.  
     
  35.  
    InitUserdata();
  36.  
    }
  37.  
     
  38.  
    private void CreateDBForder()
  39.  
    {
  40.  
    string localPath = $"file://{Application.persistentDataPath}";
  41.  
    savePath = localPath "/gameDB/";
  42.  
    try
  43.  
    {
  44.  
    if (Directory.Exists(savePath) == false)
  45.  
    {
  46.  
    Directory.CreateDirectory(savePath);
  47.  
    }
  48.  
    }
  49.  
    catch { }
  50.  
    }
  51.  
     
  52.  
    private void InitUserdata()
  53.  
    {
  54.  
    string queryModel = Read(UserData.type);
  55.  
    Debug.Log("UserData : " queryModel);
  56.  
    if (!string.IsNullOrEmpty(queryModel))
  57.  
    {
  58.  
    UserData.Inst = JsonConvert.DeserializeObject<UserData>(queryModel);
  59.  
    }
  60.  
    else
  61.  
    {
  62.  
    // 无数据就创建新用户
  63.  
    UserData.Inst = new UserData();
  64.  
    UserData.Inst.InitUserData();
  65.  
    }
  66.  
    }
  67.  
     
  68.  
    private string Read(string type)
  69.  
    {
  70.  
    string data = string.Empty;
  71.  
    string name = PLAYKEY type ".dat";
  72.  
    string filename = string.Format("{0}/{1}", savePath, name);
  73.  
    if (FileExists(filename))
  74.  
    {
  75.  
    try
  76.  
    {
  77.  
    data = StreamReader(filename);
  78.  
    }
  79.  
    catch
  80.  
    {
  81.  
    Debug.LogError("存档文件失败 : " filename);
  82.  
    }
  83.  
    }
  84.  
    return data;
  85.  
    }
  86.  
     
  87.  
    private void Save(string data, string type)
  88.  
    {
  89.  
    string name = PLAYKEY type ".dat";
  90.  
    try
  91.  
    {
  92.  
    string filename = string.Format("{0}/{1}", savePath, name);
  93.  
    StreamWriter(filename, data);
  94.  
    }
  95.  
    catch
  96.  
    {
  97.  
    Debug.LogError("存档文件保存失败:" name);
  98.  
    }
  99.  
    }
  100.  
     
  101.  
    #region Common
  102.  
    /// <summary>
  103.  
    /// 判断文件是否存在
  104.  
    /// </summary>
  105.  
    /// <param name="path"></param>
  106.  
    /// <returns></returns>
  107.  
    private bool FileExists(string path)
  108.  
    {
  109.  
    path = ReplaceFileStart(path);
  110.  
    return System.IO.File.Exists(path);
  111.  
    }
  112.  
     
  113.  
    /// <summary>
  114.  
    /// 替换FILE
  115.  
    /// </summary>
  116.  
    /// <param name="path"></param>
  117.  
    /// <returns></returns>
  118.  
    private string ReplaceFileStart(string path)
  119.  
    {
  120.  
    if (path.StartsWith("file://"))
  121.  
    {
  122.  
    path = path.Replace("file://", string.Empty);
  123.  
    }
  124.  
    return path;
  125.  
    }
  126.  
     
  127.  
    /// <summary>
  128.  
    /// 读取文件
  129.  
    /// </summary>
  130.  
    /// <param name="path"></param>
  131.  
    /// <returns></returns>
  132.  
    private string StreamReader(string path)
  133.  
    {
  134.  
    path = ReplaceFileStart(path);
  135.  
    if (FileExists(path))
  136.  
    {
  137.  
    try
  138.  
    {
  139.  
    System.IO.StreamReader sr = new System.IO.StreamReader(path);
  140.  
    string jsonStr = sr.ReadToEnd();
  141.  
    sr.Close();
  142.  
    return jsonStr;
  143.  
    }
  144.  
    catch
  145.  
    {
  146.  
    Debug.LogError("读取文件失败 : " path);
  147.  
    }
  148.  
    }
  149.  
    return string.Empty;
  150.  
    }
  151.  
     
  152.  
    /// <summary>
  153.  
    /// 写入储存文件
  154.  
    /// </summary>
  155.  
    /// <param name="path"></param>
  156.  
    /// <param name="data"></param>
  157.  
    private void StreamWriter(string path, string data)
  158.  
    {
  159.  
    path = ReplaceFileStart(path);
  160.  
    try
  161.  
    {
  162.  
    string forder = GetFileDirectory(path);
  163.  
    bool exists = System.IO.Directory.Exists(forder);
  164.  
    if (!exists)
  165.  
    {
  166.  
    System.IO.Directory.CreateDirectory(forder);
  167.  
    }
  168.  
     
  169.  
    System.IO.StreamWriter sw = new System.IO.StreamWriter(path);
  170.  
    sw.Write(data);
  171.  
    //关闭StreamWriter
  172.  
    sw.Close();
  173.  
    }
  174.  
    catch (System.Exception ee)
  175.  
    {
  176.  
    Debug.Log("文件写入失败:" path " Error:" ee.Message);
  177.  
    }
  178.  
    }
  179.  
     
  180.  
    /// <summary>
  181.  
    /// 替换格式
  182.  
    /// </summary>
  183.  
    /// <param name="path"></param>
  184.  
    /// <returns></returns>
  185.  
    private string GetFileDirectory(string path)
  186.  
    {
  187.  
    path = path.Replace("\\", "/");
  188.  
    path = ReplaceFileStart(path);
  189.  
    return System.IO.Path.GetDirectoryName(path);
  190.  
    }
  191.  
    #endregion
  192.  
    }
学新通

(数据加密这里我就不展开说了,这里只介绍储存方法) 

        最后就是处理DBManager了 :

  1.  
    using System.Collections;
  2.  
    using System.Collections.Generic;
  3.  
    using UnityEngine;
  4.  
     
  5.  
    public class DBManager : MonoBehaviour
  6.  
    {
  7.  
    private float saveTimeout = 0;
  8.  
     
  9.  
    /// <summary>
  10.  
    /// 用户数据自动储存时间
  11.  
    /// </summary>
  12.  
    public const float AUTOSAVETIME = 60f;
  13.  
     
  14.  
    private void Start()
  15.  
    {
  16.  
    DontDestroyOnLoad(this);
  17.  
    }
  18.  
     
  19.  
    private void Update()
  20.  
    {
  21.  
    AutoSave();
  22.  
    }
  23.  
     
  24.  
    private void OnApplicationFocus(bool focus)
  25.  
    {
  26.  
    if (!focus)
  27.  
    {
  28.  
    SaveData();
  29.  
    }
  30.  
    }
  31.  
     
  32.  
    private void SaveData()
  33.  
    {
  34.  
    if (UserData.Inst == null || DB_User.Inst == null) return;
  35.  
     
  36.  
    if (UserData.Inst.save)
  37.  
    {
  38.  
    DB_User.Inst.SaveUser();
  39.  
    UserData.Inst.save = false;
  40.  
    }
  41.  
    }
  42.  
     
  43.  
    private void AutoSave()
  44.  
    {
  45.  
    if (Time.time > saveTimeout AUTOSAVETIME)
  46.  
    {
  47.  
    saveTimeout = Time.time;
  48.  
    SaveData();
  49.  
    }
  50.  
    }
  51.  
    }
学新通

        这里就是每隔60s对用户数据进行一次本地的写入储存,如果用户有脱离游戏焦点的行为是强制储存一次。

结尾:

        如何使用我们这个数据储存模块呢?

        在正确的初始化之后,我们直接调用UserData就可以了。

        UserData.Inst.glod = 100;

        再次进入游戏之后就可看到在控台输出一个json:

  1.  
    {
  2.  
    "glod": 96010
  3.  
    }

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfichfa
系列文章
更多 icon
同类精品
更多 icon
继续加载