Unity数据持久化之PlayerPrefs

这篇具有很好参考价值的文章主要介绍了Unity数据持久化之PlayerPrefs。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

PlayerPrefs概述

什么是数据持久化
数据持久化就是将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型的统称。即将游戏数据存储到硬盘,硬盘中数据读取到游戏中,也就是传统意义上的存盘。

基本方法

PlayerPrefs是什么
Unity提供的可以用于存储读取玩家数据的公共类
存储相关
PlayerPrefs的数据存储,类似于键值对存储,一个键对应一个值。
提供了存储3中数据的方法:int、float、string
键:string类型
值:int float string对应3种API

PlayerPrefs.SetInt("myAge",18);
PlayerPrefs.SetString("myHeight",177f);
PlayerPrefs.SetString("myName","123");

直接调用Set相关方法,只会把数据存到内存里。当游戏结束时,Unity会自动把数据存到硬盘中。如果游戏不是正常结束的,而是崩溃,数据是不会存到硬盘中的。

只要调用该方法,就会马上存储到硬盘中。

PlayerPrefs.Save();

PlayerPrefs是有局限性的,它只能存3种类型的数据,如果想要存储别的类型的数据,只能降低精度,或者上升精度来进行存储。

如果不同类型用同一键名进行存储,会进行覆盖。

PlayerPrefs.SetFloat("myAge",20.2f);

读取相关
运行时,只要使用了Set相关方法设置了对应键值对,即使没有马上存储在Save在本地,也可以读取出信息。

//int
int age = PlayerPrefs.GetInt("myAge");
age = PlayerPrefs.GetInt("myAge",100);
//float
float height = PlayerPrefs.GetFloat("myHeight",1000f);
//string
string name = PlayerPrefs.GetString("myName");

第二个参数默认值的作用就是在得到没有的数据的时候,就可以用它来进行基础数据的初始化。

判断数据是否存在。

if(PlayerPrefs.HasKey("myName"))
{
}

删除数据
删除指定键值对

PlayerPrefs.DeleteKey("myAge");

删除所有存储的信息

PlayerPrefs.DeleteAll();

PlayerPrefs存储位置

PlayerPrefs存储的数据存在哪里?
1、Windows
PlayerPrefs存储在:HKCU\Software\[公司名称]\[产品名称]项下的注册表中
其中公司和产品名称是在“Project Settings”中设置的名称

查找过程:
运行regedit
HKEY_CURRENT_USER
SOFTWARE
Unity
UnityEditor
公司名称
产品名称
2、Android
/data/data/包名/shared_prefs/pkg-name.xml
3、IOS
/Library/Preferences/[应用ID].plist
PlayerPrefs数据唯一性
PlayerPrefs中不同数据的唯一性,是由key决定的,不同的key决定了不同的数据。同一项目中,如果不同数据key相同,会造成数据丢失。要保证数据不丢失就要建立一个保证key唯一的规则。

实践小项目

反射知识补充

反射相关内容请移步:C#进阶学习
反射知识回顾
反射3剑客
1、Type:用于获取类的所有信息、字段、属性、方法等等。
2、Assembly:用于获取程序集,通过程序集获取Type
3、Activator:用于快速实例化对象。
判断一个类型的对象是否可以让另一个类型为自己分配空间(父类装子类)

public class Father
{
}
public class Son:Father
{
}
Type fatherType = typeof(Father);
Type sonType = typeof(Son);
//判断是否可以通过传入的类型为自己分配空间
if(fatherType.IsAssignableFrom(sonType))
{
}

通过反射获取泛型类型

List<string> list = new List<string>();
Type listType = list.GetType();
Type[] types = listType.GetGenericArguments();//获取到泛型类型string

Dictionary<string,float> dic = new Dictionary<string,float>();
Type dicType = dic.GetType();
types = dicType.GetGenericArguments();

数据管理类的创建

//PlayerPrefs数据管理类,统一管理数据的存储和读取
public class PlayerPrefsDataMgr
{
	private static PlayerPrefsDataMgr instance = new PlayerPrefsDataMgr();
	public static PlayerPrefsDataMgr Instance
	{
		get
		{
			return instance;
		}
	}
	private PlayerPrefsDataMgr(){}//私有构造
	
