Unity利用Xml和Json保存场景


尊重原创,转载请注明出处,谢谢!

http://blog.csdn.net/y1196645376/article/details/52549082


之前已经简单介绍了XML和JSON的基本使用方法。这里我就介绍一个例子来对XML和JSON进行实战应用 --------- 场景的保存和热更。

提前Ps :   所讲工程内容最后都会给出源码地址。


1.首先你得有一个场景。这个迷宫地形我搭了好久。。


可以看到地图中有个环境Env,人物Player,灯光Light,UGUI事件系统EventSystem,画布Canvas。Init不用管,先删掉。我们把这几个物品全部做成Prefab。我放在了Prefab的文件夹里面。

值得注意的是,如果这些Prefab或者其子物体中身上所挂脚本有pubulic变量添加的是其他物体或者组件的引用需要将这些变量全部私有化然后放到Awake函数里面通过Game.FindWithTag()或者Transform.Find等函数动态获取。

当然,以上的解决方案可能让你很不习惯,没有更好的解决方法了吗?当然有,这个教程中我们只是对资源设置了Prefab。后面我们用篇文章来讲述AssetBundle的使用,而这个技术不仅实现了资源的打包,而且很好的处理了这些资源依赖关系。这也就是后话了。。。这篇文章不涉及。


2.做完以上步骤之后,我们对资源的处理就完毕了,剩下我们就来编写代码实现对场景信息记录。大概的思路就是:读取所有场景信息,然后对于每个场景遍历其所有的Prefab物体,然后记录其坐标,旋转,大小。( 注意:下面代码中涉及到LitJsond包的使用,请将LitJson.dll放到工程的Plugin目录下 )

