其实关于这部分内容,雨松研究院已经写得很清楚了,也比较权威,链接在此:http://www.xuanyusong.com/archives/1919,但是现在还是想根据自己的思路整理一下

其实原理就是讲Hierarchy中所有的父物体(即transform.parent == null)都做成预设,然后记录下每个父物体的Transform里的属性,记录到Xml或者Json文件中,然后再解析文件,把其中的预设加载到新场景里,就会得到与原场景一模一样的场景了

首先在Project里新建一个Editor文件夹,里面新建一个脚本MyEditor.cs

using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;
using System.Xml;
using System.IO;
using System.Text;
using LitJson;public class MyEditor : Editor
{//这样是修改了编译器,在菜单栏GameObject下面会多出ExportXML选项
	[MenuItem("GameObject/ExportXML")]
	static void ExportXML()
	{
		string filePath = Application.dataPath + "/StreamingAssets/my.xml";
		string prefabPath = Application.dataPath + "/Resources/Prefabs";		if(!File.Exists(filePath))
		{
			File.Delete(filePath);
		}		if(!Directory.Exists(prefabPath))
		{
			Directory.CreateDirectory(prefabPath);
		}

		XmlDocument xmlDoc = new XmlDocument ();
		XmlDeclaration xmlDec = xmlDoc.CreateXmlDeclaration ("1.0", "utf-8", null);
		xmlDoc.AppendChild (xmlDec);
		XmlElement root = xmlDoc.CreateElement ("gameObjects");		//遍历所有的游戏场景
		foreach(UnityEditor.EditorBuildSettingsScene s in UnityEditor.EditorBuildSettings.scenes)
		{
			//打开场景
			EditorApplication.OpenScene(s.path);
			XmlElement scenes = xmlDoc.CreateElement("scenes");
			scenes.SetAttribute("name", s.path);			foreach(GameObject obj in Object.FindObjectsOfType(typeof(GameObject)))
			{
				//是否被禁用
				if(obj.transform.parent == null && obj.activeSelf)
				{
					//将该物体制作成预设并存放在Resources目录下的Prefabs中
					ExportPrefab(obj, prefabPath);					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");
					XmlElement position_y = xmlDoc.CreateElement("y");
					XmlElement position_z = xmlDoc.CreateElement("z");
					position_x.InnerText = obj.transform.position.x + "";
					position_y.InnerText = obj.transform.position.y + "";
					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");
					XmlElement rotation_y = xmlDoc.CreateElement("y");
					XmlElement rotation_z = xmlDoc.CreateElement("z");
					rotation_x.InnerText = obj.transform.rotation.eulerAngles.x + "";
					rotation_y.InnerText = obj.transform.rotation.eulerAngles.y + "";
					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");
					XmlElement scale_y = xmlDoc.CreateElement("y");
					XmlElement scale_z = xmlDoc.CreateElement("z");
					scale_x.InnerText = obj.transform.localScale.x + "";
					scale_y.InnerText = obj.transform.localScale.y + "";
					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);
				}
			}
		}		AssetDatabase.Refresh ();
		Debug.Log ("Xml export completed");
		Debug.Log (Time.realtimeSinceStartup);
	}	[MenuItem("GameObject/ExportJson")]
	static void ExportJson()
	{
		string filePath = Application.dataPath + "/StreamingAssets/json.txt";
		string prefabPath = Application.dataPath + "/Resources/Prefabs";

		if(!File.Exists(filePath))
		{
			File.Delete(filePath);
		}		if(!Directory.Exists(prefabPath))
		{
			Directory.CreateDirectory(prefabPath);
		}		FileInfo t = new FileInfo (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)
		{
			//打开场景
			EditorApplication.OpenScene(s.path);			writer.WriteObjectStart();
			writer.WritePropertyName("scenes");
			writer.WriteArrayStart ();
			writer.WriteObjectStart();
			writer.WritePropertyName("name");
			writer.Write(s.path);
			writer.WritePropertyName("gameobject");
			writer.WriteArrayStart ();			foreach(GameObject obj in Object.FindObjectsOfType(typeof(GameObject)))
			{
				if(obj.transform.parent == null && obj.activeSelf)
				{
					//将该物体制作成预设并存放在Resources目录下的Prefabs中
					ExportPrefab(obj, prefabPath);					writer.WriteObjectStart();
					writer.WritePropertyName("name");
					writer.Write(obj.name);					writer.WritePropertyName("position");
					writer.WriteArrayStart ();
					writer.WriteObjectStart();
					writer.WritePropertyName("x");
					writer.Write(obj.transform.position.x.ToString("F5"));//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.WriteArrayEnd();

					writer.WritePropertyName("rotation");
					writer.WriteArrayStart ();
					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.WriteArrayEnd();

					writer.WritePropertyName("scale");
					writer.WriteArrayStart ();
					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.WriteArrayEnd();

					writer.WriteObjectEnd();
				}
			}			writer.WriteArrayEnd();
			writer.WriteObjectEnd();
			writer.WriteArrayEnd();
			writer.WriteObjectEnd();
		}		writer.WriteArrayEnd ();
		writer.WriteObjectEnd();		sw.WriteLine (sb.ToString());
		sw.Close ();
		sw.Dispose ();
		AssetDatabase.Refresh ();
		Debug.Log ("Json export completed");
		Debug.Log (Time.realtimeSinceStartup);
	}	private static void ExportPrefab(GameObject gameObject, string prefabPath)
	{
		if(Directory.Exists(prefabPath))
		{
			PrefabUtility.CreatePrefab("Assets/Resources/Prefabs/" + gameObject.name + ".prefab", gameObject, ReplacePrefabOptions.ConnectToPrefab);
		}
	}
}

