2014-05-04更新

SqliteDatabase.cs这个文件的初始方法有问题,具体是如果指定URL已经存在了DB文件,就不会重新覆盖DB文件。

这导致我们修改之后的DB文件无法产生效果。

本人的解决办法是在游戏启动的界面,通过对比本地的Resources目录下的文件A,和玩家核心数据B里面的数据库版本号,

如果A>B,则判定本地的DB文件版本较老,需要更新。

具体代码请到目录SQLite篇下下载

2014-04-30更新

剔除了使用网络上烂大街的SQLite使用方法(原因android下无法读取数据),使用libSQLite3.so,通过DLLImport,在C#代码里直接调用C接口

这种原生调用SQLite的方式,我在pc、android上亲测无误,ios没测过,但是stackoverflow上有兄弟试过,没问题。园子的朋友如果可以测IOS的,欢迎提供结果

基本思路,游戏基础配置数据,比如怪物的属性、装备模板属性、关卡怪物等,使用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,拷贝到项目中的任意位置

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

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

 调用方式

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

我做了个unitypackge的例子,大家可以下载导入

Json篇

原先是使用XML格式来存储数据的,因为XML跨平台,但是Json同样也可以做到,加上有LitJson这个格式转化利器,因此,本地文件存储格式,本文以Json为例。

关于数据加密

使用c#提供的加密类即可,自己定义秘钥

  1. using System.Security.Cryptography;
  2. using System.Text;
  3.  
  4. public class GlobalDataHelper
  5. {
  6. private const string DATA_ENCRYPT_KEY = "a234857890654c3678d77234567890O2";
  7. private static RijndaelManaged _encryptAlgorithm = null;
  8.  
  9. public static RijndaelManaged DataEncryptAlgorithm ()
  10. {
  11. _encryptAlgorithm = new RijndaelManaged ();
  12. _encryptAlgorithm.Key = Encoding.UTF8.GetBytes (DATA_ENCRYPT_KEY);
  13. _encryptAlgorithm.Mode = CipherMode.ECB;
  14. _encryptAlgorithm.Padding = PaddingMode.PKCS7;
  15.  
  16. return _encryptAlgorithm;
  17. }
  18. }

关于破解版软件

安卓机子上泛滥各种XXX破解版,关于破解版的问题,我们可以通过Unity提供的唯一机器ID,在写入玩家数据的时候,将其一并写入到数据中去,在读取数据之后,对比该ID和本机ID,如果不一致,则认为是破解版

  1. SystemInfo.deviceUniqueIdentifier

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

关于避免更新之后,玩家存档被覆盖

Unity提供了一个只读路径,放在该路径下的文件,不会被软件更新所影响。

  1. Application.persistentDataPath
  1.  

Json Helper类~~

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

调用方式

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

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

只有玩家数据,才使用本地文件存储的方式,存储在永久的路径里面

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