using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;
using System.Xml;
using System.IO;
using System.Text;
using LitJson;
public class ScencePack : Editor
{
    //将所有游戏场景导出为XML格式
    [MenuItem("GameObject/ExportXML")]
    static void ExportXML()
    {
        string filepath = Application.dataPath + @"/StreamingAssets/my.xml";
        if (!File.Exists(filepath))
        {
            File.Delete(filepath);
        }
        XmlDocument xmlDoc = new XmlDocument();
        XmlElement root = xmlDoc.CreateElement("gameObjects");
        //遍历所有的游戏场景
        foreach (UnityEditor.EditorBuildSettingsScene S in UnityEditor.EditorBuildSettings.scenes)
        {
            //当关卡启用
            if (S.enabled)
            {
                //得到关卡的名称
                string name = S.path;
                //打开这个关卡
                EditorApplication.OpenScene(name);
                XmlElement scenes = xmlDoc.CreateElement("scenes");
                scenes.SetAttribute("name", name);
                foreach (GameObject obj in Object.FindObjectsOfType(typeof(GameObject)))
                {
                    if (obj.transform.parent == null)
                    {
                        XmlElement gameObject = xmlDoc.CreateElement("gameObjects");
                        gameObject.SetAttribute("name", obj.name);

                        gameObject.SetAttribute("asset", obj.name + ".prefab");
                        XmlElement transform = xmlDoc.CreateElement("transform");
                        XmlElement position = xmlDoc.CreateElement("position");
                        XmlElement position_x = xmlDoc.CreateElement("x");
                        position_x.InnerText = obj.transform.position.x + "";
                        XmlElement position_y = xmlDoc.CreateElement("y");
                        position_y.InnerText = obj.transform.position.y + "";
                        XmlElement position_z = xmlDoc.CreateElement("z");
                        position_z.InnerText = obj.transform.position.z + "";
                        position.AppendChild(position_x);
                        position.AppendChild(position_y);
                        position.AppendChild(position_z);

                        XmlElement rotation = xmlDoc.CreateElement("rotation");
                        XmlElement rotation_x = xmlDoc.CreateElement("x");
                        rotation_x.InnerText = obj.transform.rotation.eulerAngles.x + "";
                        XmlElement rotation_y = xmlDoc.CreateElement("y");
                        rotation_y.InnerText = obj.transform.rotation.eulerAngles.y + "";
                        XmlElement rotation_z = xmlDoc.CreateElement("z");
                        rotation_z.InnerText = obj.transform.rotation.eulerAngles.z + "";
                        rotation.AppendChild(rotation_x);
                        rotation.AppendChild(rotation_y);
                        rotation.AppendChild(rotation_z);

                        XmlElement scale = xmlDoc.CreateElement("scale");
                        XmlElement scale_x = xmlDoc.CreateElement("x");
                        scale_x.InnerText = obj.transform.localScale.x + "";
                        XmlElement scale_y = xmlDoc.CreateElement("y");
                        scale_y.InnerText = obj.transform.localScale.y + "";
                        XmlElement scale_z = xmlDoc.CreateElement("z");
                        scale_z.InnerText = obj.transform.localScale.z + "";

                        scale.AppendChild(scale_x);
                        scale.AppendChild(scale_y);
                        scale.AppendChild(scale_z);

                        transform.AppendChild(position);
                        transform.AppendChild(rotation);
                        transform.AppendChild(scale);

                        gameObject.AppendChild(transform);
                        scenes.AppendChild(gameObject);
                        root.AppendChild(scenes);
                        xmlDoc.AppendChild(root);
                        xmlDoc.Save(filepath);

                    }
                }
            }
        }
        //刷新Project视图, 不然需要手动刷新哦
        AssetDatabase.Refresh();
    }
    //将所有游戏场景导出为JSON格式
    [MenuItem("GameObject/ExportJSON")]
    static void ExportJSON()
    {
        string filepath = Application.dataPath + @"/StreamingAssets/json.txt";
        FileInfo t = new FileInfo(filepath);
        if (!File.Exists(filepath))
        {
            File.Delete(filepath);
        }
        StreamWriter sw = t.CreateText();

        StringBuilder sb = new StringBuilder();
        JsonWriter writer = new JsonWriter(sb);
        writer.WriteObjectStart();
        writer.WritePropertyName("GameObjects");
        writer.WriteArrayStart();

        foreach (UnityEditor.EditorBuildSettingsScene S in UnityEditor.EditorBuildSettings.scenes)
        {
            if (S.enabled)
            {
                string name = S.path;
                EditorApplication.OpenScene(name);
                writer.WriteObjectStart();
                writer.WritePropertyName("scenes");
                writer.WriteArrayStart();
                writer.WriteObjectStart();
                writer.WritePropertyName("name");
                writer.Write(name);
                writer.WritePropertyName("gameObject");
                writer.WriteArrayStart();

                foreach (GameObject obj in Object.FindObjectsOfType(typeof(GameObject)))
                {
                    if (obj.transform.parent == null)
                    {
                        writer.WriteObjectStart();
                        writer.WritePropertyName("name");
                        writer.Write(obj.name);
                        writer.WritePropertyName("asset");
                        writer.Write(obj.name + ".prefab");
                        writer.WritePropertyName("position");
                        writer.WriteObjectStart();
                        writer.WritePropertyName("x");
                        writer.Write(obj.transform.position.x.ToString("F5"));
                        writer.WritePropertyName("y");
                        writer.Write(obj.transform.position.y.ToString("F5"));
                        writer.WritePropertyName("z");
                        writer.Write(obj.transform.position.z.ToString("F5"));
                        writer.WriteObjectEnd();

                        writer.WritePropertyName("rotation");
                        writer.WriteObjectStart();
                        writer.WritePropertyName("x");
                        writer.Write(obj.transform.rotation.eulerAngles.x.ToString("F5"));
                        writer.WritePropertyName("y");
                        writer.Write(obj.transform.rotation.eulerAngles.y.ToString("F5"));
                        writer.WritePropertyName("z");
                        writer.Write(obj.transform.rotation.eulerAngles.z.ToString("F5"));
                        writer.WriteObjectEnd();

                        writer.WritePropertyName("scale");
                        writer.WriteObjectStart();
                        writer.WritePropertyName("x");
                        writer.Write(obj.transform.localScale.x.ToString("F5"));
                        writer.WritePropertyName("y");
                        writer.Write(obj.transform.localScale.y.ToString("F5"));
                        writer.WritePropertyName("z");
                        writer.Write(obj.transform.localScale.z.ToString("F5"));
                        writer.WriteObjectEnd();

                        writer.WriteObjectEnd();
                    }
                }

                writer.WriteArrayEnd();
                writer.WriteObjectEnd();
                writer.WriteArrayEnd();
                writer.WriteObjectEnd();
            }
        }
        writer.WriteArrayEnd();
        writer.WriteObjectEnd();

        sw.WriteLine(sb.ToString());
        sw.Close();
        sw.Dispose();
        AssetDatabase.Refresh();
    }
}
( 申明: 以上代码源自雨松Momo大神,本人根据工程实际情况可能有地方进行了略微修改 )

