对于Unity Sqlite和JSON 本地数据存储这方面我不是很了解,所以就在这共享一下被人的帖子,希望可以对这方面有需求的人是一种帮助。

基本思路,游戏基础配置数据,比如怪物的属性、装备模板属性、关卡怪物等,使用SQLite(Unity插件SQLiteUnityKit-GitHub地址,推荐客户端SQLite Expert Personal 3),管理方便
玩家核心数据(属性、装备、技能)使用JSON格式,加密保存在Application.persistentDataPath路径里,避免每次升级被覆盖
插件本地下载地址Sqlite框架
litJson

准备工作 

1 litJson.dll放在Plugins目录下

2 libsqlite3.so文件放到 Assets/Plugins/Android目录下

3 自定义的SQLite DB数据文件放到 Assets/StreamingAssets目录下

SQLite篇 将准备好的DB数据文件拷贝到Assets/StreamingAssets
         把SQLiteUnityKit GitHub下载的压缩包里的 DataTable.cs、SqliteDatabase.cs,拷贝到项目中的任意位置

最终项目结构看起来是这样子的

Unity Sqlite和JSON 本地数据存储

       SQLiteUnityKit框架用Dictionary数据结构模拟了DataTable,DataRow,因此我们执行查询语句的时候,返回的是DataTable,就像平时使用ado.net提供的查询模式一样。

调用方式

SqliteDatabase sqlDB = new SqliteDatabase(“config.db”);
string query = “INSERT INTO User(UserName) VALUES( ‘Santiago’)”;

sqlDB.ExecuteNonQuery(query);

我做了个unitypackge的例子,大家可以下载导入
Json篇原先是使用XML格式来存储数据的,因为XML跨平台,但是Json同样也可以做到,加上有LitJson这个格式转化利器,因此,本地文件存储格式,本文以Json为例。
关于数据加密使用c#提供的加密类即可,自己定义秘钥
  1. using System.Security.Cryptography;
  2. using System.Text;
  3. public class GlobalDataHelper
  4. {
  5. private const string DATA_ENCRYPT_KEY = "a234857890654c3678d77234567890O2";
  6. private static RijndaelManaged _encryptAlgorithm = null;
  7. public static RijndaelManaged DataEncryptAlgorithm ()
  8. {
  9. _encryptAlgorithm = new RijndaelManaged ();
  10. _encryptAlgorithm.Key = Encoding.UTF8.GetBytes (DATA_ENCRYPT_KEY);
  11. _encryptAlgorithm.Mode = CipherMode.ECB;
  12. _encryptAlgorithm.Padding = PaddingMode.PKCS7;
  13. return _encryptAlgorithm;
  14. }
  15. }
关于破解版软件安卓机子上泛滥各种XXX破解版,关于破解版的问题,我们可以通过Unity提供的唯一机器ID,在写入玩家数据的时候,将其一并写入到数据中去,在读取数据之后,对比该ID和本机ID,如果不一致,则认为是破解版

SystemInfo.deviceUniqueIdentifier

本例子是以基础配置数据为例,因此代码中不提供该功能。

关于避免更新之后,玩家存档被覆盖Unity提供了一个只读路径,放在该路径下的文件,不会被软件更新所影响。