Unity本地数据存储---Sqlite和JSON的更多相关文章

  1. Android之ListView,AsyncTask,GridView,CardView,本地数据存储,SQLite数据库

    版权声明:未经博主允许不得转载 补充 补充上一节,使用ListView是用来显示列表项的,使用ListView需要两个xml文件,一个是列表布局,一个是单个列表项的布局.如我们要在要显示系统所有app ...

  2. Android本地数据存储复习

    Android本地数据存储复习 Android无论是应用层还是系统层都需要在本地保存一些数据,尤其在应用层中使用的就更为普遍,大体有这么几种:SharedPreference,file,sqlite数 ...

  3. iOS开发——数据持久化&使用NSUserDefaults来进行本地数据存储

    使用NSUserDefaults来进行本地数据存储   NSUserDefaults适合存储轻量级的本地客户端数据,比如记住密码功能,要保存一个系统的用户名.密码.使用NSUserDefaults是首 ...

  4. iOS APP之本地数据存储(译)

    最近工作中完成了项目的用户信息本地存储,查阅了一些本地存储加密方法等相关资料.期间发现了一个来自印度理工学院(IIT)的信息安全工程师的个人博客,写了大量有关iOS Application secur ...

  5. cocos2d-html5开发之本地数据存储

    做游戏时常常须要的一个功能呢就是数据的保存了,比方游戏最高分.得到的金币数.物品的数量等等.cocos2d-html5使用了html5.所以html5的数据保存方法是对引擎可用的: html5本地数据 ...

  6. Android本地数据存储: Reservoir

    一:前言 今天做项目,准备使用本地存储,把一些数据存在本地磁盘上,比如用户名.密码这样的.其实大家都知道,这种情况最常用的就是SharedPreferences了,我也不例外,脑子里第一个想到的就是用 ...

  7. [安卓安全] 01.安卓本地数据存储:Shared Preferences安全风险浅析

    *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...

  8. Windows 8 应用开发 - 本地数据存储

    原文:Windows 8 应用开发 - 本地数据存储      在应用中通常会遇到用户主动或被动存储信息的情况,当应用关闭后这些数据仍然会存储在本地设备上,用户下次重新激活应用时会自动加载这些数据.下 ...

  9. iOS开发技术分享(1)— iOS本地数据存储

    iOS开发技术分享(1)— iOS本地数据存储 前言: 我本是一名asp.net程序员,后来加入了iOS游戏开发队伍,到现在也有一年多的时间了.这一年来,每天都干到2.3点钟才睡觉,不为别的,只为了学 ...

随机推荐

  1. python3----datetime模块分析

    datetime模块用于是date和time模块的合集,datetime有两个常量,MAXYEAR和MINYEAR,分别是9999和1. datetime模块定义了5个类,分别是 1.datetime ...

  2. P2483 [SDOI2010]魔法猪学院

    P2483 [SDOI2010]魔法猪学院 摘要 --> 题目描述 iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练.经过了一周理论知识和一周基本魔法的学习之后,iPig对猪世 ...

  3. django定义app名称

    1.apps.py class AccountConfig(AppConfig): name = 'account' verbose_name = u'用户信息' # app显示中文 2. __ini ...

  4. kotlin gradle的修改

    Kotlin插件包括一个让我们配置Gradle的工具.但是我还是倾向于保持我对Gradle文件读写的控制权,否则它只会变得混乱而不会变得简单.不管怎么样,在使用自动工具之前知道它是怎么工作的是个不错的 ...

  5. 75、JSON 解析库---FastJson, Gson

    JSON 的简介: JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.用于数据转换传输, 通用于PHP,Java,C++,C#,Python等编程语言数据交 ...

  6. CxGrid如何实现导出Excel 功能

    ExportGrid4ToEXCEL  这个老的版本用的,新的版本引用 cxGridExportLink 这个单元 uses  Windows, Messages, SysUtils, Variant ...

  7. gulp报错160

    gulp报错: 这种提示,说明端口被占用,并且要改端口号,首先,我需要把Apache服务器关掉, 然后在gulpfile.js里: 把8080的端口号加进去.就解决了

  8. FluentNhibernate 不支持存储过程

    一直以为没有使用FN进行存储过程的操作,这次因为后台首页想统计下数据,就利用了存储过程,但在使用中却发现FN目前还不支持存储过程(点击查看官方),没有办法,只能利用Fluent Configurati ...

  9. idea下maven项目增加依赖项目里面没有添加相关依赖jar

    困扰了一晚上的问题,一般在pom.xml中增加了相关依赖,idea会自动将依赖的Jar包增加到maven项目中,但是在pom.xml中增加了依赖,项目中并没有 偶然打开idea的侧边栏maven工具栏 ...

  10. Xcode6 部署iphone4s出现的问题 No architectures to compile for

    手贱升级到了Xcode6.结果一打开来就爆了各种错误换个警告; 各种百度和谷歌,终于搞定了,然后插上4S,结果还是报错. 解决: 1.找到 Build Settings 2.点击 Architectu ...