1.描述

在游戏会话之间存储和访问玩家的偏好。

Editor/Standalone 

在macOS PlayerPrefs上存储在/librar/preferences文件夹中,在一个名为unity.[company name].[product name].plist。在项目设置中设置名称的公司和产品名称。同样的,plist文件用于在编辑器和独立播放器中运行的两个项目。

在Windows上,PlayerPrefs被存储在HKCU\Software\[company name]\[product name] key中,公司和产品名称是在项目设置中设置的名称。

在Linux上,PlayerPrefs可以在/中找到。配置/unity3d/CompanyName/ProductName再次使用在项目设置中指定的公司和产品名称。

在Windows Store应用程序中,玩家Prefs可以在%\AppData\Local\Packages\[ProductPackageId]>\LocalState\playerprefs.dat中找到。

在Windows Phone 8上,玩家Prefs可以在应用程序的本地文件夹中找到,See Also: Directory.localFolder

Android数据在设备上存储(持久化)。数据保存在SharedPreferences中。c/JavaScript、Android Java和本机代码都可以访问PlayerPrefs数据。PlayerPrefs数据物理存储在/data/data/pkg-name/shared_prefs/pkg-name.xml。

在WebGL上,PlayerPrefs是使用浏览器的IndexedDB API存储的。

在iOS上,PlayerPrefs被存储在 /Library/Preferences/[bundle identifier].plist.

2.静态方法


DeleteAll

从偏好中删除所有的键和值。谨慎使用。

DeleteKey

从偏好中删除键及其对应值。

GetFloat

如果存在的话,返回首选项文件中的键值。

GetInt

如果存在的话,返回首选项文件中的键值。

GetString

如果存在的话,返回首选项文件中的键值。

HasKey

如果钥匙存在于偏好中,则返回true。

Save

将所有修改后的首选项写入磁盘。

SetFloat

设置由键识别的首选项的值。

SetInt

设置由键识别的首选项的值。

SetString

设置由键识别的首选项的值。

3.使用方法

 保存:      

PlayerPrefs.SetInt("MusicOn", 1);
PlayerPrefs.Save();

注意,如果是第一次进入游戏,在保存之前有可能就要访问,因此最好在Awake方法里面判断keys存不存在且保存其默认值:

PlayerPrefs.HasKey("MusicOn") //判断是否有没有keys
PlayerPrefs.GetInt("MusicOn",0) //得到keys的值,如果不存在则会返回默认值0

4.存档方法

当我们存储的数据是一个复杂对象时,采用PlayerPrefs显然已经不满足我们的需求,接着我们来看以下几种存档方式

首先我们要存储的数据类型如下:

[System.Serializable]
public class Save{

    public List<int> livingTargetPositions = new List<int>();
    public List<int> livingMonsterTypes = new List<int>();

    public int shootNum = 0;
    public int score = 0;
}

①.二进制存档与读档

存档:

private void SaveByBin()
    {
        //序列化过程(将Save对象转换为字节流)
        //创建Save对象并保存当前游戏状态
        Save save = CreateSaveGO();
        //创建一个二进制格式化程序
        BinaryFormatter bf = new BinaryFormatter();
        //创建一个文件流
        FileStream fileStream = File.Create(Application.dataPath + "/StreamingFile" + "/byBin.txt");
        //用二进制格式化程序的序列化方法来序列化Save对象,参数:创建的文件流和需要序列化的对象
        bf.Serialize(fileStream, save);
        //关闭流
        fileStream.Close();

        //如果文件存在,则显示保存成功
        if (File.Exists(Application.dataPath + "/StreamingFile" + "/byBin.txt"))
        {
            UIManager._instance.ShowMessage("保存成功");
        }
    }

读档:

private void LoadByBin()
    {
        if(File.Exists(Application.dataPath + "/StreamingFile" + "/byBin.txt"))
        {
            //反序列化过程
            //创建一个二进制格式化程序
            BinaryFormatter bf = new BinaryFormatter();
            //打开一个文件流
            FileStream fileStream = File.Open(Application.dataPath + "/StreamingFile" + "/byBin.txt", FileMode.Open);
            //调用格式化程序的反序列化方法,将文件流转换为一个Save对象
            Save save = (Save)bf.Deserialize(fileStream);
            //关闭文件流
            fileStream.Close();

            SetGame(save);
            UIManager._instance.ShowMessage("");
        }
        else
        {
            UIManager._instance.ShowMessage("存档文件不存在");
        }
    }

②.Xml存档与读档

存档:

