游戏的存档和读档

Posted Turtle Zhang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了游戏的存档和读档相关的知识,希望对你有一定的参考价值。

1、保存的数据类:

 1 using System.Collections;
 2 using System.Collections.Generic;
 3 using UnityEngine;
 4 
 5 [System.Serializable]
 6 public class Save
 7 {
 8     public List<int> livingTargetPosition = new List<int>();       //用来保存有怪物的位置信息
 9     public List<int> livingMonsterType = new List<int>();          //保存生成的怪物类型
10 
11     public int shootNumebr=0;           //射击数
12     public int score = 0;        //分数
13 }

 

 

 

2、游戏管理器,用来管理游戏的保存和加载

  1 using System.Collections;
  2 using System.Collections.Generic;
  3 using UnityEngine;
  4 using UnityEngine.UI;
  5 using System.IO;
  6 using System.Runtime.Serialization.Formatters.Binary;           //二进制转换器
  7 using LitJson;              //json的命名空间引入
  8 using System.Xml;           //引入xml的命名空间
  9     
 10 public class GameManager : MonoBehaviour
 11 {
 12     private static GameManager _instance;
 13     public static GameManager Instace
 14     {
 15         get
 16         {
 17             return _instance;
 18         }
 19         set
 20         {
 21             _instance = value;
 22         }
 23     }
 24     private void Awake()
 25     {
 26         _instance = this;
 27 
 28     }
 29 
 30     public GameObject MenuGameObject;              //菜单游戏物体
 31     public GameObject[] targets;                   //每个格子都会有怪物生成,则要一一获取
 32     public bool IsPause = true;                     //默认菜单面板显示出来就是暂停状态
 33 
 34     private void Start()
 35     {
 36         IsPause = true;
 37         Pause();                                    //默认菜单面板显示出来就是暂停状态
 38     }
 39 
 40     private void Update()
 41     {
 42         if (Input.GetKeyDown(KeyCode.Escape))
 43         {
 44             Pause();                         //当按下了ESC键就调出菜单面板
 45         }
 46     }
 47 
 48     /// <summary>
 49     /// 通过生成的游戏数据,然后创建保存类,将相关的数据写到Sava类中进行保存
 50     /// //只要调用这个方法,就会得到一个保存好数据的Save类
 51     /// </summary>
 52     /// <returns></returns>
 53     private Save CreateSave()
 54     {
 55         Save save = new Save();     //先创建这个对象
 56         foreach (GameObject targetGo in targets)
 57         {
 58             TargetManager targetManager = targetGo.GetComponent<TargetManager>();
 59             if(targetManager.activateMoster!=null)
 60             {
 61                 //如果有不为空的,也就是在游戏场景中生成了的,
 62                 save.livingTargetPosition.Add(targetManager.targetPosition);            //则要进行保存
 63                 save.livingMonsterType.Add(targetManager.activateMoster.GetComponent<MosterManager>().mosterType);  //保存怪物类型
 64             }
 65         }
 66         save.shootNumebr = UIManager.Instance.shootNumber;
 67         save.score = UIManager.Instance.scoreNumber;                //将分数和射击数进行保存
 68 
 69         return save;        
 70     }
 71     /// <summary>
 72     /// 通过读档,将得到的数据运用到游戏中,分数、射击数、怪物位置、怪物类型
 73     /// </summary>
 74     /// <param name="save">读取到的文件类</param>
 75     private void SetGame(Save save)
 76     {
 77         foreach (GameObject targetGo in targets)
 78         {
 79             targetGo.GetComponent<TargetManager>().UpdateMoster();      //通过数据读取来设计游戏中的场景时,要先将场景中有的进行清空
 80         }
 81 
 82         for (int i = 0; i < save.livingTargetPosition.Count; i++)
 83         {
 84             int position = save.livingTargetPosition[i];            //得到在哪个格子里面进行生成
 85             int type = save.livingMonsterType[i];                   //得到生成那种类型的
 86             targets[position].GetComponent<TargetManager>().ActivateMonsterByType(type);        //通过怪物下标来进行生成
 87         }
 88 
 89         UIManager.Instance.shootNumber = save.shootNumebr;
 90         UIManager.Instance.scoreNumber = save.score;                //更新得分和成绩
 91     }
 92 
 93 
 94 
 95 
 96     //二进制:存档和读档
 97     private void SaveByBin()
 98     {
 99         //1、首先得到要保存的Save类
100         Save save = CreateSave();          
101         //2、创建一个二进制转化程序
102         BinaryFormatter binF = new BinaryFormatter();
103         //3、得到要保存数据的数据流
104         FileStream fileStream = File.Create(Application.dataPath + "/StreamingFile" + "/Bin.txt");
105         //4、进行序列化,写入
106         binF.Serialize(fileStream, save);
107         //5、关闭
108         fileStream.Close();
109 
110         if(File.Exists((Application.dataPath + "/StreamingFile" + "/Bin.txt")))
111         {
112             //如果保存成功了,显示保存成功的提示
113             UIManager.Instance.Message("保存成功");
114         }
115     }
116 
117     private void LoadByBin()
118     {
119         //1、先判断存档文件是否存在
120         if(File.Exists(Application.dataPath + "/StreamingFile" + "/Bin.txt"))
121         { 
122             //2、创建二进制转换器
123             BinaryFormatter binf = new BinaryFormatter();
124             //3、得到文件流
125             FileStream fileStrem = File.Open(Application.dataPath + "/StreamingFile" + "/Bin.txt", FileMode.Open);
126             //4、通过二进制逆转换器得到数据
127             Save save = (Save)binf.Deserialize(fileStrem);      //得到数据
128             //5、关闭
129             fileStrem.Close();
130             //6、将数据进行保存
131             SetGame(save);
132 
133             UIManager.Instance.Message("读档成功");
134         }
135         else
136         {
137             UIManager.Instance.Message("文档不存在");
138         }
139     }
140 
141 
142     //XML:存档和读档
143     private void SaveByXml()
144     {
145         //1、创建save对象
146         Save save = CreateSave();
147         //2、创建XML文件的存储路径
148         string filePath = Application.dataPath + "/StreamingFile" + "/byXml.xml";
149         //3、创建XML文档
150         XmlDocument xmlDoc = new XmlDocument();
151         //4、创建根节点,名字为Save,注意,一个XML文档只有一个根节点,就和html语言一样
152         XmlElement root = xmlDoc.CreateElement("Save");
153         //5、设置根节点的属性,也可以不设置
154         root.SetAttribute("namne","saveFile");
155 
156         //6、创建XmlElement
157         XmlElement target;
158         XmlElement targetPosition;
159         XmlElement targetType;
160 
161         for (int i = 0; i < save.livingTargetPosition.Count; i++)
162         {
163             target = xmlDoc.CreateElement("Target");
164 
165             //创建其中一个属性 设置innertext的值
166             targetPosition = xmlDoc.CreateElement("targetPosition");
167             targetPosition.InnerText = save.livingTargetPosition[i].ToString();
168 
169             targetType = xmlDoc.CreateElement("targetType");
170             targetType.InnerText = save.livingMonsterType[i].ToString();
171 
172             //设置层级关系
173             target.AppendChild(targetPosition);
174             target.AppendChild(targetType);
175             root.AppendChild(target);
176         }
177         XmlElement UI;
178         XmlElement shootNumber;
179         XmlElement score;
180 
181         UI = xmlDoc.CreateElement("UI");
182         shootNumber = xmlDoc.CreateElement("ShootNumber");
183         score = xmlDoc.CreateElement("Score");
184 
185         //存入数据
186         shootNumber.InnerText = save.shootNumebr.ToString();
187         score.InnerText = save.score.ToString();
188 
189         //设置层级关系
190         UI.AppendChild(shootNumber);
191         UI.AppendChild(score);
192         root.AppendChild(UI);
193 
194         //将根节点添加到xml文档中
195         xmlDoc.AppendChild(root);
196         //保存xml文档
197         xmlDoc.Save(filePath);
198 
199         if(File.Exists(filePath))
200         {
201             UIManager.Instance.Message("保存成功");
202         }
203 
204     }
205     private void LoadByXml()
206     {
207         string filePath= Application.dataPath + "/StreamingFile" + "/byXml.xml";
208         //如果存在文件的话
209         if(File.Exists(filePath))
210         {
211             Save save = new Save();
212             //加载XML文档
213             XmlDocument xmlDoc = new XmlDocument();
214             xmlDoc.Load(filePath);
215             //通过节点名称来获取元素,注意,文档中会有多个该节点,结果为XmlNodeList类型
216             XmlNodeList targets =xmlDoc.GetElementsByTagName("Target");
217             if(targets.Count!=0)
218             {
219                 for (int i = 0; i < targets.Count; i++)
220                 {
221                     //每一个target节点下面还有子节点,数据存在了对应的子节点下面
222                     XmlNode targetPosition = targets[i].ChildNodes[0];
223                     int targetPositionValue = int.Parse(targetPosition.InnerText);
224                     save.livingTargetPosition.Add(targetPositionValue);
225 
226                     XmlNode targetType = targets[i].ChildNodes[1];
227                     int targetTypeValue = int.Parse(targetType.InnerText);
228                     save.livingMonsterType.Add(targetTypeValue);
229 
230                 }
231             }
232 
233             XmlNodeList UI = xmlDoc.GetElementsByTagName("UI");
234             if(UI.Count!=0)
235             {
236                 foreach (XmlNode ui in UI)
237                 {
238                     XmlNode shootNumber = ui.ChildNodes[0];
239                     int shootNumberValue = int.Parse(shootNumber.InnerText);
240                     save.shootNumebr = shootNumberValue;
241 
242                     XmlNode score = ui.ChildNodes[1];
243                     int scoreValue = int.Parse(score.InnerText);
244                     save.score = scoreValue;
245                 }
246             }
247 
248             //将得到的数据进行应用
249             SetGame(save);      
250 
251             UIManager.Instance.Message("文档加载成功");
252         }
253         else
254         {
255             UIManager.Instance.Message("文档不存在");
256         }
257 
258         
259 
260     }
261 
262 
263     //JSON:存档和读档
264     private void SaveByJson()
265     {
266         //1、创建save对象
267         Save save = CreateSave();
268         //2、得到要放置json文件的地址
269         string filePath = Application.dataPath + "/StreamingFile" + "/byJson.json";
270         //3、将save对象转换为json字符串
271         string saveJsonString = JsonMapper.ToJson(save);
272         //4、 //设置为写入的文件流
273         StreamWriter writer = new StreamWriter(filePath);
274         //5、写入
275         writer.Write(saveJsonString);
276         //6、关闭
277         writer.Close();
278         if(File.Exists(Application.dataPath + "/StreamingFile" + "/byJson.json"))
279         {
280             UIManager.Instance.Message("保存成功");
281         }
282 
283 
284     }
285     private void LoadByJson()
286     {
287         string filrPath = Application.dataPath + "/StreamingFile" + "/byJson.json";
288         if(File.Exists(filrPath))
289         {
290             //1、如果文件存在
291             StreamReader reader = new StreamReader(filrPath);
292             //2、通过读取数据流读到json文件中的信息,转化为字符串
293             string loadJsonString = reader.ReadToEnd();         //读取到结尾
294             //3、将json文件转化为save对象
295             Save save = JsonMapper.ToObject<Save>(loadJsonString);
296             //4、将数据应用到游戏中
297             SetGame(save);
298             UIManager.Instance.Message("读取成功");
299         }
300         else
301         {
302             UIManager.Instance.Message("文档不存在");
303         }
304 
305     }
306 
307     /// <summary>
308     /// 暂停游戏
309     /// </summary>
310     private void Pause()
311     {
312         MenuGameObject.SetActive(true);
313         IsPause = true;
314         Time.timeScale = 0;         //暂停游戏
315         Cursor.visible = true;
316     }
317 
318 
319     /// <summary>
320     /// 非暂停状态
321     /// </summary>
322     private void UpPause()
323     {
324         IsPause = false;
325         MenuGameObject.SetActive(false);
326         Time.timeScale = 1;         //继续进行游戏
327         Cursor.visible = false;
328     }
329 
330     /// <summary>
331     /// 继续游戏
332     /// </summary>
333     public void OnContinueGameButtonClick()
334     {
335         UpPause();
336     }
337 
338     /// <summary>
339     /// 退出游戏
340     /// </summary>
341     public void OnQuietButtonClick()
342     {
343     #if UNITY_EDITOR
344          UnityEditor.EditorApplication.isPlaying = false;
345     # else
346          Application.Quit();    
347     #endif
348     }
349 
350     /// <summary>
351     ///新游戏
352     /// </summary>
353     public void OnNewGameButtonClick()
354     {
355         foreach (GameObject target in targets)
356         {
357             target.GetComponent<TargetManager>().UpdateMoster();            //对场景中的每一个敌人进行消息传递,进行更新
358         }
359         UIManager.Instance.shootNumber = 0;
360         UIManager.Instance.scoreNumber = 0;         //将分数进行清零
361         UpPause();
362     }
363 
364     /// <summary>
365     /// 保存数据
366     /// </summary>
367     public void OnSaveButtonClick()
368     {
369         UIManager.Instance.Message("");
370         //SaveByBin();            //二进制保存
371         //SaveByJson();
372         SaveByXml();
373         StartCoroutine(HideMessage());
374     }
375 
376     /// <summary>
377     /// 加载数据
378     /// </summary>
379     public void OnLoadButtonClick()
380     {
381         UIManager.Instance.Message("");
382         //LoadByBin();
383         //LoadByJson();
384         LoadByXml();
385         StartCoroutine(HideMessage());
386     }
387 
388     /// <summary>
389     /// 在一定时间内将帮助文档进行隐藏
390     /// </summary>
391     /// <returns></returns>
392    IEnumerator HideMessage()
393     {
394         yield return new WaitForSeconds(1.0f);
395         UIManager.Instance.message_Text.gameObject.SetActive(false);
396     }
397 }

 

