- A+
所属分类:.NET技术
数据持久化
PlayerPrefs相关
PlayerPrefs是Unity游戏引擎中的一个类,用于在游戏中存储和访问玩家的偏好设置和数据。它可以用来保存玩家的游戏进度、设置选项、最高分数等信息。PlayerPrefs将数据存储在本地文件中,因此可以在游戏重新启动时保持数据的持久性。
//PlayerPrefs的数据存储 类似于键值对存储 一个键对应一个值 //提供了存储3种数据的方法 int float string //键: string类型 //值:int float string 对应3种API PlayerPrefs.SetInt("myAge", 18); PlayerPrefs.SetFloat("myHeight", 177.5f); PlayerPrefs.SetString("myName", "TonyChang"); //直接调用Set相关方法 只会把数据存到内存里 //当游戏结束时 Unity会自动把数据存到硬盘中 //如果游戏不是正常结束的 而是崩溃 数据是不会存到硬盘中的 //只要调用该方法 就会马上存储到硬盘中 PlayerPrefs.Save(); //PlayerPrefs是有局限性的 它只能存3种类型的数据 //如果你想要存储别的类型的数据 只能降低精度 或者上升精度来进行存储 bool sex = true; PlayerPrefs.SetInt("sex", sex ? 1 : 0); //如果不同类型用同一键名进行存储 会进行覆盖 PlayerPrefs.SetFloat("myAge", 20.2f); //注意 运行时 只要你Set了对应键值对 //即使你没有马上存储Save在本地 //也能够读取出信息 //int int age = PlayerPrefs.GetInt("myAge"); print(age); //前提是 如果找不到myAge对应的值 就会返回函数的第二个参数 默认值 age = PlayerPrefs.GetInt("myAge", 100); print(age); //float float height = PlayerPrefs.GetFloat("myHeight", 1000f); print(height); //string string name = PlayerPrefs.GetString("myName"); print(name); //第二个参数 默认值 对于我们的作用 //就是 在得到没有的数据的时候 就可以用它来进行基础数据的初始化 //判断数据是否存在 if( PlayerPrefs.HasKey("myName") ) { print("存在myName对应的键值对数据"); } //删除指定键值对 PlayerPrefs.DeleteKey("myAge"); //删除所有存储的信息 PlayerPrefs.DeleteAll();
PlayerPrefs中存储的数据存储在哪里?
PC端: PlayerPrefs 存储在 HKCUSoftware[公司名称][产品名称] 项下的注册表中
其中公司和产品名称是 在“Project Settings”中设置的名称。
安卓: /data/data/包名/shared_prefs/pkg-name.xml
PlayerPrefs中数据的唯一性,PlayerPrefs中数据的唯一性是由key决定的,不同的key决定了不同的数据,同一个项目中如果不同数据key相同会造成数据丢失,要保证数据名称命名的唯一性规则。
优点:使用简单
缺点:存储数据类型有限、安全性差(直接找到在设备上的存储的位置查看设置)
PlayerPrefs存储工具类:
为了方便进行数据的存储,使用PlayerPrefs中进行存储方法的设置的存取!
主要实现功能是数据的读和数据的取~ 通过反射进行数据类型的获取,利用PlayerPrefs进行数据存储。
using System; using System.Collections; using System.Reflection; using UnityEngine; namespace Framwork { /// <summary> /// Playerprefs 存储类 /// </summary> public class PlayerPrefsManager { private static PlayerPrefsManager instance=new PlayerPrefsManager(); public static PlayerPrefsManager Instance => instance; private PlayerPrefsManager() { } /// <summary> /// 存取数据的方法 /// </summary> /// <param name="obj">数据实体</param> /// <param name="name">数据名称</param> public void SaveData(object data, string keyName) { Type type = data.GetType(); FieldInfo[] infos = type.GetFields(); string tempKey="null"; FieldInfo tempInfo = null; for (int i = 0; i < infos.Length; i++) { //获取数据数据类型 tempInfo = infos[i]; Debug.Log("Types==="+tempInfo); //类的名字+类的类型 + 数据内容名字+数据类型 //作为存储的keyName键 tempKey = keyName + "_" + type.Name + "_" + tempInfo.Name + "_" + tempInfo.FieldType.Name; SaveValue(tempInfo.GetValue(data),tempKey); } //进行值的获取 //tempInfo.GetValue(data); PlayerPrefs.Save(); } /// <summary> /// 读取数据的类型 /// </summary> /// <param name="type">要读取的数据类型</param> /// <param name="name">要读取的数据名称</param> /// <returns>返回数据实体</returns> public object LoadData(Type type, string name) { //获取数据中的类型 FieldInfo[] infos = type.GetFields(); //创建存储数据信息的实体 object data = Activator.CreateInstance(type); string tempName = null; FieldInfo tempInfo = null; for (int i = 0; i < infos.Length; i++) { tempInfo = infos[i];//数据结构中的数据名称 tempName = name + "_" + type.Name + "_" +tempInfo.Name+"_" +tempInfo.FieldType.Name;//数据结构中的数据名称类型 //装载的容器 容器中的数据 //进行数据装载 tempInfo.SetValue(data,LoadValue(tempInfo.FieldType,tempName)); } return data; } /// <summary> /// 进行具体的类型数据的存储 /// </summary> /// <param name="data"></param> /// <param name="keyName"></param> private void SaveValue(object value, string keyName) { Type fieldType = value.GetType(); if (fieldType == typeof(int)) { Debug.Log("存储int"+value); PlayerPrefs.SetInt(keyName,(int)value); }else if (fieldType == typeof(float)) { Debug.Log("存储float"+value); PlayerPrefs.SetFloat(keyName,(float)value); }else if (fieldType == typeof(string)) { Debug.Log("存储string"+value); PlayerPrefs.SetString(keyName,value.ToString()); } //对于List存储的设置 //根据存储的字段类型和IList是否是父子关系 else if(typeof(IList).IsAssignableFrom(fieldType)) { //父类装子类 IList list=value as IList; //存储元素数量 PlayerPrefs.SetInt(keyName,list.Count); Debug.Log("存储List长度为"+list.Count); int index = 0; foreach (var obj in list) { //存储list列表中元素内容 //命名形式是 list名字+索引编号 //递归调用存储 SaveValue(obj,keyName+index); index++; } }else if (typeof(IDictionary).IsAssignableFrom(fieldType)) { IDictionary dictionary = value as IDictionary; //存储数据个数 PlayerPrefs.SetInt(keyName,dictionary.Count); Debug.Log("存储Dic长度为"+dictionary.Count); int index = 0; foreach (var key in dictionary.Keys) { //存储键 SaveValue(key,keyName+"_key_"+index); //存储值 SaveValue(dictionary[key],keyName+"_value_"+index); index++; } }//自定义数据类型的存储 进行解析 else { SaveData(value,keyName); } } private object LoadValue(Type type, string name) { if (type == typeof(int)) { return PlayerPrefs.GetInt(name,0); }else if (type == typeof(float)) { return PlayerPrefs.GetFloat(name,0.0f); }else if (type == typeof(string)) { return PlayerPrefs.GetString(name,""); }else if (typeof(IList).IsAssignableFrom(type)) { //读取列表 int count = PlayerPrefs.GetInt(name); IList tempList=Activator.CreateInstance(type) as IList; for (int i = 0; i < count; i++) { //获取List中存储元素的类型 type.GetGenericArguments()[0] tempList.Add(LoadValue(type.GetGenericArguments()[0],name+i)); } return tempList; }else if (typeof(IDictionary).IsAssignableFrom(type)) { //进行对字典的读取 int count = PlayerPrefs.GetInt(name); IDictionary tempDictionary=Activator.CreateInstance(type) as IDictionary; for (int i = 0; i < count; i++) { tempDictionary.Add(LoadValue(type.GetGenericArguments()[0], name + "_key_" + i), LoadValue(type.GetGenericArguments()[1], name + "_value_" + i)); } return tempDictionary; } else { //读取自定义类成员的设置 return LoadData(type, name); } } } }
附:
测试脚本
using System.Collections.Generic; using UnityEngine; namespace Framwork { //注意: //1 自定义数据结构类型中要有有效的无参构造函数 public class PlayerInfo { public int age; public string name; public float height; public int sex;//0是女 1是男 public ItemInfo ItemInfo; //list存储测试 public List<int> list; public Dictionary<int, string> dic; } public class ItemInfo { public int stu_no;//学号 public int stu_class;//班级 public ItemInfo() { } public ItemInfo(int no,int classNo) { stu_no = no; stu_class = classNo; } } /// <summary> /// 测试类 /// </summary> public class TestPlayerPrefsTest:MonoBehaviour { private PlayerInfo playerInfo; private PlayerInfo playerInfo1; private void Start() { //读取数据 playerInfo = new PlayerInfo(); // Type fieldType = playerInfo.GetType(); playerInfo.age = 18; playerInfo.name = "TonyChang"; playerInfo.height = 175.8f; playerInfo.sex = 1; playerInfo.ItemInfo = new ItemInfo(2001, 2); playerInfo.list = new List<int>(){1,5,6,8}; playerInfo.dic = new Dictionary<int, string>(); playerInfo.dic.Add(1,"Tony"); playerInfo.dic.Add(2,"Jeny"); playerInfo.dic.Add(3,"JayChou"); //进行数据保存 PlayerPrefsManager.Instance.SaveData(playerInfo,"Player1"); playerInfo1 = PlayerPrefsManager.Instance.LoadData(typeof(PlayerInfo), "Player1") as PlayerInfo; Debug.Log("age=="+playerInfo1.age); Debug.Log("name=="+playerInfo1.name); Debug.Log("sex=="+playerInfo1.sex); Debug.Log("List[1]=="+playerInfo1.list[1]); Debug.Log("Dic[1]=="+playerInfo1.dic[1]); } } }