编译项目,并点击GameObject下的ExportXML和ExportJson选项,会发现在StreamingAssets多了json.txt和my.xml,同时多了文件夹Resources/Prefabs,文件夹里面的预设就是Hirearchy里的父物体的预设

 

unity 状态同步 恢复游戏的状态数据 unity场景恢复_Parse

unity 状态同步 恢复游戏的状态数据 unity场景恢复_Parse_02

下面说说解析文件并还原场景

 

这是XML的解析

using UnityEngine;
using System.Collections;
using System.Xml;
using System.IO;public class XML : MonoBehaviour
{
	void Start ()
	{
		string filePath = Application.dataPath + "/StreamingAssets/my.xml";		if(File.Exists(filePath))
		{
			XmlDocument xmlDoc = new XmlDocument();
			xmlDoc.Load(filePath);
			XmlNodeList nodeList = xmlDoc.SelectSingleNode("gameObjects").ChildNodes;			foreach(XmlElement scene in nodeList)
			{
				Debug.Log(scene.GetAttribute("name"));
				if(!scene.GetAttribute("name").Equals("Assets/Scenes/Demo.unity"))
					continue;				foreach(XmlElement gameObjects in scene.ChildNodes)
				{
					string asset = "Prefabs/" + gameObjects.GetAttribute("name");

					Vector3 position = Vector3.zero;
					Vector3 rotation = Vector3.zero;
					Vector3 scale = Vector3.zero;					foreach(XmlElement transform in gameObjects.ChildNodes)
					{
						foreach(XmlElement info in transform.ChildNodes)
						{
							if(info.Name.Equals("position"))
							{
								foreach(XmlElement pos in info.ChildNodes)
								{
									switch(pos.Name)
									{
									case "x":
										position.x = float.Parse(pos.InnerText);
										break;
									case "y":
										position.y = float.Parse(pos.InnerText);
										break;
									case "z":
										position.z = float.Parse(pos.InnerText);
										break;
									}
								}
							}
							else if(info.Name.Equals("rotation"))
							{
								foreach(XmlElement rot in info.ChildNodes)
								{
									switch(rot.Name)
									{
									case "x":
										rotation.x = float.Parse(rot.InnerText);
										break;
									case "y":
										rotation.y = float.Parse(rot.InnerText);
										break;
									case "z":
										rotation.z = float.Parse(rot.InnerText);
										break;
									}
								}
							}
							else if(info.Name.Equals("scale"))
							{
								foreach(XmlElement sca in info.ChildNodes)
								{
									switch(sca.Name)
									{
									case "x":
										scale.x = float.Parse(sca.InnerText);
										break;
									case "y":
										scale.y = float.Parse(sca.InnerText);
										break;
									case "z":
										scale.z = float.Parse(sca.InnerText);
										break;
									}
								}
							}
						}						//1. 从Resource中读取相应的预设从而实例化出来一个对象
						GameObject obj = (GameObject)Instantiate(Resources.Load(asset), position, Quaternion.Euler(rotation));						obj.transform.localScale = scale;
					}
				}
			}			Debug.Log("Xml restore to scene");
			Debug.Log (Time.realtimeSinceStartup);
		}
		else
		{
			Debug.Log("File not exist");
		}
	}
}

