原文地址:Unity3D游戏开发之游戏读/存档功能在Unity3D中的实现
感谢风宇冲Unity3D教程宝典之两步实现超实用的XML存档一文提供相关思路!
using Newtonsoft.Json;错误,则是因为缺少Newtonsoft.JSON库,请自行下载。
Newtonsoft.Json文件存放在Unity位置如下所示
UNITY对于JSON存储的思路以及介绍,参考资料已经说明很清楚
本文章着重代码说明,说明代码的作用
-----------------------------------------------------TestSave.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class TestSave : MonoBehaviour
{
///
/// 定义一个测试类
///
public class TestClass
{
public string Name = "张三";
public float Age = 23.0f;
public int Sex = 1;
public List Ints = new List(){1,2,3};//定义List变量
}
void Start()
{
//定义存档路径
string dirpath = Application.persistentDataPath + "/Save";//Application.persistentDataPath="C:/Users/Administrator/AppData/LocalLow/lucas_meijer@gmail_com/unity"
//创建存档文件夹
IOHelper.CreateDirectory(dirpath);
//定义存档文件路径
string filename = dirpath + "/GameData.sav";//dirpath="C:/Users/Administrator/AppData/LocalLow/lucas_meijer@gmail_com/unity/Save"
TestClass t = new TestClass();
//保存数据
IOHelper.SetData(filename, t);
//读取数据
TestClass t1 = (TestClass)IOHelper.GetData(filename, typeof(TestClass));
Debug.Log(t1.Name);
Debug.Log(t1.Age);
Debug.Log(t1.Ints);
Debug.Log(filename);//加上这一句,就可以显示存档路径
}
}
结束-----------------------------------------------------TestSave.cs
意思是这个public class TestClass类,里面的数据都是可以存储的,
还可以使用C#类的继承来,子类继承父类,(在原有的类的数据基础上,子类可以添加更多的数据类型和数据)
显示存档路径为
C:/Users/Administrator/AppData/LocalLow/lucas_meijer@gmail_com/unity/Save/GameData.sav
c#如何定义全局变量list
public是公共的,static是静态的,class表示这是类。
public static class 表示这是一个公共的静态类,直接通过类名调用里面的方法,变量等。不用new的。
public class 需要new才可以用。
class 是表示私有的类,外部不能调用。
-----------------------------------------------------IOHelper.cs
using UnityEngine;
using System.Collections;
using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
using Newtonsoft.Json;
public static class IOHelper
{
///
/// 判断文件是否存在
///
//为真,则路径表示文件
public static bool IsFileExists(string fileName)
{
return File.Exists(fileName);//参考资料1
}
///
/// 判断文件夹是否存在
///
//为真,则路径表示目录
public static bool IsDirectoryExists(string fileName)
{
return Directory.Exists(fileName);
}
///
/// 创建一个文本文件
///
/// 文件路径
/// 文件内容
public static void CreateFile(string fileName, string content)
{
StreamWriter streamWriter = File.CreateText(fileName);//参考资料2 C#中File类的文件操作方法详解
streamWriter.Write(content);
streamWriter.Close();
}
///
/// 创建一个文件夹
///
public static void CreateDirectory(string fileName)
{
//文件夹存在则返回//为真,则路径表示目录
if (IsDirectoryExists(fileName))
return;
Directory.CreateDirectory(fileName);
}
//写入存档文件
public static void SetData(string fileName, object pObject)
{
//将对象序列化为字符串
string toSave = SerializeObject(pObject);//调用 序列化函数
//对字符串进行加密,32位加密密钥//调用 Rijndael加密算法
toSave = RijndaelEncrypt(toSave, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");//在这里把32个"x"的字符串变量的值 改为一个32位根据MAC地址编辑的变量就是密钥
StreamWriter streamWriter = File.CreateText(fileName);//· CreateText:为写入文本创建或打开新文件
streamWriter.Write(toSave);
streamWriter.Close();
}
//读取存档文件
public static object GetData(string fileName, Type pType)
{
StreamReader streamReader = File.OpenText(fileName);//· OpenText:打开现有文本文件以进行读取
string data = streamReader.ReadToEnd();//参考资料3 ReadToEnd() 这个方法适用于小文件的读取,一次性的返回整个文件
//对数据进行解密,32位解密密钥//调用 Rijndael解密算法
data = RijndaelDecrypt(data, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");//在这里把32个"x"的字符串变量的值 改为一个32位根据MAC地址编辑的变量就是密钥
streamReader.Close();
return DeserializeObject(data, pType);//调用 反 加密算法函数
//返回已经解密的值
}
///
/// Rijndael加密算法
///
/// 待加密的明文
/// 密钥,长度可以为:64位(byte[8]),128位(byte[16]),192位(byte[24]),256位(byte[32])
/// iv向量,长度为128(byte[16])
///
private static string RijndaelEncrypt(string pString, string pKey)// Rijndael加密算法
{
//密钥
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(pKey);
//待加密明文数组
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(pString);//上面被序列化的变量
//Rijndael解密算法
RijndaelManaged rDel = new RijndaelManaged();
rDel.Key = keyArray;
rDel.Mode = CipherMode.ECB;
rDel.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = rDel.CreateEncryptor();
//返回加密后的密文
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
///
/// ijndael解密算法
///
/// 待解密的密文
/// 密钥,长度可以为:64位(byte[8]),128位(byte[16]),192位(byte[24]),256位(byte[32])
/// iv向量,长度为128(byte[16])
///
private static String RijndaelDecrypt(string pString, string pKey)// ijndael解密算法
{
//解密密钥
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(pKey);
//待解密密文数组
byte[] toEncryptArray = Convert.FromBase64String(pString);//上面被序列化的变量
//Rijndael解密算法
RijndaelManaged rDel = new RijndaelManaged();
rDel.Key = keyArray;
rDel.Mode = CipherMode.ECB;
rDel.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = rDel.CreateDecryptor();
//返回解密后的明文
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
return UTF8Encoding.UTF8.GetString(resultArray);
}
///
/// 将一个对象序列化为字符串
///
/// The object.
/// 对象
/// 对象类型
private static string SerializeObject(object pObject)
{
//序列化后的字符串
string serializedString = string.Empty;
//使用Json.Net进行序列化
serializedString = JsonConvert.SerializeObject(pObject);
return serializedString;
}
///
/// 将一个字符串反序列化为对象
///
/// The object.
/// 字符串
/// 对象类型
private static object DeserializeObject(string pString, Type pType)
{
//反序列化后的对象
object deserializedObject = null;
//使用Json.Net进行反序列化
deserializedObject = JsonConvert.DeserializeObject(pString, pType);
return deserializedObject;
}
}
结束-----------------------------------------------------IOHelper.cs
1.file_exists
c#中怎么获得当前路径
使用Directory.Exists或File.Exist方法,如果前者为真,则路径表示目录;如果后者为真,则路径表示文件
上面的方法有个缺点就是不能处理那些不存在的文件或目录。
这时可以考虑使用Path.GetFileName方法获得其包含的文件名,如果一个路径不为空,而文件名为空那么它表示目录,否则表示文件;
2.C#中File类的文件操作方法详解
【整理】C#文件操作大全(SamWang)
3.ReadToEnd()
这个方法适用于小文件的读取,一次性的返回整个文件
StreamReader类以及其方法ReadLine,Read,ReadToEnd的分析
------------------------------------------------------------
那么这个32个“x”是否就是密钥呢,代码改变如下所示
UNITY返回的结果如下所示
密钥改变如下所示
结果正常
那么把 加密和解密的代码注释掉,是否正常运行。
源码中的数据都是通过 对自己数据改变,因此注释 加密和解密的代码
是完全没有问题的
---------------------------------------------------------------------------IOHelper.cs代码图片
---------------------------------------------------------------------------
那么如何存储多个像NET.JSON一样的数据呢,
添加了一个和张三差不多的数据,李四
输出的结果如下所示,李四的数据完全覆盖了张三的信息,如果想要分别保存张三和李四的信息,该怎么做呢
存储多个“张三”“李四”类型的数据,就得使用继承基础类
,效果理解上与“复制粘贴”一样
每个数据的类型不同,比XML相比较,只用新建一个"李四"类
就可以在不改变数据结构的情况下,保存类似的结构
效果如下所示,然后发现是可选的