Unity-BattleStar丨12. 让数据更流畅:数据存储与性能优化

2024-08-14 16:40:34 浏览数 (1)

本章目标

完成BattleStar的数据存储与性能优化

导入资源文件

文件下载:地址

1、导入Package

2、运行_Scenes里面的BattleStar_GameScene场景,观察

BattleStar的数据存储

将BattleStar_GuideScene加载到build settings里,否则运行时会出现无法切换场景的现象。

Debug描述如下:

Scene 'BattleStar_GuideScene' couldn't be loaded because it has not been added to the build settings or the AssetBundle has not been loaded.

To add a scene to the build settings use the menu File->Build Settings...

1、PlayerPrefs

由于在场景切换的时候,脚本内的参数会被重置的,因此需要将玩家在游戏中剩余时间以某种方式保存起来,并传输到下一场景。在这个过程中,我们用PlayerPrefs完成游戏过程中游戏分数的数据存储功能

在Player中增加如下代码

代码语言:javascript复制
using UnityEngine;
using UnityEngine.UI;

public class Player : MonoBehaviour
{
    [SerializeField] private Text healthText;
    [SerializeField] private GameManager manager;

    public GameObject RestTineText;

    int time;

    AudioSource AS;

    int playerHealth = 5;

    public int PlayerHealth
    {
        get { return playerHealth; }
        set
        {
            playerHealth = value;

            healthText.text = playerHealth.ToString();

            if (playerHealth == 0)
            {
                PlayerDie();
            }
        }
    }

    private void Start()
    {
        AS = GameObject.Find("Audio Source").GetComponent<AudioSource>();
    }

    //死亡(游戏结束)
    private void PlayerDie()
    {
        time = int.Parse(RestTineText.GetComponent<Text>().text);
        PlayerPrefs.SetInt("RestTime", time);
        Debug.Log(PlayerPrefs.GetInt("RestTime"));
        manager.GameOver();
    }

    public void playGetHurt()
    {
        PlayerHealth--;
        AS.clip = (AudioClip)Resources.Load("PlayerGetHurt");
        AS.Play();
    }
}

我们看到,在玩家死亡时,该代码调用了manager.GameOver()方法。通过Unity找到该代码,我们看到该方法如下

代码语言:javascript复制
private bool gameOver;

    void Start()
    {
        gameOver = false;

        //锁定鼠标位置并设置为不可见
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;
    }
    
    public void GameOver()
    {
        //如果游戏尚未结束
        if (!gameOver)
        {
            SceneManager.LoadScene("BattleStar_GuideScene");
        }
    } 

因此我们进入BattleStar_GuideScene场景,Menu的List是所有Record的集合,我们给他增添一个代码,用于读取场景切换之前保存在注册表里的数据

代码语言:javascript复制
using UnityEngine;
using UnityEngine.UI;

public class ListTime : MonoBehaviour {

    public GameObject Timetext;
    
	void Start () {
        Timetext.GetComponent<Text>().text = PlayerPrefs.GetInt("RestTime").ToString();
    }
}

2、Xml

Xml文件用来存储姓名、成绩等信息,下面展示一种单纯Xml API格式编写的脚本代码,和用LINQ to XML API格式代码

Xml格式
代码语言:javascript复制
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.IO;
using System.Xml;

//实现每次游戏胜利排行榜排序并写入的顺序:1、创建Xml文件—>{2、运行游戏胜利时添加数据到xml文件—>
//3、导出数据到List<Rank>集合(先将List原数据清空),并进行排序—>4、写入排行榜}(每次胜利添加名字时运行一次)

public class Xml_Skode : MonoBehaviour
{
    List<Rank> timeRank = new List<Rank>();
    public GameObject recordParent;
    public Text nameText;
    string filepath1, filepath2;

    private void Start()
    {
        filepath1 = Application.dataPath   @"myRank_Skode.xml";
        filepath2 = @"C:/Users/Administrator/Desktop/myRank_Skode.xml";
        CreatXml();
    }

    //创建Xml文件
    void CreatXml()
    {
        if (!File.Exists(filepath1))
        {
            XmlDocument xmlDoc = new XmlDocument();
            XmlElement userData = xmlDoc.CreateElement("userData");
            xmlDoc.AppendChild(userData);

            xmlDoc.Save(filepath1);
        }
    }

    XmlDocument xmlDoc = new XmlDocument();