Application.persistentDataPath
Json Helper类~~
  1. using System.Security.Cryptography;
  2. using System.Text;
  3. using System;
  4. using System.IO;
  5. using LitJson;
  6. public class DataStoreProcessor
  7. {
  8. private static DataStoreProcessor _dataStoreProcessor = null;
  9. public static DataStoreProcessor SharedInstance {
  10. get {
  11. if (_dataStoreProcessor == null)
  12. _dataStoreProcessor = new DataStoreProcessor ();
  13. return _dataStoreProcessor;
  14. }
  15. }
  16. /// <summary>
  17. /// 加密数据
  18. /// </summary>
  19. /// <returns>The data.</returns>
  20. /// <param name="dataToEncrypt">Data to encrypt.</param>
  21. public string EncryptData (string dataToEncrypt)
  22. {
  23. //给明文加密用GetBytes
  24. byte[] dataToEncryptArray = Encoding.UTF8.GetBytes (dataToEncrypt);
  25. byte[] dataAfterEncryptArray = GlobalDataHelper.DataEncryptAlgorithm().CreateEncryptor ()
  26. .TransformFinalBlock (dataToEncryptArray, 0, dataToEncryptArray.Length);
  27. return Convert.ToBase64String (dataAfterEncryptArray, 0, dataAfterEncryptArray.Length);
  28. }
  29. /// <summary>
  30. /// 解密数据
  31. /// </summary>
  32. /// <returns>The data.</returns>
  33. /// <param name="dataToDecrypt">Data to decrypt.</param>
  34. public string DecryptData (string dataToDecrypt)
  35. {
  36. //给密文解密用FromBase64String
  37. byte[] dataToDecryptArray = Convert.FromBase64String (dataToDecrypt);
  38. byte[] dataAfterDecryptArray = GlobalDataHelper.DataEncryptAlgorithm().CreateDecryptor ()
  39. .TransformFinalBlock (dataToDecryptArray, 0, dataToDecryptArray.Length);
  40. return Encoding.UTF8.GetString (dataAfterDecryptArray);
  41. }
  42. /// <summary>
  43. /// 数据保存
  44. /// </summary>
  45. /// <param name="tobject">Tobject.</param>
  46. /// <param name="path">;Path.</param>
  47. /// <typeparam name="T">The 1st type parameter.</typeparam>
  48. public void Save (Object tobject, string path, bool isEncrypt=true)
  49. {
  50. string serializedString = JsonMapper.ToJson (tobject);
  51. using (StreamWriter sw = File.CreateText(path)) {
  52. if (isEncrypt)
  53. sw.Write (EncryptData (serializedString));
  54. else
  55. sw.Write (serializedString);
  56. }
  57. }
  58. /// <summary>
  59. /// 载入数据
  60. /// </summary>
  61. /// <param name="path">;Path.</param>
  62. /// <typeparam name="T">The 1st type parameter.</typeparam>
  63. public T Load<T> (string path, bool isEncrypt=true)
  64. {
  65. if (File.Exists (path) == false)
  66. return default(T);
  67. using (StreamReader sr = File.OpenText(path)) {
  68. string stringEncrypt = sr.ReadToEnd ();
  69. if (string.IsNullOrEmpty (stringEncrypt))
  70. return default(T);
  71. if (isEncrypt)
  72. return  JsonMapper.ToObject<T> (DecryptData (stringEncrypt));
  73. else
  74. return JsonMapper.ToObject<T> (stringEncrypt);
  75. }
  76. }
  77. }

调用方式 下面的代码将提供了一个自定义窗体,允许开发者自行定义用户在等待界面时,显示本地配置好的文字

按照道理,这种游戏基础配置类的应该使用Sql方式来进行数据交互,本文仅仅是为了进行功能的演示。

只有玩家数据,才使用本地文件存储的方式,存储在永久的路径里面
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. using UnityEditor;
  4. public class LoadingDataConfigWindow : ScriptableWizard
  5. {
  6. public List<string> NotifyString;
  7. //改成 Application.persistentDataPath永久存储
  8. private readonly string LOADING_DATA_CONFIG_URL = Application.dataPath + @"/Resources/Setting/LoadNotify.data";
  9. public LoadingDataConfigWindow()
  10. {
  11. NotifyString = DataStoreProcessor.SharedInstance.Load<List<string>>(LOADING_DATA_CONFIG_URL,false);
  12. }
  13. [MenuItem ("GameObject/Data Setting/Loading text")]
  14. static void CreateWizard ()
  15. {
  16. LoadingDataConfigWindow window =    DisplayWizard<LoadingDataConfigWindow> ("配置登陆提示文字", "确认", "取消");
  17. window.minSize = new Vector2(1024,768);
  18. }
  19. // This is called when the user clicks on the Create button.
  20. void OnWizardCreate ()
  21. {
  22. DataStoreProcessor.SharedInstance.Save(NotifyString,LOADING_DATA_CONFIG_URL,false);
  23. Debug.Log(string.Format(" 保存成功,共计录入 {0} 数据",NotifyString.Count));
  24. }
  25. // Allows you to provide an action when the user clicks on the
  26. // other button "Apply".
  27. void OnWizardOtherButton ()
  28. {
  29. Debug.Log ("取消");
  30. }
  31. }