3、显示TargetManager和UIManager两个类方便阅读

 

  1 using System.Collections;
  2 using System.Collections.Generic;
  3 using UnityEngine;
  4 using UnityEngine.UI;
  5 
  6 public class UIManager : MonoBehaviour
  7 {
  8 
  9     private static UIManager _instace;
 10     public static UIManager Instance
 11     {
 12         set
 13         {
 14             _instace = value;
 15         }
 16         get
 17         {
 18             return _instace;
 19         }
 20     }
 21     private void Awake()
 22     {
 23         _instace = this;
 24     } 
 25 
 26     public Text shootNumber_Text;
 27     public Text scoreNumber_Text;
 28     public Toggle musicToggle;
 29     public Text message_Text;           //用来显示保存、加载成功的
 30 
 31     public int shootNumber = 0;
 32     public int scoreNumber = 0;
 33 
 34     public Audiosource music;
 35 
 36 
 37     private void Start()
 38     {
 39         message_Text.gameObject.SetActive(false);
 40     }
 41 
 42     private void Update()
 43     {
 44         UpdateUI();     //更新UI显示   
 45 
 46 
 47 
 48         //如果存在声音控制的键值
 49         if(PlayerPrefs.HasKey("MusicOn"))
 50         {
 51             if(PlayerPrefs.GetInt("MusicOn")==0)
 52             {
 53                 musicToggle.isOn = false;
 54                 music.enabled = false;
 55             }
 56             else if(PlayerPrefs.GetInt("MusicOn")==1)
 57             {
 58                 musicToggle.isOn = true;
 59                 music.enabled = true;
 60             }
 61         }
 62         //如果不存在这个键的话,就默认设置为播放状态
 63         else
 64         {
 65             musicToggle.isOn = true;
 66             music.enabled = true;
 67         }
 68 
 69 
 70     }
 71 
 72 
 73     /// <summary>
 74     /// 声音开光控制
 75     /// 使用了PlayerPrefs的保存方法来进行保存
 76     /// </summary>
 77     public void MusicSwitch()
 78     {
 79         if(musicToggle.isOn==true)
 80         {   
 81             music.enabled = true;
 82             PlayerPrefs.SetInt("MusicOn", 1);           //为1表示播放音乐,为0表示暂停音乐
 83         }
 84         else
 85         {        
 86             music.enabled = false;
 87             PlayerPrefs.SetInt("MusicOn", 0);
 88         }
 89 
 90         PlayerPrefs.Save();         //注意,在设置完值后,一定要进行保存,否则结果是无法进行保存的
 91     }
 92 
 93 
 94 
 95 
 96 
 97     /// <summary>
 98     /// 更新Ui显示的方法
 99     /// </summary>
100     private void UpdateUI()
101     {
102         shootNumber_Text.text = shootNumber.ToString();
103         scoreNumber_Text.text = scoreNumber.ToString();
104     }
105     /// <summary>
106     /// 增加射击数的
107     /// </summary>
108     public void AddShootNumber()
109     {
110         shootNumber += 1;
111     }
112 
113     /// <summary>
114     /// 增加分数的
115     /// </summary>
116     public void AddScoreNumber()
117     {
118         scoreNumber += 1;
119     }
120 
121     /// <summary>
122     /// 显示加载、保存成功的提示消息的
123     /// </summary>
124     /// <param name="message">保存成功、保存失败</param>
125     public void Message(string message)
126     {
127         message_Text.text = message;
128         message_Text.gameObject.SetActive(true);
129     }
130 }

 

  1 using System.Collections;
  2 using System.Collections.Generic;
  3 using UnityEngine;
  4 
  5 public class TargetManager : MonoBehaviour
  6 {
  7     //这里不能用单例模式,因为在游戏中会生成多个相同的对象,
  8     //到后面就不能正确的知道是那个TargetManager了
  9     //private static TargetManager _instance;
 10     //public static TargetManager Instance
 11     //{
 12     //    get
 13     //    {
 14     //        return _instance;
 15     //    }
 16     //    set
 17     //    {
 18     //        _instance = value;
 19     //    }
 20     //}
 21     //private void Awake()
 22     //{
 23     //    _instance = this;
 24     //}
 25 
 26     public GameObject[] mosters;
 27     public GameObject activateMoster=null;         //这个是用来取得当前实例出来的怪物
 28     public int targetPosition;          //用来设置怪物的生成位置,要被保存的
 29 
 30     private void Start()
 31     {
 32         //一开始先做预判的处理
 33         foreach (GameObject moster in mosters)
 34         {
 35             moster.GetComponent<BoxCollider>().enabled = false;
 36             moster.SetActive (false);
 37         }
 38         StartCoroutine(AliveTiemr());
 39     }
 40 
 41 
 42 
 43     /// <summary>
 44     /// 等待多久进行怪物的生成的协程
 45     /// </summary>
 46     /// <returns></returns>
 47     IEnumerator AliveTiemr()
 48     {
 49         yield return new WaitForSeconds(Random.Range(1, 5));            //等待个随机1-4秒再生成
 50         ActivateMoster();
 51         StartCoroutine(DeathTimer());
 52     }
 53 
 54     /// <summary>
 55     /// 控制怪物在生成一段时间后自动进行消失
 56     /// </summary>
 57     /// <returns></returns>
 58     IEnumerator DeathTimer()
 59     {
 60         yield return new WaitForSeconds(Random .Range(3f,8.0f));
 61         DeActivateMoster();
 62     }
 63 
 64 
 65 
 66     /// <summary>
 67     /// 将小怪物进行激活
 68     /// </summary>
 69     private void ActivateMoster()
 70     {
 71         int index = Random.Range(0, mosters.Length);            //取得随机的生成怪物的下标
 72         activateMoster = mosters[index];
 73         activateMoster.SetActive(true);
 74         activateMoster.GetComponent<BoxCollider>().enabled = true;
 75     }
 76 
 77     /// <summary>
 78     /// 将怪物进行隐藏
 79     /// </summary>
 80     private void DeActivateMoster()
 81     {
 82         if(activateMoster!=null)
 83         {
 84             activateMoster.GetComponent<BoxCollider>().enabled = false;
 85             activateMoster.SetActive(false);
 86             activateMoster = null;
 87         }
 88        StartCoroutine(AliveTiemr());
 89 
 90     }
 91 
 92     /// <summary>
 93     /// 当怪物被打死后,让外界(MosterManager)进行调用重新再生成一波敌人
 94     /// </summary>
 95     public void UpdateMoster()
 96     {
 97         StopAllCoroutines();            //现将所有的协程进行暂停,避免出现协程没运行完,就开始生成下一波怪物了
 98         if (activateMoster!=null)
 99         {
100             activateMoster.GetComponent<BoxCollider>().enabled = false;
101             activateMoster.SetActive(false);
102             activateMoster = null;
103         }
104         StartCoroutine(AliveTiemr());
105     }
106 
107 
108     /// <summary>
109     /// 通过指定的怪物类型来进行怪物的生成
110     /// 放在游戏加载的时候被调用
111     /// </summary>
112     /// <param name="type">怪物下标类型</param>
113     public void ActivateMonsterByType(int type)
114     {
115         StopAllCoroutines();            //先停止所有的协程
116         if(activateMoster!=null)
117         {
118             activateMoster.GetComponent<BoxCollider>().enabled = false;
119             activateMoster.SetActive(false);
120             activateMoster = null;          
121         }
122         activateMoster = mosters[type];         //通过怪物类型来进行生成
123         activateMoster.SetActive(true);
124         activateMoster.GetComponent<BoxCollider>().enabled = true;
125         StartCoroutine(DeathTimer());           //怪物生成出来了,就要等待被删除了
126 
127     }
128 }

 