private void SaveByXml()
    {
        Save save = CreateSaveGO();
        //创建XML文件的存储路径
        string filePath = Application.dataPath + "/StreamingFile" + "/byXML.txt";
        //创建XML文档
        XmlDocument xmlDoc = new XmlDocument();
        //创建根节点,即最上层节点
        XmlElement root = xmlDoc.CreateElement("save");
        //设置根节点中的值
        root.SetAttribute("name", "saveFile1");

        //创建XmlElement
        XmlElement target;
        XmlElement targetPosition;
        XmlElement monsterType;

        //遍历save中存储的数据,将数据转换成XML格式
        for(int i = 0; i < save.livingTargetPositions.Count; i++)
        {
            target = xmlDoc.CreateElement("target");
            targetPosition = xmlDoc.CreateElement("targetPosition");
            //设置InnerText值
            targetPosition.InnerText = save.livingTargetPositions[i].ToString();
            monsterType = xmlDoc.CreateElement("monsterType");
            monsterType.InnerText = save.livingMonsterTypes[i].ToString();

            //设置节点间的层级关系 root -- target -- (targetPosition, monsterType)
            target.AppendChild(targetPosition);
            target.AppendChild(monsterType);
            root.AppendChild(target);
        }

        //设置射击数和分数节点并设置层级关系  xmlDoc -- root --(target-- (targetPosition, monsterType), shootNum, score)
        XmlElement shootNum = xmlDoc.CreateElement("shootNum");
        shootNum.InnerText = save.shootNum.ToString();
        root.AppendChild(shootNum);

        XmlElement score = xmlDoc.CreateElement("score");
        score.InnerText = save.score.ToString();
        root.AppendChild(score);

        xmlDoc.AppendChild(root);
        xmlDoc.Save(filePath);

        if(File.Exists(Application.dataPath + "/StreamingFile" + "/byXML.txt"))
        {
            UIManager._instance.ShowMessage("保存成功");
        }
    }

读档:

private void LoadByXml()
    {
        string filePath = Application.dataPath + "/StreamingFile" + "/byXML.txt";
        if(File.Exists(filePath))
        {
            Save save = new Save();
            //加载XML文档
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(filePath);

            //通过节点名称来获取元素,结果为XmlNodeList类型
            XmlNodeList targets = xmlDoc.GetElementsByTagName("target");
            //遍历所有的target节点,并获得子节点和子节点的InnerText
            if(targets.Count != 0)
            {
                foreach(XmlNode target in targets)
                {
                    XmlNode targetPosition = target.ChildNodes[0];
                    int targetPositionIndex = int.Parse(targetPosition.InnerText);
                    //把得到的值存储到save中
                    save.livingTargetPositions.Add(targetPositionIndex);

                    XmlNode monsterType = target.ChildNodes[1];
                    int monsterTypeIndex = int.Parse(monsterType.InnerText);
                    save.livingMonsterTypes.Add(monsterTypeIndex);
                }
            }
            
            //得到存储的射击数和分数
            XmlNodeList shootNum = xmlDoc.GetElementsByTagName("shootNum");
            int shootNumCount = int.Parse(shootNum[0].InnerText);
            save.shootNum = shootNumCount;

            XmlNodeList score = xmlDoc.GetElementsByTagName("score");
            int scoreCount = int.Parse(score[0].InnerText);
            save.score = scoreCount;

            SetGame(save);
            UIManager._instance.ShowMessage("");

        }
        else
        {
            UIManager._instance.ShowMessage("存档文件不存在");
        }
    }

③.Json存档与读档

存档:

private void SaveByJson()
    {
        Save save = CreateSaveGO();
        string filePath = Application.dataPath + "/StreamingFile" + "/byJson.json";
        //利用JsonMapper将save对象转换为Json格式的字符串
        string saveJsonStr = JsonMapper.ToJson(save);
        //将这个字符串写入到文件中
        //创建一个StreamWriter,并将字符串写入文件中
        StreamWriter sw = new StreamWriter(filePath);
        sw.Write(saveJsonStr);
        //关闭StreamWriter
        sw.Close();

        UIManager._instance.ShowMessage("保存成功");
    }

读档:

private void LoadByJson()
    { 
        string filePath = Application.dataPath + "/StreamingFile" + "/byJson.json";
        if(File.Exists(filePath))
        {
            //创建一个StreamReader,用来读取流
            StreamReader sr = new StreamReader(filePath);
            //将读取到的流赋值给jsonStr
            string jsonStr = sr.ReadToEnd();
            //关闭
            sr.Close();

            //将字符串jsonStr转换为Save对象
            Save save = JsonMapper.ToObject<Save>(jsonStr);
            SetGame(save);
            UIManager._instance.ShowMessage("");
        }
        else
        {
            UIManager._instance.ShowMessage("存档文件不存在");
        }
    }

5.Unity中JsonUtility对List<T>和Dictionary<Key,Value>的序列化

          (只针对于key与value都是基本类型才有用)