游戏的存档和读档
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);
}
}
以上是关于游戏的存档和读档的主要内容,如果未能解决你的问题,请参考以下文章