資料持久化
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 儲存在 HKCU\Software[公司名稱][產品名稱] 項下的登錄檔中
其中公司和產品名稱是 在“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]);
}
}
}