    public void UpdateXml_Skode()  //添加数据。该方法绑定在取得游戏胜利输入名字的“确定”按键上
    {
        xmlDoc.Load(filepath1);
        XmlNode userData = xmlDoc.SelectSingleNode("userData");
        XmlElement rank = xmlDoc.CreateElement("rank");
        XmlElement userName = xmlDoc.CreateElement("name");
        XmlElement userTime = xmlDoc.CreateElement("time");

        userName.InnerText = nameText.text;   //InnerText为标签之间的纯文本信息
        userTime.InnerText = PlayerPrefs.GetInt("RestTime").ToString();

        xmlDoc.AppendChild(userData);
        userData.AppendChild(rank);
        rank.AppendChild(userName);
        rank.AppendChild(userTime);

        xmlDoc.Save(filepath1);

        outXmlToList();
    }

    //导出xml数据到List
    void outXmlToList()
    {
        timeRank.Clear();  //因为每次胜利输入名字时都要在timeRank中写入数据,所以要先清空上次留下的数据,再执行本次命令

        XmlNodeList userData = xmlDoc.SelectSingleNode("userData").ChildNodes;

        string userInfo_Name = null;   //用于承载遍历Xml得出的信息,将其写入新的timeRank集合
        int userInfo_Time = 0;

        foreach (XmlElement rankList in userData)  //遍历所有rank节点
        {
            foreach (XmlElement userInfo in rankList)  //遍历每个rank节点下的name、time信息
            {
                if (userInfo.Name == "name")
                {
                    userInfo_Name = userInfo.InnerText;
                }
                else    //rank节点下一共两个标签,分别是name和time
                {
                    //userInfo_Time = Convert.ToInt32(userInfo.InnerText);   //using System;
                    userInfo_Time = int.Parse(userInfo.InnerText);
                }
            }
            Rank iRank = new Rank(userInfo_Name, userInfo_Time);
            timeRank.Add(iRank);
        }
        TimeSort();
    }


    //给timeRank中的元素排序
    void TimeSort()
    {
        for (int i = timeRank.Count; i > 1; i--)  //循环,不断将最小的数字向后排。10个数字,进行9次排序就够了
        {
            for (int j = 0; j < i - 1; j  )   //本次循环将最小的时间数字排到最后面(前面的数字还是乱的)
            {
                if (timeRank[j].time < timeRank[j   1].time)
                {
                    Rank temp;

                    temp = timeRank[j];
                    timeRank[j] = timeRank[j   1];
                    timeRank[j   1] = temp;
                }
            }
        }

        WriteList();
    }

    //将成绩写入排行榜
    void WriteList()
    {
        Text noText, nameText, timeText;

        if (timeRank.Count > 10)
        {
            for (int i = 1; i < 11; i  )
            {
                GameObject gObject = GameObject.Find("Record ("   i.ToString()   ")");

                #region  给排名序号赋值
                noText = gObject.transform.Find("NumberText").GetComponent<Text>();
                if (i < 10)
                {
                    noText.text = 0.ToString()   i.ToString();
                }
                else
                    noText.text = i.ToString();
                #endregion

                #region 给Nmae赋值
                nameText = gObject.transform.Find("NameText").GetComponent<Text>();
                nameText.text = timeRank[i - 1].name;
                #endregion

                #region 给Time赋值
                timeText = gObject.transform.Find("TimeText").GetComponent<Text>();
                timeText.text = timeRank[i - 1].time.ToString();
                #endregion
            }
        }
        else
        {
            for (int i = 0; i < timeRank.Count; i  )  //i不能等于1,如果等于1,当只有一个成绩时,排行榜就不会显示
            {
                GameObject gObject = GameObject.Find("Record ("   (i 1).ToString()   ")");

                #region  给排名序号赋值
                noText = gObject.transform.Find("NumberText").GetComponent<Text>();
                if (i < 9)
                {
                    noText.text = 0.ToString()   (i 1).ToString();
                }
                else
                    noText.text = (i   1).ToString();
                #endregion

                #region 给Nmae赋值
                nameText = gObject.transform.Find("NameText").GetComponent<Text>();
                if (nameText != null)
                    Debug.Log("find name"); 
                nameText.text = timeRank[i].name;
                #endregion

                #region 给Time赋值
                timeText = gObject.transform.Find("TimeText").GetComponent<Text>();
                timeText.text = timeRank[i].time.ToString();
                #endregion
            }
        }
    }
}
LINQ to XML API格式
代码语言:javascript复制
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.IO;
using System.Linq;
using System.Xml.Linq;

