SIKI_Unity_2_入门_通过实例学习游戏的存档和读档
任务5:创建设计目标
Animation的直接使用:
将Animation组件直接挂载在游戏物体上即可播放
脚本控制:
方法1:
直接在Inspector面板给Animation的Animations集合赋值动画a和b
通过animation.clip = a或animation.clip = b后进行animation.Play()即可播放相关动画
注意:这种情况下如果在Inspector面板的Animations集合中没有动画b,那么即使给animation.clip = b赋了b动画的值,也是无法播放b动画的
[SerializeField] private AnimationClip m_IdleAnimationClip; [SerializeField] private AnimationClip m_DieAnimationClip; m_Animation.clip = m_DieAnimationClip; m_Animation.Play();
方法2:
用代码给Animation的Animations赋值,AddClip(clip, name)可以给音效设定名称,之后animation.Play(name)传入name即可播放对应音效
[SerializeField] private AnimationClip m_IdleAnimationClip; [SerializeField] private AnimationClip m_IdleAnimationClip; m_Animation.AddClip(m_IdleAnimationClip, "Idle"); m_Animation.AddClip(m_DieAnimationClip, "Die"); m_Animation.Play("Die");
任务9:设置手枪的旋转
效果:
思路:
设定旋转的最大与最小角度,并根据鼠标在屏幕上的位置,按比例对枪体进行x和y轴上的旋转
任务21:存档相关概念
unity中使用的存档方式
1. PlayerPrefs: 数据持久化方案
存储形式: 键值对
存储数据: Int、Float、String类型
bool类型可以用int的0/1模拟
接口:
PlayerPrefs.SetInt("Key", value);
PlayerPrefs.SetFloat("Key", value);
PlayerPrefs.SetString("Key", value);
PlayerPrefs.GetInt("Key");
2. Serialization/ Deserialization: 序列化和反序列化
存储: 将对象序列化为字节流(Bytes),将字节流存储
读取: 将存储的字节流数据反序列化为对象
常见的数据序列化方法:二进制、XML、JSON
简单的数据用二进制的方式存储就够了,但是二进制的方式有局限性
在实际开发中最常用的是XML/ JSON方式
二进制方法:Binary Formatter
序列化:新建/打开一个二进制文件,通过二进制格式器将对象写入该二进制文件
反序列化:打开待反序列化的二进制文件,通过二进制格式器将文件解析成对象
XML:扩展标记语言(具有结构性的标记语言)
序列化/ 反序列化的方式与二进制方法类似
https://blog.csdn.net/y1196645376/article/details/52541882
JSON:数据的常用格式,可用来跨平台数据传输
序列化: 对象 -- > JSON
反序列化: JSON -> 对象
优缺点:
二进制: 简单 || 可读性差
XML: 可读性强 || 数据文件比较大、冗余信息多
JSON: 数据格式较简单、易读写 || 可读性比XML差(键值对--不直观)
任务23:存储背景音乐的开关状态
使用PlayerPrefs保存后,需要通过PlayerPrefs.Save()进行存储
任务27~28:通过二进制方法存档读档
Save对象中包含相关数据作为属性,该类需要marked as Serializable
[Serializable] public class SaveData { public List<Enemy.EnemyType> enemyTypeList; // 对应位置的敌人种类信息 public SaveData() { enemyTypeList = new List<Enemy.EnemyType>(); for(int i = 0; i < GameManager.instance.enemyGeneratorList.Count; i++) { enemyTypeList.Add(Enemy.EnemyType.Null); } } public int shootCount; public int score; }
存储:
void SaveByBinary() { BinaryFormatter bf = new BinaryFormatter(); FileStream fileStream = File.Create(Application.dataPath + "/StreamingFile/ByBin.txt"); bf.Serialize(fileStream, save); fileStream.Close(); }
读取:
void LoadByBinary() { BinaryFormatter bf = new BinaryFormatter(); FileStream fileStream = File.Open(Application.dataPath + "StreamingFile/ByBin.txt"); Save save = (Save) bf.Deserialize(fileStream); fileStream.Close(); }
存储得到的二进制文件:
FAssembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null SaveData
enemyTypeList
shootCountscore |System.Collections.Generic.List`1[[Enemy+EnemyType, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]] |System.Collections.Generic.List`1[[Enemy+EnemyType, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]] _items_size_version Enemy+EnemyType[] Enemy+EnemyType ?Enemy+EnemyType value__ ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??
任务29~30:通过Json方法存档读档
通过第三方插件LitJson来操作Json文件
存档:
void SaveByJson(SaveData save) { string jsonRepresentation = JsonUtility.ToJson(save); StreamWriter streamWriter = new StreamWriter(Application.dataPath + "..."); streamWriter.Write(jsonRepresentation); streamWriter.Close(); }
读档:
SaveData LoadByJson() { StreamReader streamReader = new StreamReader(Application.dataPath + ""); string jsonRepresentation = streamReader.ReadToEnd(); streamReader.Close(); return JsonUtility.FromJson<SaveData>(jsonRepresentation); }
或者使用JsonMapper.ToObject<SaveData>(jsonRepresentation);
存储得到的Json文件:
{"enemyTypeList":[1,0,4,4,4,1,0,3,4],"shootCount":4,"score":0}
任务31~32:通过XML方法存档读档
通过System.Xml的接口进行Xml文件的操作
存档:
private void SaveByXML(SaveData save) { // 创建XML文档 XmlDocument xmlDocument = new XmlDocument(); // 创建根节点 XmlElement root = xmlDocument.CreateElement("root"); root.SetAttribute("name", "save1"); // 节点的属性值 xmlDocument.AppendChild(root); // 怪物信息 XmlElement target; for (int i = 0; i < save.enemyTypeList.Count; i++) { target = xmlDocument.CreateElement("target"); target.InnerText = ((int)save.enemyTypeList[i]).ToString(); root.AppendChild(target); } // 分数信息 XmlElement scoreElement = xmlDocument.CreateElement("score"); scoreElement.InnerText = save.score.ToString(); root.AppendChild(scoreElement); XmlElement shootCountElement = xmlDocument.CreateElement("shootNumber"); shootCountElement.InnerText = save.shootCount.ToString(); root.AppendChild(shootCountElement); xmlDocument.Save(m_SavePath + BY_XML_FILENAME); }
读档:
private SaveData LoadByXML() { XmlDocument xmlDocument = new XmlDocument(); xmlDocument.Load(m_SavePath + BY_XML_FILENAME); SaveData save = new SaveData(); XmlNodeList targetNodeList = xmlDocument.GetElementsByTagName("target"); // 读取敌人信息 for (int i = 0; i < targetNodeList.Count; i++) { save.enemyTypeList[i] = ((Enemy.EnemyType)int.Parse(targetNodeList[i].InnerText)); } XmlNode scoreNode = xmlDocument.GetElementsByTagName("score")[0]; save.score = int.Parse(scoreNode.InnerText); XmlNode shootCountNode = xmlDocument.GetElementsByTagName("shootCount")[0]; save.shootCount = int.Parse(shootCountNode.InnerText); return save; }
存储得到的Xml文件:
<root name="save1"> <target>4</target> <target>4</target> <target>4</target> <target>4</target> <target>3</target> <target>3</target> <target>3</target> <target>4</target> <target>3</target> <score>0</score> <shootCount>3</shootCount> </root>