数据持久化-PlayerPrefs

87 阅读2分钟

一、基础方法

1、介绍持久化

image.png

将内存中的数据存储到硬盘中。

2、PalyerPrefs是一个存储玩家数据的公共类。

3、存储相关

image.png

键是唯一的,即使是存储不同类型的。

4、读取相关

image.png

取值和其参数介绍:

image.png

第二个参数是用来赋予默认值的。并不会存储到硬盘中。

判断是否存在该键:

image.png

删除数据

image.png

练习题:

image.png

using System.Collections;
using System.Collections.Generic;
using System.Xml.Linq;
using Unity.VisualScripting;
using UnityEngine;

public class Player
{
    public string name1;
    public int age;
    public int atk;
    public int def;
    public List<Equip> equips;
    public void SaveData()
    {
        PlayerPrefs.SetString("name", this.name1);
        PlayerPrefs.SetInt("age", this.age);
        PlayerPrefs.SetInt("atk", this.atk);
        PlayerPrefs.SetInt("def", this.def);
        PlayerPrefs.SetInt("equipsSum", equips.Count);
        for (int i = 0; i < equips.Count; i++)
        {
            PlayerPrefs.SetInt($"equipId{i}", equips[i].id);
            PlayerPrefs.SetInt($"equipNum{i}", equips[i].num);
        }
        PlayerPrefs.Save();
    }

    public void ReadData()
    {
        name1 = PlayerPrefs.GetString("name", "未知名称");
        age = PlayerPrefs.GetInt("age", 20);
        atk = PlayerPrefs.GetInt("atk", 1);
        def = PlayerPrefs.GetInt("def", 1);
        int sum = PlayerPrefs.GetInt("equipsSum", 0);
        equips = new List<Equip>();
        for(int i = 0; i < sum; i++)
        {
            Equip equip = new Equip();
            equip.id = PlayerPrefs.GetInt($"equipId{i}", 0);
            equip.num = PlayerPrefs.GetInt($"equipNum{i}", 0);
            equips.Add(equip);
        }
    }
    // 重写ToString方法以便更好地打印Player信息
    public override string ToString()
    {
        return $"玩家{name1}({age}岁)目前攻击力:{atk},防御力:{def},拥有{equips.Count}种装备";
    }
}

public class Player1 : MonoBehaviour
{
    private void Start()
    {
        Player p1 = new Player();
        p1.ReadData();
        print(p1.ToString());
        print(p1.equips.Count );
        print($"7777玩家{p1.name1}({p1.age}岁)目前攻击力:{p1.atk},防御力:{p1.def}");
        for (int i = 0; i < p1.equips.Count; i++)
        {
            print($"拥有装备{p1.equips[i].id}共{p1.equips[i].num}件");
        }
        p1.name1 = "战神";
        p1.age = 88;
        p1.def = 7;
        
        p1.atk = 7;
        Equip e1 = new Equip();
        e1.id = 1;
        e1.num = 1;
        p1.equips.Add(e1);
        p1.SaveData();
    }
}

public class Equip
{
    public int id;
    public int num;
}

二、存储位置

1、不同平台位置:

windows:

image.png

Android:

image.png

IOS:

image.png

2、保证数据不重复

image.png

PlayerPrefs主要作用

image.png

三、反射复习

ISAssignableFrom用于判断调用者是否可以使用传入参数分配空间。 CreateInstance用于创建实例

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class Fa
{

}
public class Son : Fa
{

}

public class P : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Type fa = typeof(Fa);
        Type son = typeof(Son);
        if (fa.IsAssignableFrom(son))
        {
            print("可以分配");
            Fa fa1 = Activator.CreateInstance(son) as Fa;
            print(fa1);
        }
    }
}

GetGenericArguments用于获取泛型类型

image.png

四、PlayerPrefs拓展练习

using System.Collections;
using System.Collections.Generic;
using System.Xml.Linq;
using Unity.VisualScripting;
using UnityEngine;

public class Player
{
    public string keyName;
    public string name1;
    public int age;
    public int atk;
    public int def;
    public List<Equip> equips = new List<Equip>();
    public Dictionary<string, string> skillExplain = new Dictionary<string, string>();
    
}