创建好脚本保存后,你会发现在Unity工具栏上GameObject那栏下拉列表中会出现 ExportXML 和 ExportJSON。保存场景。

然后在工程中创建一个文件夹命名StreamingAssets。然后点击以上两个选项其一。然后就会在该目录中生成对应的记录文件。


我们可以打开这两个文件进行查看,记录的就是工程的所有场景信息和每个场景中物体的Transform信息。


3.加载场景。大概思路:我们就可以通过解析这些文件,然后得到自身场景的Prefab的Transform信息,然后根据asset路径信息去加载prefab然后实例到到场景中,再调整坐标,大小,旋转。即可复原原来的场景。

下面是加载场景的脚本:

using UnityEngine;
using System.Collections;
using System.Xml;
using System.IO;
using UnityEditor;
using LitJson;
public class LoadScene: MonoBehaviour
{

    [MenuItem("GameObject/ImprotXML")]
    public static void LoadSenceXML()
    {

        //电脑和iphong上的路径是不一样的,这里用标签判断一下。
#if UNITY_EDITOR
        string filepath = Application.dataPath + "/StreamingAssets" + "/my.xml";
#elif UNITY_IPHONE
	  string filepath = Application.dataPath +"/Raw"+"/my.xml";
#endif
        //如果文件存在话开始解析。
        if (File.Exists(filepath))
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(filepath);
            XmlNodeList nodeList = xmlDoc.SelectSingleNode("gameObjects").ChildNodes;
            foreach (XmlElement scene in nodeList)
            {
                //因为我的XML是把所有游戏对象全部导出, 所以这里判断一下只解析需要的场景中的游戏对象
                //JSON和它的原理类似
                string path = scene.GetAttribute("name");
                string name = path.Substring(path.LastIndexOf('/')+1,path.LastIndexOf('.')-path.LastIndexOf('/')-1);
                Debug.Log(name);
                if (!name.Equals(Application.loadedLevelName))
                {
                    continue;
                }

                foreach (XmlElement gameObjects in scene.ChildNodes)
                {

                    string asset = "Assets/Prefab/" + gameObjects.GetAttribute("asset");
                    Vector3 pos = Vector3.zero;
                    Vector3 rot = Vector3.zero;
                    Vector3 sca = Vector3.zero;
                    foreach (XmlElement transform in gameObjects.ChildNodes)
                    {
                        foreach (XmlElement prs in transform.ChildNodes)
                        {
                            if (prs.Name == "position")
                            {
                                foreach (XmlElement position in prs.ChildNodes)
                                {
                                    switch (position.Name)
                                    {
                                        case "x":
                                            pos.x = float.Parse(position.InnerText);
                                            break;
                                        case "y":
                                            pos.y = float.Parse(position.InnerText);
                                            break;
                                        case "z":
                                            pos.z = float.Parse(position.InnerText);
                                            break;
                                    }
                                }
                            }
                            else if (prs.Name == "rotation")
                            {
                                foreach (XmlElement rotation in prs.ChildNodes)
                                {
                                    switch (rotation.Name)
                                    {
                                        case "x":
                                            rot.x = float.Parse(rotation.InnerText);
                                            break;
                                        case "y":
                                            rot.y = float.Parse(rotation.InnerText);
                                            break;
                                        case "z":
                                            rot.z = float.Parse(rotation.InnerText);
                                            break;
                                    }
                                }
                            }
                            else if (prs.Name == "scale")
                            {
                                foreach (XmlElement scale in prs.ChildNodes)
                                {
                                    switch (scale.Name)
                                    {
                                        case "x":
                                            sca.x = float.Parse(scale.InnerText);
                                            break;
                                        case "y":
                                            sca.y = float.Parse(scale.InnerText);
                                            break;
                                        case "z":
                                            sca.z = float.Parse(scale.InnerText);
                                            break;
                                    }
                                }
                            }
                        }

                        //拿到 旋转 缩放 平移 以后克隆新游戏对象
                        Debug.Log(asset);
                        Object obj = UnityEditor.AssetDatabase.LoadAssetAtPath(asset, typeof(GameObject));
                        GameObject ob = (GameObject)Instantiate(obj, pos, Quaternion.Euler(rot));
                        ob.transform.localScale = sca;
                        ob.name = obj.name;
                    }
                }
            }
        }
    }

    [MenuItem("GameObject/ImprotJSON")]
    public static void LoadSenceJSON()
    {
#if UNITY_EDITOR
        string filepath = Application.dataPath + "/StreamingAssets" + "/json.txt";
#elif UNITY_IPHONE
	  string filepath = Application.dataPath +"/Raw"+"/json.txt";
#endif

        StreamReader sr = File.OpenText(filepath);
        string strLine = sr.ReadToEnd();
        JsonData jd = JsonMapper.ToObject(strLine);
        JsonData gameObjectArray = jd["GameObjects"];
        int i, j, k;
        for (i = 0; i < gameObjectArray.Count; i++)
        {
            JsonData senseArray = gameObjectArray[i]["scenes"];
            for (j = 0; j < senseArray.Count; j++)
            {
                string path = (string)senseArray[j]["name"];
                string name = path.Substring(path.LastIndexOf('/') + 1, path.LastIndexOf('.') - path.LastIndexOf('/') - 1);


                if (!name.Equals(Application.loadedLevelName))
                {
                    continue;
                }
                JsonData gameObjects = senseArray[j]["gameObject"];

                for (k = 0; k < gameObjects.Count; k++)
                {
                    string asset = "Assets/Prefab/" + (string)gameObjects[k]["asset"];
                    Vector3 pos = Vector3.zero;
                    Vector3 rot = Vector3.zero;
                    Vector3 sca = Vector3.zero;

                    JsonData position = gameObjects[k]["position"];
                    JsonData rotation = gameObjects[k]["rotation"];
                    JsonData scale = gameObjects[k]["scale"];

                    pos.x = float.Parse((string)position["x"]);
                    pos.y = float.Parse((string)position["y"]);
                    pos.z = float.Parse((string)position["z"]);

                    rot.x = float.Parse((string)rotation["x"]);
                    rot.y = float.Parse((string)rotation["y"]);
                    rot.z = float.Parse((string)rotation["z"]);

                    sca.x = float.Parse((string)scale["x"]);
                    sca.y = float.Parse((string)scale["y"]);
                    sca.z = float.Parse((string)scale["z"]);

                    Debug.Log(asset);
                    Object obj = UnityEditor.AssetDatabase.LoadAssetAtPath(asset, typeof(GameObject));
                    GameObject ob = (GameObject)Instantiate(obj, pos, Quaternion.Euler(rot));
                    ob.transform.localScale = sca;
                    ob.name = obj.name;

                }

            }
        }

    }
}
我们发现现在GameObject工具栏又多了两个选项:ImportXML,ImportJSON。这就是导入场景信息。