	//存储数据
	public void SaveData(object data,string keyName)
	{
	}
	//读取数据
	public object LoadData(Type type,string keyName)
	{
		return null;
	}
}

反射存储数据----常用成员

//存储数据
//通过Type得到传入数据对象的所有的字段,然后结合PlayerPrefs来进行存储
public void SaveData(object data,string keyName)
{
	//获取传入数据对象的所有字段
	Type dataType = data.GetType();	
	FieldInfo[] infos = dataTypes.GetFields();
	//自己定义一个key规则,进行数据存储
	//keyName_数据类型_字段类型_字段名
	
	//遍历这些字段进行数据存储
	string saveKeyName = "";
	FieldInfo info;
	for(int i = 0;i < infos.Length;i++)
	{
		//字段的类型:info.FieldType.Name
		//字段的名字:info.Name
		info = infos[i];//得到具体的字段信息
		saveKeyName = keyName + "_" + dataType.Name + "_" + info.FieldType.Name + "_" + info.Name;
		//封装一个方法进行存储
		//获取值:info.GetValue(data)
		SaveValue(info.GetValue(data),saveKeyName);
	}
}
private void SaveValue(object value,string keyName)
{
	//PlayerPrefs只支持3种类型存储
	//判断数据类型是什么类型,然后调用具体的方法来存储
	Type fieldType = value.GetType();
	if(fieldType == typeof(int))
	{
		PlayerPrefs.SetInt(keyName,(int)value);
	}
	else if(fieldType == typeof(float))
	{
		PlayerPrefs.SetFloat(keyName,(float)value);
	}
	else if(fieldType == typeof(string))
	{
		PlayerPrefs.SetString(keyName,value.ToString());
	}
	else if(fieldType == typeof(bool))
	{
		PlayerPrefs.SetInt(keyName,(bool)value ? 1 : 0);
	}
}

反射存储数据----List成员