public class Xml_Skode2 : MonoBehaviour
{
    List<Rank> timeRank = new List<Rank>();
    public GameObject recordParent;
    public Text nameText;
    string filepath1, filepath2;

    private void Start()
    {
        filepath1 = Application.dataPath   @"myRank_Skode2.xml";
        filepath2 = @"C:/Users/Administrator/Desktop/myRank_Skode.xml";
        CreatXml();
    }

    //创建Xml文件
    void CreatXml()
    {
        if (!File.Exists(filepath1))
        {
            XDocument xDoc = new XDocument(
                new XElement("userData"));
            xDoc.Save(filepath1);
        }
    }

    public void UpdateXml_Skode()  //添加数据。该方法绑定在取得游戏胜利输入名字的“确定”按键上
    {
        XDocument xDoc = XDocument.Load(filepath1);
        XElement userData = xDoc.Element("userData");
        userData.Add(new XElement("rank",
            new XElement("name", nameText.text),
            new XElement("time", PlayerPrefs.GetInt("RestTime").ToString())
            )
            );

        xDoc.Save(filepath1);

        outXmlToList();
    }

    //导出xml数据到List
    void outXmlToList()
    {
        timeRank.Clear();

        XDocument xDoc = XDocument.Load(filepath1);
        IEnumerable<XElement> userData = xDoc.Element("userData").Elements();

        string userInfo_Name = null;
        int userInfo_Time = 0;

        var rankList = from a in userData
                       select a;

        foreach (var b in rankList)  //rank层
        {
            foreach (var c in b.Elements())   //name、time层
            {
                if (c.Name == "name")
                {
                    userInfo_Name = c.Value;
                }
                else
                {
                    userInfo_Time = int.Parse(c.Value);
                }
            }

            Rank iRank = new Rank(userInfo_Name, userInfo_Time);
            timeRank.Add(iRank);
        }
        TimeSort();
    }


    //给timeRank中的元素排序
    void TimeSort()
    {
        for (int i = timeRank.Count; i > 1; i--)
        {
            for (int j = 0; j < i - 1; j  )
            {
                if (timeRank[j].time < timeRank[j   1].time)
                {
                    Rank temp;

                    temp = timeRank[j];
                    timeRank[j] = timeRank[j   1];
                    timeRank[j   1] = temp;
                }
            }
        }

        WriteList();
    }

    //将成绩写入排行榜
    void WriteList()
    {
        Text noText, nameText, timeText;

        if (timeRank.Count > 10)
        {
            for (int i = 1; i < 11; i  )
            {
                GameObject gObject = GameObject.Find("Record ("   i.ToString()   ")");

                #region  给排名序号赋值
                noText = gObject.transform.Find("NumberText").GetComponent<Text>();
                if (i < 10)
                {
                    noText.text = 0.ToString()   i.ToString();
                }
                else
                    noText.text = i.ToString();
                #endregion

                #region 给Nmae赋值
                nameText = gObject.transform.Find("NameText").GetComponent<Text>();
                nameText.text = timeRank[i - 1].name;
                #endregion

                #region 给Time赋值
                timeText = gObject.transform.Find("TimeText").GetComponent<Text>();
                timeText.text = timeRank[i - 1].time.ToString();
                #endregion
            }
        }
        else
        {
            for (int i = 0; i < timeRank.Count; i  )
            {
                GameObject gObject = GameObject.Find("Record ("   (i   1).ToString()   ")");

                #region  给排名序号赋值
                noText = gObject.transform.Find("NumberText").GetComponent<Text>();
                if (i < 9)
                {
                    noText.text = 0.ToString()   (i   1).ToString();
                }
                else
                    noText.text = (i   1).ToString();
                #endregion

                #region 给Nmae赋值
                nameText = gObject.transform.Find("NameText").GetComponent<Text>();
                if (nameText != null)
                    Debug.Log("find name");
                nameText.text = timeRank[i].name;
                #endregion

                #region 给Time赋值
                timeText = gObject.transform.Find("TimeText").GetComponent<Text>();
                timeText.text = timeRank[i].time.ToString();
                #endregion
            }
        }
    }
}

0 人点赞