这是Json的解析

using UnityEngine;
using System.Collections;
using System.IO;
using LitJson;public class Json : MonoBehaviour
{
	void Start ()
	{
		string filePath = Application.dataPath + "/StreamingAssets/json.txt";
		StreamReader sr = File.OpenText (filePath);
		string strLine = sr.ReadToEnd ();
		JsonData jd = JsonMapper.ToObject (strLine);
		JsonData gameObjectArray = jd["gameobjects"];		int i, j, k;
		//foreach(JsonData gameObject in gameObjectArray)
		for(i = 0; i < gameObjectArray.Count; i++)
		{
			JsonData sceneArray = gameObjectArray[i]["scenes"];			//foreach(JsonData scene in sceneArray)
			for(j = 0; j < sceneArray.Count; j++)
			{
				string sceneName = sceneArray[j]["name"].ToString();				if(!sceneName.Equals("Assets/Scenes/Demo.unity"))
					continue;				JsonData gameObjects = sceneArray[j]["gameobject"];
				//foreach(JsonData obj in gameObjects)
				for(k = 0; k < gameObjects.Count; k++)
				{
					string objName = gameObjects[k]["name"].ToString();
					string asset = "Prefabs/" + objName;
					Vector3 position = Vector3.zero;
					Vector3 rotation = Vector3.zero;
					Vector3 scale = Vector3.zero;					JsonData pos = gameObjects[k]["position"];
					JsonData rot = gameObjects[k]["rotation"];
					JsonData sca = gameObjects[k]["scale"];					position.x = float.Parse((string)pos[0]["x"]);
					position.y = float.Parse((string)pos[0]["y"]);
					position.z = float.Parse((string)pos[0]["z"]);					rotation.x = float.Parse((string)rot[0]["x"]);
					rotation.y = float.Parse((string)rot[0]["y"]);
					rotation.z = float.Parse((string)rot[0]["z"]);					scale.x = float.Parse((string)sca[0]["x"]);
					scale.y = float.Parse((string)sca[0]["y"]);
					scale.z = float.Parse((string)sca[0]["z"]);					GameObject ob = (GameObject)Instantiate(Resources.Load(asset), position, Quaternion.Euler(rotation));
					ob.transform.localScale = scale;
				}
			}
		}		Debug.Log("Json restore to scene");
		Debug.Log (Time.realtimeSinceStartup);
	}
}

是不是挺简单呢,只要新建个场景,建个空物体把上述脚本挂在物体上,运行即可获得跟原来一模一样的场景啦~~

PS:对于XML和Json对场景的解析和还原效率,我做了测试,下面是测试结果:

当场景为小场景时,即物体个数较少(4个为例),draw call:110

 

解析场景时间

还原时间

文件大小

XML

0.1372822

0.1477898

2k

JSON

0.1357037

0.1179444

1k

 

当场景为大场景时,即物体个数比较多(100个为例),draw call:2848

 

解析场景时间

还原时间

文件大小

XML

0.2660492

0.1703795

48k

JSON

0.1601105

0.1329994

22k

当draw call比较大时,物体个数130,draw call:26068(此时cpu 45%,电脑已经比较卡了)

 

解析场景时间

还原时间

文件大小

XML

0.3745174

0.176897

52k

JSON

0.124469

0.136014

24k

个人觉得,还是Json更胜一筹。