有了以上代码我们就可以对场景的复原了。

首先:我们先把场景里面的物品全部删了。( 注意:要先通过ExportXML or ExportJSON 导出场景记录 )

然后:创建一个名为Init的空物体。挂上一个脚本TestData. 然后只留Start函数然后执行 LoadScene.LoadSenceJSON() 或者 LoadScene.LoadSenceXML();


最后:运行游戏。你会发现所有物体都被实例化出来了。



基本上xml和json的对场景保存和加载的方式如上。最后记录信息文件也不是特别大:

不过你觉得你的工程物品实在有点多,信息文件太大,影响效率的话。可以使用二进制数据格式。主要就是使用BinaryWriter写出二进制流,用BinaryRendeader读入二进制流。这样可以大大压缩信息文件的大小。不过这种方式的坏处是解析的时候。必须要完全了解写入信息的顺序。也就是说如果是xml和json的话只需要知道属性名就可以获取了。而二进制没有这些用于索引的字符,所以只能严格按照字节位数来控制每个变量的所占位置。同时也必须严格按照字节对齐。不然一个变量范围错了,后面的跟着都错了。



Demo工程地址:https://git.oschina.net/Wahh_1314/XmlAndJsonSceneDemo


  • 7
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
### 回答1: Unity中使用Newtonsoft.Json保存Vector类型需要进行以下步骤: 1. 首先,确保你已经在Unity项目中添加了Newtonsoft.Json库。你可以从Unity Asset Store或者Github上下载这个库。 2. 在你需要保存Vector的脚本中,首先引入Newtonsoft.Json命名空间。 ```c# using Newtonsoft.Json; ``` 3. 定义一个Vector类型的变量并给它赋值。 ```c# Vector3 vector = new Vector3(1, 2, 3); ``` 4. 使用JsonConvert.SerializeObject方法将Vector对象转换为JSON字符串。 ```c# string json = JsonConvert.SerializeObject(vector); ``` 5. 将生成的JSON字符串保存到文件中,你可以使用File.WriteAllText方法来实现。 ```c# string filePath = "vector.json"; File.WriteAllText(filePath, json); ``` 6. 如果需要加载保存的Vector,我们可以使用JsonConvert.DeserializeObject方法将JSON字符串转换回Vector对象。 ```c# string loadedJson = File.ReadAllText(filePath); Vector3 loadedVector = JsonConvert.DeserializeObject<Vector3>(loadedJson); ``` 这样,你就可以成功地使用Newtonsoft.Json保存和加载Vector类型了。 注意:在使用Newtonsoft.Json库时,需要确保你已经正确安装并添加了相关引用,以便能够引用正确的命名空间和方法。 ### 回答2: Unity可以使用Newtonsoft.Json保存Vector类型。Newtonsoft.Json是一个流行的JSON序列化和反序列化库,可以轻松地将对象转换为JSON格式并保存。 要保存Vector类型,首先需要安装Newtonsoft.Json库。您可以在Unity Asset Store或Newtonsoft官方网站上找到并下载该库。 安装完毕后,可以使用以下代码将Vector类型转换为JSON字符串并保存: ```csharp using UnityEngine; using Newtonsoft.Json; public class SaveManager : MonoBehaviour { private Vector2 savedVector; private void Start() { // 假设此处是要保存的Vector2 Vector2 vectorToSave = new Vector2(1f, 2f); // 将Vector2对象转换为JSON字符串 string jsonString = JsonConvert.SerializeObject(vectorToSave); // 保存JSON字符串到文件或其他位置 // 这里仅示范输出到控制台 Debug.Log(jsonString); // 反序列化JSON字符串为Vector2对象 savedVector = JsonConvert.DeserializeObject<Vector2>(jsonString); // 输出反序列化后的Vector2 Debug.Log(savedVector); } } ``` 在上面的示例中,我们使用JsonConvert.SerializeObject方法将Vector2对象转换为JSON字符串,并使用Debug.Log输出到控制台。我们还使用JsonConvert.DeserializeObject方法将JSON字符串反序列化为Vector2对象,并将其打印到控制台。 通过上述步骤,您可以使用Newtonsoft.Json保存Unity中的Vector类型。 ### 回答3: Unity是一款强大的游戏开发引擎,它提供了许多实用的功能来简化开发过程。其中一个重要的功能就是数据的序列化与反序列化。为了保存和加载Vector类型的数据,我们可以使用Newtonsoft.Json库。 首先,我们需要将Newtonsoft.Json库导入到Unity项目中。这可以通过在Unity Asset Store中下载并导入Newtonsoft.Json插件来完成。 接下来,在我们需要保存Vector类型数据的脚本中,我们需要引入Newtonsoft.Json命名空间。命名空间的引入可以通过以下代码实现: ```csharp using Newtonsoft.Json; ``` 然后,我们可以使用JsonConvert.SerializeObject方法将Vector类型数据转换为JSON字符串,并将其保存到文件中。下面是一个示例代码: ```csharp Vector3 vectorData = new Vector3(1.0f, 2.0f, 3.0f); string json = JsonConvert.SerializeObject(vectorData); File.WriteAllText("vectorData.json", json); ``` 上述代码将一个名为vectorData.json的文件保存到项目目录中。该文件中包含了Vector3类型的数据。 最后,如果我们想要加载保存的Vector类型数据,我们可以使用JsonConvert.DeserializeObject方法将JSON字符串转换回Vector类型。以下是一个示例代码: ```csharp string json = File.ReadAllText("vectorData.json"); Vector3 loadedVectorData = JsonConvert.DeserializeObject<Vector3>(json); ``` 上述代码将通过读取vectorData.json文件中的JSON字符串,并将其转换为Vector3类型的loadedVectorData变量。 使用Newtonsoft.Json保存和加载Vector类型数据是非常简单的。我们只需要导入库,将Vector类型数据转换为JSON字符串并保存,然后反过来将JSON字符串转换回Vector类型数据即可。这些步骤可以帮助我们在Unity中轻松地保存和加载Vector类型数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值