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);
}
}
原文地址:https://www.cnblogs.com/zhh19981104/p/9141070.html