private void SaveValue(object value,string keyName)
{
	//PlayerPrefs只支持3种类型存储
	//判断数据类型是什么类型,然后调用具体的方法来存储
	Type fieldType = value.GetType();
	if(fieldType == typeof(int))
	{
		PlayerPrefs.SetInt(keyName,(int)value);
	}
	else if(fieldType == typeof(float))
	{
		PlayerPrefs.SetFloat(keyName,(float)value);
	}
	else if(fieldType == typeof(string))
	{
		PlayerPrefs.SetString(keyName,value.ToString());
	}
	else if(fieldType == typeof(bool))
	{
		PlayerPrefs.SetInt(keyName,(bool)value ? 1 : 0);
	}
	//判断字段是不是IList的子类
	else if(typeof(IList).IsAssignableFrom(fieldType))
	{
		//父类装子类
		IList list = value as IList;
		//先存储数量
		PlayerPrefs.SetInt(keyName,list.Count);
		//存储具体的值
		int index = 0;
		foreach(object obj in list)
		{
			SaveValue(obj,keyName + index);
			++index;
	}

反射存储数据----Dictionary成员

private void SaveValue(object value,string keyName)
{
	//PlayerPrefs只支持3种类型存储
	//判断数据类型是什么类型,然后调用具体的方法来存储
	Type fieldType = value.GetType();
	if(fieldType == typeof(int))
	{
		PlayerPrefs.SetInt(keyName,(int)value);
	}
	else if(fieldType == typeof(float))
	{
		PlayerPrefs.SetFloat(keyName,(float)value);
	}
	else if(fieldType == typeof(string))
	{
		PlayerPrefs.SetString(keyName,value.ToString());
	}
	else if(fieldType == typeof(bool))
	{
		PlayerPrefs.SetInt(keyName,(bool)value ? 1 : 0);
	}
	//判断字段是不是IList的子类
	else if(typeof(IList).IsAssignableFrom(fieldType))
	{
		//父类装子类
		IList list = value as IList;
		//先存储数量
		PlayerPrefs.SetInt(keyName,list.Count);
		//存储具体的值
		int index = 0;
		foreach(object obj in list)
		{
			SaveValue(obj,keyName + index);
			++index;
	}
	else if(typeof(IDictionary).IsAssignableFrom(fieldType))
	{
		IDictionary dic = value as IDictionary;
		//存字典长度
		PlayerPrefs.SetInt(keyName,dic.Count);
		//遍历存储Dic里面的具体值
		int index = 0;
		foreach(object key in dic)
		{
			SaveValue(key,keyName + "_key_" + index);
			SaveValue(dic[key],keyName + "_value_" + index);
			++index;
		}
	}

反射存储数据----自定义类成员

private void SaveValue(object value,string keyName)
{
	//PlayerPrefs只支持3种类型存储
	//判断数据类型是什么类型,然后调用具体的方法来存储
	Type fieldType = value.GetType();
	if(fieldType == typeof(int))
	{
		PlayerPrefs.SetInt(keyName,(int)value);
	}
	else if(fieldType == typeof(float))
	{
		PlayerPrefs.SetFloat(keyName,(float)value);
	}
	else if(fieldType == typeof(string))
	{
		PlayerPrefs.SetString(keyName,value.ToString());
	}
	else if(fieldType == typeof(bool))
	{
		PlayerPrefs.SetInt(keyName,(bool)value ? 1 : 0);
	}
	//判断字段是不是IList的子类
	else if(typeof(IList).IsAssignableFrom(fieldType))
	{
		//父类装子类
		IList list = value as IList;
		//先存储数量
		PlayerPrefs.SetInt(keyName,list.Count);
		//存储具体的值
		int index = 0;
		foreach(object obj in list)
		{
			SaveValue(obj,keyName + index);
			++index;
	}
	else if(typeof(IDictionary).IsAssignableFrom(fieldType))
	{
		IDictionary dic = value as IDictionary;
		//存字典长度
		PlayerPrefs.SetInt(keyName,dic.Count);
		//遍历存储Dic里面的具体值
		int index = 0;
		foreach(object key in dic)
		{
			SaveValue(key,keyName + "_key_" + index);
			SaveValue(dic[key],keyName + "_value_" + index);
			++index;
		}
	}
	else
	{
		SaveData(value,keyName);
	}

反射读取数据----常用成员

public object LoadData(Type type,string keyName)
{
	//根据你传入的Type,创建一个对象用于存储数据
	object data = Activator.CreateInstance(type);
	//得到所有字段
	FieldInfo[] infos = type.GetFields();
	//用于拼接key的字符串
	string loadKeyName = "";
	//用于存储单个字段信息的对象
	FieldInfo info;
	for(int i = 0;i < infos.Length;i++)
	{
		info = infos[i];
		//key的拼接规则一定是和存储时一模一样,这样才能找到对应数据
		loadKeyName = keyName + "_" + type.Name + "_" + info.FieldType.Name + "_" + info.Name;
		//有key就可以结合,PlayerPrefs来读取数据
		info.SetValue(data,LoadValue(info.FieldType,loadKeyName));
	}
	return data;
}
private object LoadValue(Type fieldType,string keyName)
{
	//根据字段类型判断用哪个API读取
	if(fieldType == typeof(int))
	{
		return PlayerPrefs.GetInt(keyName,0);
	}
	else if(fieldType == typeof(float))
	{
		return PlayerPrefs.GetFloat(keyName,0);
	}
	else if(fieldType == typeof(string))
	{
		return PlayerPrefs.GetString(keyName,"");
	}
	else if(fieldType == typeof(bool))
	{
		//自定义存储bool值规则
		return PlayerPrefs.GetInt(keyName,0) == 1 ? true : false;
	}
	return null;
}

反射读取数据----List成员

private object LoadValue(Type fieldType,string keyName)
{
	//根据字段类型判断用哪个API读取
	if(fieldType == typeof(int))
	{
		return PlayerPrefs.GetInt(keyName,0);
	}
	else if(fieldType == typeof(float))
	{
		return PlayerPrefs.GetFloat(keyName,0);
	}
	else if(fieldType == typeof(string))
	{
		return PlayerPrefs.GetString(keyName,"");
	}
	else if(fieldType == typeof(bool))
	{
		//自定义存储bool值规则
		return PlayerPrefs.GetInt(keyName,0) == 1 ? true : false;
	}
	else if(typeof(IList).IsAssignableFrom(fieldType))
	{
		//得到长度
		int count = PlayerPrefs.GetInt(keyName,0);
		//实例化一个List对象进行赋值
		IList list = Activator.CreateInstance(fieldType) as IList;
		for(int i = 0;i < count;i++)
		{
			//得到List中泛型的类型
			list.Add(LoadValue(fieldType.GetGenericArguments()[0],keyName + i));
		}
		return list;
	}
	return null;
}

反射读取数据----Dic成员

private object LoadValue(Type fieldType,string keyName)
{
	//根据字段类型判断用哪个API读取
	if(fieldType == typeof(int))
	{
		return PlayerPrefs.GetInt(keyName,0);
	}
	else if(fieldType == typeof(float))
	{
		return PlayerPrefs.GetFloat(keyName,0);
	}
	else if(fieldType == typeof(string))
	{
		return PlayerPrefs.GetString(keyName,"");
	}
	else if(fieldType == typeof(bool))
	{
		//自定义存储bool值规则
		return PlayerPrefs.GetInt(keyName,0) == 1 ? true : false;
	}
	else if(typeof(IList).IsAssignableFrom(fieldType))
	{
		//得到长度
		int count = PlayerPrefs.GetInt(keyName,0);
		//实例化一个List对象进行赋值
		IList list = Activator.CreateInstance(fieldType) as IList;
		for(int i = 0;i < count;i++)
		{
			//得到List中泛型的类型
			list.Add(LoadValue(fieldType.GetGenericArguments()[0],keyName + i));
		}
		return list;
	}
	else if(typeof(IDictionary).IsAsssignableFrom(fieldType))
	{
		//得到字典的长度
		int count = PlayerPrefs.GetInt(keyName,0);
		//实例化一个字典对象,用父类装子类
		IDictionary dic = Activator.CreateInstance(fieldType);
		Type[] kvType = fieldType.GetGenericArguments();
		for(int i = 0;i < count;i++)
		{
			dic.Add(LoadValue(kvType[0],keyName + "_key_" + i),LoadValue(kvType[1],keyName + "_value_" + i));
		}
		return dic;
	}
	return null;
}

反射读取数据----自定义类成员

private object LoadValue(Type fieldType,string keyName)
{
	//根据字段类型判断用哪个API读取
	if(fieldType == typeof(int))
	{
		return PlayerPrefs.GetInt(keyName,0);
	}
	else if(fieldType == typeof(float))
	{
		return PlayerPrefs.GetFloat(keyName,0);
	}
	else if(fieldType == typeof(string))
	{
		return PlayerPrefs.GetString(keyName,"");
	}
	else if(fieldType == typeof(bool))
	{
		//自定义存储bool值规则
		return PlayerPrefs.GetInt(keyName,0) == 1 ? true : false;
	}
	else if(typeof(IList).IsAssignableFrom(fieldType))
	{
		//得到长度
		int count = PlayerPrefs.GetInt(keyName,0);
		//实例化一个List对象进行赋值
		IList list = Activator.CreateInstance(fieldType) as IList;
		for(int i = 0;i < count;i++)
		{
			//得到List中泛型的类型
			list.Add(LoadValue(fieldType.GetGenericArguments()[0],keyName + i));
		}
		return list;
	}
	else if(typeof(IDictionary).IsAsssignableFrom(fieldType))
	{
		//得到字典的长度
		int count = PlayerPrefs.GetInt(keyName,0);
		//实例化一个字典对象,用父类装子类
		IDictionary dic = Activator.CreateInstance(fieldType);
		Type[] kvType = fieldType.GetGenericArguments();
		for(int i = 0;i < count;i++)
		{
			dic.Add(LoadValue(kvType[0],keyName + "_key_" + i),LoadValue(kvType[1],keyName + "_value_" + i));
		}
		return dic;
	} 
	else 
	{
		return LoadData(fieldType,keyName);
	}
	return null;
}

加密思路

找不到
1、把存在硬盘上的内容放在一个不容易找到的地方
2、多层文件夹包裹
3、名字辨识度低
但是对于PlayerPrefs不太适用,因为位置已经固定了,改不了。
看不懂
让数据的key和value让别人看不懂,俗称加密,为key和value加密。
解不出
不让别人获取到你加密的规则。
注意: 单机游戏加密只是提高别人修改你数据的门槛,只要别人获取到你的源代码,知道你的加密规则,一切都没有任何意义。但是对于一般玩家来说几乎是不可能的事情。

生成资源包

Unity数据持久化之PlayerPrefs,Unity项目,unity,游戏引擎,数据存储与读取
Unity数据持久化之PlayerPrefs,Unity项目,unity,游戏引擎,数据存储与读取文章来源地址https://www.toymoban.com/news/detail-827933.html

到了这里,关于Unity数据持久化之PlayerPrefs的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Unity学习日记03】数据持久化

    这一篇只能说写了一部分,并没有把Unity里数据持久化的操作讲完整,之后可能是学到一点就记一点的模式。 数据持久化就是将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型的统称。 人话版:将游戏数据存储到硬盘,硬盘中数据读取到游戏中,

    2024年02月12日
    浏览(53)
  • Unity之数据持久化——Json

    JavaScript对象简谱(JavaScript Object Notation) json是国际通用的一种轻量级的数据交换格式,主要在网络通讯中用于传输数据,或本地数据存储和读取,易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率 游戏中可以把游戏数据按照Json的格式标准存储在

    2023年04月20日
    浏览(40)
  • Unity学习笔记--数据持久化Json

    json是国际通用语言,可以跨平台(游戏,软件,网页,不同OS)使用, json语法较为简单,使用更广泛。json使用键值对来存储。 认识json文件 //注意字典类型存储时,键是以string类型存储的 需要添加 “” Excel转换为JSON文件: 使用网站来转换:bejson 挖坑-----》开发一个工具,

    2024年02月05日
    浏览(52)
  • 【Unity】数据持久化路径Application.persistentDataPath

    今天突然想到这个路径Application.persistentDataPath,热更的重要路径,该文件夹可读可写,在移动端唯一一个可读写操作的文件夹。 移动端可以将本地的资源(资源MD5值配置表)等一些文件放到StreamingAssets文件夹下,通过Copy到persistentDataPath下与服务器的版本文件配置表作比对,

    2023年04月10日
    浏览(51)
  • Unity学习笔记--数据持久化XML文件(1)

    Xml是可拓展标记语言,一种文件格式。我们使用xml来完成对数据持久化的存储。等待我们有一程序运行结束之后,将内存中的数据进行保存,(保存在硬盘/服务器)实现对数据的持久化存储。 xml文件的读取和保存以及修改 要点: XMl文件的加载 XML文件节点的查找访问 XML文件

    2024年02月05日
    浏览(44)
  • Unity笔记:数据持久化的几种方式

    主要方法: ScriptableObject PlayerPrefs JSON XML 数据库(如Sqlite) PlayerPrefs 存储的数据是 全局共享 的,它们存储在用户设备的本地存储中,并且可以被应用程序的所有部分访问。这意味着,无论在哪个场景、哪个脚本中,只要是同一个应用程序中的代码,都可以读取和修改 Playe

    2024年02月19日
    浏览(44)
  • 【unity数据持久化】XML数据管理器知识点

    👨‍💻个人主页 :@元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 收录于专栏 :Unity基础实战 XML是什么 XML(Extensible Markup Language)是一种类似于 HTML,但是没有使用预定义标记的语言。因此,可以根据自己的设计需求

    2024年02月11日
    浏览(41)
  • 【unity数据持久化】数据管理类_PlayerPrfs封装包

    👨‍💻个人主页 :@元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 收录于专栏 : unity数据存储 🎶 PlayerPrefs—存储主方法 🎶 PlayerPrefs—普通数据类型的反射存储 🎶 PlayerPrefs—泛型List的反射存储 🎶 PlayerPrefs—泛型

    2024年02月12日
    浏览(34)
  • Unity3D学习之数据持久化——XML

    最终达到的效果 树形结构 属性通过空格隔开 属性名 = 引导包裹的内容 这两个代表的东西是一样的 可以在菜鸟上使用xml验证器 xml验证器 在Resources文件夹创建一个xml文件 把文件再复制到streamingAsserts 3.2.1 通过Resources文件进行读取 3.2.2 通过xml文件进行加载 获取根节点 遍历同名

    2024年01月23日
    浏览(45)
  • 【Unity】二进制文件 数据持久化(修改版)【个人复习笔记/有不足之处欢迎斧正/侵删】

             变量的本质都是二进制 ,在内存中都以字节的形式存储着,通过sizeof方法可以看到常用变量类型占用的字节空间长度( 1byte = 8bit,1bit(位)不是0就是1 )         二进制文件读写的本质: 将各类型变量转换为字节数组,将字节数组直接存储到文件中 ,不仅可以节

    2024年04月17日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包