Unity3D 保存游戏的几种方式
1. playerpref
官方文档:
https://docs.unity3d.com/ScriptReference/PlayerPrefs.html
保存位置:
http://blog.csdn.net/william_lv/article/details/39520367
2. 保存类
定义一个Save类,当想保存游戏的时候,创建一个类,并赋值。然后存储。当想读取游戏是,先读取文件并生成一个类,然后再赋值到游戏属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | using System.Collections; using System.Collections.Generic; using UnityEngine; [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; } //创建Save对象并存储当前游戏状态信息 private Save CreateSaveGO() { //新建Save对象 Save save = new Save(); //遍历所有的target //如果其中有处于激活状态的怪物,就把该target的位置信息和激活状态的怪物的类型添加到List中 foreach (GameObject targetGO in targetGOs) { TargetManager targetManager = targetGO.GetComponent<TargetManager>(); if (targetManager.activeMonster != null ) { save.livingTargetPositions.Add(targetManager.targetPosition); int type = targetManager.activeMonster.GetComponent<MonsterManager>().monsterType; save.livingMonsterTypes.Add(type); } } //把shootNum和score保存在Save对象中 save.shootNum = UIManager._instance.shootNum; save.score = UIManager._instance.score; //返回该Save对象 return save; } //通过读档信息重置我们的游戏状态(分数、激活状态的怪物) private void SetGame(Save save) { //先将所有的targrt里面的怪物清空,并重置所有的计时 foreach (GameObject targetGO in targetGOs) { targetGO.GetComponent<TargetManager>().UpdateMonsters(); } //通过反序列化得到的Save对象中存储的信息,激活指定的怪物 for ( int i = 0; i < save.livingTargetPositions.Count; i++) { int position = save.livingTargetPositions[i]; int type = save.livingMonsterTypes[i]; targetGOs[position].GetComponent<TargetManager>().ActivateMonsterByType(type); } //更新UI显示 UIManager._instance.shootNum = save.shootNum; UIManager._instance.score = save.score; //调整为未暂停状态 UnPause(); } |
2.1. 保存到二进制文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | using System.IO; using System.Runtime.Serialization.Formatters.Binary; //二进制方法:存档和读档 private void SaveByBin() { //序列化过程(将Save对象转换为字节流) Save save = CreateSaveGO(); //创建Save对象并保存当前游戏状态 BinaryFormatter bf = new BinaryFormatter(); //创建一个二进制格式化程序 FileStream fileStream = File.Create(Application.dataPath + "/StreamingFile" + "/byBin.txt" ); //创建一个文件流 bf.Serialize(fileStream, save); //用二进制格式化程序的序列化方法来序列化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( "存档文件不存在" ); } } |
2.2..JSON
需要使用第三方库 LitJson.dll
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | using LitJson; //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( "存档文件不存在" ); } } |
2.3.. XML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | using System.Xml; //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( "存档文件不存在" ); } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!