4、希望可以帮助到大家,这也是自己的学习出来的,有错误希望大家帮忙指正。

 

【注意:】使用JSON的话要导入Json库!!!

 

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

public class UIManager : MonoBehaviour
{

    private static UIManager _instace;
    public static UIManager Instance
    {
        set
        {
            _instace = value;
        }
        get
        {
            return _instace;
        }
    }
    private void Awake()
    {
        _instace = this;
    }

    public Text shootNumber_Text;
    public Text scoreNumber_Text;
    public Toggle musicToggle;
    public Text message_Text;           //用来显示保存、加载成功的

    public int shootNumber = 0;
    public int scoreNumber = 0;

    public AudioSource music;


    private void Start()
    {
        message_Text.gameObject.SetActive(false);
    }

    private void Update()
    {
        UpdateUI();     //更新UI显示   



        //如果存在声音控制的键值
        if(PlayerPrefs.HasKey("MusicOn"))
        {
            if(PlayerPrefs.GetInt("MusicOn")==0)
            {
                musicToggle.isOn = false;
                music.enabled = false;
            }
            else if(PlayerPrefs.GetInt("MusicOn")==1)
            {
                musicToggle.isOn = true;
                music.enabled = true;
            }
        }
        //如果不存在这个键的话,就默认设置为播放状态
        else
        {
            musicToggle.isOn = true;
            music.enabled = true;
        }


    }