public class Equip
{
    public int id;
    public string equipName;
    public Equip()
    {

    }
    public Equip(int id, string equipName)
    {
        this.id = id;
        this.equipName = equipName;
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using static UnityEditor.LightingExplorerTableColumn;

public class PlayerPrefsData
{
    //使用单例模式
    private static PlayerPrefsData prefsData = new PlayerPrefsData();
    public static PlayerPrefsData PrefsData { get { return prefsData; } }
    private PlayerPrefsData()
    {
    }
    //存储
    public void Save(object data, string keyName)
    {
        Type dataType = data.GetType();
        FieldInfo[] dataInfo = dataType.GetFields();
        string saveKeyname = "";
        foreach (FieldInfo fieldInfo in dataInfo)
        {
            saveKeyname = $"{keyName}_{dataType.Name}_{fieldInfo.FieldType.Name}_{fieldInfo.Name}";
            SaveFunc(saveKeyname, fieldInfo.GetValue(data));
        }
    }
    //存储方法:
    private void SaveFunc(string keyName, object value)
    {
        Type type = value.GetType();
        if (type == typeof(string))
        {
            PlayerPrefs.SetString($"{keyName}", value.ToString());
        }
        else if (type == typeof(int))
        {
            PlayerPrefs.SetInt($"{keyName}", (int)value);
        }
        else if (type == typeof(float))
        {
            PlayerPrefs.SetFloat($"{keyName}", (float)value);
        }
        //判断该类型是否是IList的子类,因为List继承了IList
        else if (typeof(IList).IsAssignableFrom(type))
        {
            Debug.Log("打印List");
            IList valueIList = value as IList;
            int index = 0;
            PlayerPrefs.SetInt(keyName, valueIList.Count);
            foreach (object obj in valueIList)
            {
                SaveFunc(keyName + index, obj);
                index++;
            }
        }
        else if (typeof(IDictionary).IsAssignableFrom(type))
        {
            Debug.Log("打印Dictionary");
            IDictionary valueIDictionary = value as IDictionary;
            int index = 0;
            PlayerPrefs.SetInt(keyName, valueIDictionary.Count);//存储长度方便读取
            foreach (object key in valueIDictionary.Keys)
            {
                SaveFunc(keyName + index + "_Key", key);
                SaveFunc(keyName + index + "_Value", valueIDictionary[key]);
                index++;
            }
        }
        else
        {
            Save(value, keyName);
        }
        Debug.Log($"{keyName}:{value}");
    }
    //读取
    public object Load(string keyName, Type type)
    {
        FieldInfo[] fieldInfos = type.GetFields();
        string loadKeyname = "";
        object data = Activator.CreateInstance(type);
        foreach (FieldInfo fieldInfo in fieldInfos)
        {
            loadKeyname = $"{keyName}_{type.Name}_{fieldInfo.FieldType.Name}_{fieldInfo.Name}";
            fieldInfo.SetValue(data, LoadFunc(loadKeyname, fieldInfo.FieldType));
        }
        return data;
    }
    public object LoadFunc(string loadKeyname, Type fieldInfoType)
    {
        if (fieldInfoType == typeof(int))
        {
            return PlayerPrefs.GetInt(loadKeyname, -1);
        }
        else if (fieldInfoType == typeof(float))
        {
            return PlayerPrefs.GetFloat(loadKeyname, -1.0f);
        }
        else if (fieldInfoType == typeof(string))
        {
            return PlayerPrefs.GetString(loadKeyname, "未赋值");
        }
        else if (typeof(IList).IsAssignableFrom(fieldInfoType))
        {
            Debug.Log("读取List");
            int count = PlayerPrefs.GetInt(loadKeyname, 0);
            if (count == 0)
            {
                return null;
            }
            IList lists = Activator.CreateInstance(fieldInfoType) as IList;
            for (int i = 0; i < count; i++)
            {
                lists.Add(LoadFunc(loadKeyname + i, fieldInfoType.GetGenericArguments()[0]));
            }
            return lists;
        }
        else if (typeof(IDictionary).IsAssignableFrom(fieldInfoType))
        {
            Debug.Log("读取Dictionary");
            int count = PlayerPrefs.GetInt(loadKeyname, 0);
            if (count == 0)
            {
                return null;
            }
            IDictionary dictionary = Activator.CreateInstance(fieldInfoType) as IDictionary;
            for (int i = 0; i < count; i++)
            {
                dictionary.Add(LoadFunc(loadKeyname + i + "_Key", fieldInfoType.GetGenericArguments()[0]), LoadFunc(loadKeyname + i + "_Value", fieldInfoType.GetGenericArguments()[1]));
            }
            return dictionary;
        }
        else
        {
            return Load(loadKeyname, fieldInfoType);
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class P : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        //Player player = new Player();
        //player.keyName = "player1";
        //player.name1 = "阿龙";
        //player.age = 20;
        //player.atk = 10;
        //player.def = 2;
        //List<Equip> equipList = new List<Equip> { new Equip(1, "木剑"), new Equip(2, "铁斧") };
        //player.skillExplain = new Dictionary<string, string> { { "半月斩", "弧线的一次斩击" }, {"鞑靼牛肉", "你可以使用生牛肉"} };
        //player.equips.AddRange(equipList);
        //PlayerPrefsData.PrefsData.Save(player, player.keyName);
        Player player1 = PlayerPrefsData.PrefsData.Load("player1", typeof(Player)) as Player;
    }
    private void Update()
    {
        
    }
}