    /// <summary>
    /// 声音开光控制
    /// 使用了PlayerPrefs的保存方法来进行保存
    /// </summary>
    public void MusicSwitch()
    {
        if(musicToggle.isOn==true)
        {   
            music.enabled = true;
            PlayerPrefs.SetInt("MusicOn", 1);           //为1表示播放音乐,为0表示暂停音乐
        }
        else
        {        
            music.enabled = false;
            PlayerPrefs.SetInt("MusicOn", 0);
        }

        PlayerPrefs.Save();         //注意,在设置完值后,一定要进行保存,否则结果是无法进行保存的
    }





    /// <summary>
    /// 更新Ui显示的方法
    /// </summary>
    private void UpdateUI()
    {
        shootNumber_Text.text = shootNumber.ToString();
        scoreNumber_Text.text = scoreNumber.ToString();
    }
    /// <summary>
    /// 增加射击数的
    /// </summary>
    public void AddShootNumber()
    {
        shootNumber += 1;
    }

    /// <summary>
    /// 增加分数的
    /// </summary>
    public void AddScoreNumber()
    {
        scoreNumber += 1;
    }

    /// <summary>
    /// 显示加载、保存成功的提示消息的
    /// </summary>
    /// <param name="message">保存成功、保存失败</param>
    public void Message(string message)
    {
        message_Text.text = message;
        message_Text.gameObject.SetActive(true);
    }
}

以上是关于游戏的存档和读档的主要内容,如果未能解决你的问题,请参考以下文章

unity游戏中存档和读档的方法

SIKI_Unity_2_入门_通过实例学习游戏的存档和读档

数据存档和读档三种方式

Unity开发之存档和读档的三种实现方式

学Git,用Git ②

Unity 常用的几种存档读档方式