亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 編程設計 > 正文

Unity3D 場景導出成 XML 并解析還原場景

2020-07-14 13:22:55
字體:
來源:轉載
供稿:網友

為了盡可能加快從網絡加載場景,我們通常可以把場景先導出成 XML,把優先級高的資源優先加載并顯示(地形等),把可以進入場景之后再加載的對象放到最后(比如場景里面的怪物等),本篇一部分代碼引用自:http://www.xuanyusong.com/archives/1919,導出場景部分在原作者的代碼基礎進行了優化,并且整理成了更加方便,容易使用的類庫。

先來搭建測試場景(測試場景來源網絡),并整理場景中的對象,如圖:

然后把場景中的對象都設置成預設,方便打包成 assetbundle 文件(如何打包預設請查看),如圖:

接著我們編寫把場景打包成 XML 的代碼,取名 ExportSceneToXml.cs,大家可以先看這篇文章(http://www.xuanyusong.com/archives/1919),我在此基礎上面進行了優化,全部代碼如下:


復制代碼
代碼如下:

</font>using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using System.IO;
using System.Text;
public class ExportSceneToXml : Editor
{
[MenuItem("Assets/Export Scene To XML From Selection")]
static void ExportXML()
{
string path = EditorUtility.SaveFilePanel ("Save Resource", "", "New Resource", "xml");
if (path.Length != 0)
{
Object[] selectedAssetList = Selection.GetFiltered (typeof(Object), SelectionMode.DeepAssets);

//遍歷所有的游戲對象
foreach (Object selectObject in selectedAssetList)
{
// 場景名稱
string sceneName = selectObject.name;
// 場景路徑
string scenePath = AssetDatabase.GetAssetPath(selectObject);
// 場景文件
//string xmlPath = path; //Application.dataPath + "/AssetBundles/Prefab/Scenes/" + sceneName + ".xml";
// 如果存在場景文件,刪除
if(File.Exists(path)) File.Delete(path);
// 打開這個關卡
EditorApplication.OpenScene(scenePath);
XmlDocument xmlDocument = new XmlDocument();
// 創建XML屬性
XmlDeclaration xmlDeclaration = xmlDocument.CreateXmlDeclaration("1.0", "utf-8", null);
xmlDocument.AppendChild(xmlDeclaration);
// 創建XML根標志
XmlElement rootXmlElement = xmlDocument.CreateElement("root");
// 創建場景標志
XmlElement sceneXmlElement = xmlDocument.CreateElement("scene");
sceneXmlElement.SetAttribute("sceneName", sceneName);

foreach (GameObject sceneObject in Object.FindObjectsOfType(typeof(GameObject)))
{
// 如果對象是激活狀態
if (sceneObject.transform.parent == null && sceneObject.activeSelf)
{
// 判斷是否是預設
if(PrefabUtility.GetPrefabType(sceneObject) == PrefabType.PrefabInstance)
{
// 獲取引用預設對象
Object prefabObject = EditorUtility.GetPrefabParent(sceneObject);
if(prefabObject != null)
{
XmlElement gameObjectXmlElement = xmlDocument.CreateElement("gameObject");
gameObjectXmlElement.SetAttribute("objectName", sceneObject.name);
gameObjectXmlElement.SetAttribute("objectAsset", prefabObject.name);

XmlElement transformXmlElement = xmlDocument.CreateElement("transform");

// 位置信息
XmlElement positionXmlElement = xmlDocument.CreateElement("position");
positionXmlElement.SetAttribute("x", sceneObject.transform.position.x.ToString());
positionXmlElement.SetAttribute("y", sceneObject.transform.position.y.ToString());
positionXmlElement.SetAttribute("z", sceneObject.transform.position.z.ToString());

// 旋轉信息
XmlElement rotationXmlElement = xmlDocument.CreateElement("rotation");
rotationXmlElement.SetAttribute("x", sceneObject.transform.rotation.eulerAngles.x.ToString());
rotationXmlElement.SetAttribute("y", sceneObject.transform.rotation.eulerAngles.y.ToString());
rotationXmlElement.SetAttribute("z", sceneObject.transform.rotation.eulerAngles.z.ToString());

// 縮放信息
XmlElement scaleXmlElement = xmlDocument.CreateElement("scale");
scaleXmlElement.SetAttribute("x", sceneObject.transform.localScale.x.ToString());
scaleXmlElement.SetAttribute("y", sceneObject.transform.localScale.y.ToString());
scaleXmlElement.SetAttribute("z", sceneObject.transform.localScale.z.ToString());

transformXmlElement.AppendChild(positionXmlElement);
transformXmlElement.AppendChild(rotationXmlElement);
transformXmlElement.AppendChild(scaleXmlElement);

gameObjectXmlElement.AppendChild(transformXmlElement);
sceneXmlElement.AppendChild(gameObjectXmlElement);
}
}
}
}
rootXmlElement.AppendChild(sceneXmlElement);
xmlDocument.AppendChild(rootXmlElement);
// 保存場景數據
xmlDocument.Save(path);
// 刷新Project視圖
AssetDatabase.Refresh();
}
}
}
}


然后我們選中需要打包的場景,選擇把場景打包成 XML 的選項,如圖:

生成完成,我們可以查看生成出的 XML 內容,如圖:

這兒為什么說是對原作者的代碼進行了優化,下面我們可以把場景中的一個對象名稱改成與預設名稱不同,如圖:

然后再次導出成 XML 文件,查看 XML 生成的內容我們可以發現,我們可以正確找到預設的名稱,如圖:

另外,我們還可以選擇場景中的哪些文件不用導出,方法很簡單,我們可以先把場景中的對象禁用,再導出,如圖:

再次查看新導出的 XML 文件,我們會發現 XML 中已經不包括了被禁用對象的配置信息,如圖:

以上兩點是對原作者代碼的優化,而且我也改成了使用右鍵導出,個人感覺這樣更加方便、實用。

現在回到場景中,我們可以把場景里面的對象全部刪除,因為場景中已經不需要這些對象了,我們需要通過代碼創建這些對象,如圖:

下面我們來看如何還原場景,有了 XML,我們解析 XML 就可以了,資源的加載可以看這篇文章(查看詳情),加載場景以及預設資源(assetbundle)的代碼如下:


復制代碼
代碼如下:

using UnityEngine;
using System.Collections.Generic;
public class LoaderScene : MonoBehaviour
{
public UISlider progressBar;
public UILabel lblStatus;
private string scenePath;

void Awake()
{
string prefabPath = "file:///" + Application.dataPath + "/Assets/{0}.assetbundle";
this.scenePath = "file:///" + Application.dataPath + "/Assets/MainScene.unity3d";
IList<WwwLoaderPath> pathList = new List<WwwLoaderPath> ();
pathList.Add (new WwwLoaderPath (this.scenePath, Random.Range (0, 100), WwwLoaderTypeEnum.UNITY_3D));
pathList.Add (new WwwLoaderPath (string.Format(prefabPath, "Lights"), Random.Range (0, 100), WwwLoaderTypeEnum.ASSET_BUNDLE));
pathList.Add (new WwwLoaderPath (string.Format(prefabPath, "Particles"), Random.Range (0, 100), WwwLoaderTypeEnum.ASSET_BUNDLE));
pathList.Add (new WwwLoaderPath (string.Format(prefabPath, "PhysicsCube"), Random.Range (0, 100), WwwLoaderTypeEnum.ASSET_BUNDLE));
pathList.Add (new WwwLoaderPath (string.Format(prefabPath, "Player"), Random.Range (0, 100), WwwLoaderTypeEnum.ASSET_BUNDLE));
pathList.Add (new WwwLoaderPath (string.Format(prefabPath, "Stamps"), Random.Range (0, 100), WwwLoaderTypeEnum.ASSET_BUNDLE));
pathList.Add (new WwwLoaderPath (string.Format(prefabPath, "Statics"), Random.Range (0, 100), WwwLoaderTypeEnum.ASSET_BUNDLE));
pathList.Add (new WwwLoaderPath (string.Format(prefabPath, "Terrain"), Random.Range (0, 100), WwwLoaderTypeEnum.ASSET_BUNDLE));
pathList.Add (new WwwLoaderPath (string.Format(prefabPath, "Trees"), Random.Range (0, 100), WwwLoaderTypeEnum.ASSET_BUNDLE));

this.lblStatus.text = "場景加載中,請稍候。。。";
WwwLoaderManager.instance.Loader (pathList, onLoaderProgress, onLoaderComplete, "MainScene");
}
private void onLoaderProgress(string path, float currentValue, float totalValue)
{
this.progressBar.value = currentValue;
}
private void onLoaderComplete()
{
this.lblStatus.text = "場景正在初始化,請等待。。。";
Application.LoadLevelAsync("MainScene");
}
}


然后新建立一個 C# 文件,取名:InitObject.cs,代碼如下:


復制代碼
代碼如下:

using UnityEngine;
using System.Collections;
using System.Xml;
public class InitObject : MonoBehaviour
{
void Awake()
{
string xmlPath = Application.dataPath + "/Assets/MainScene.xml";
string prefabPath = "file:///" + Application.dataPath + "/Assets/{0}.assetbundle";
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load (xmlPath);

// 使用 XPATH 獲取所有 gameObject 節點
XmlNodeList xmlNodeList = xmlDocument.SelectNodes("http://gameObject");
foreach(XmlNode xmlNode in xmlNodeList)
{
string gameObjectName = xmlNode.Attributes["objectName"].Value;
string prefabName = xmlNode.Attributes["objectAsset"].Value;
AssetBundle assetBundle = WwwDataManager.instance.GetDataAssetBundle(string.Format(prefabPath, prefabName));
if(assetBundle != null)
{
GameObject assetObject = (GameObject)assetBundle.Load(prefabName, typeof(GameObject));
if(assetObject != null)
{
GameObject gameObject = (GameObject)Instantiate(assetObject);
// 使用 XPATH 獲取 位置、旋轉、縮放數據
XmlNode positionXmlNode = xmlNode.SelectSingleNode("descendant::position");
XmlNode rotationXmlNode = xmlNode.SelectSingleNode("descendant::rotation");
XmlNode scaleXmlNode = xmlNode.SelectSingleNode("descendant::scale");

if(positionXmlNode != null && rotationXmlNode != null && scaleXmlNode != null)
{
gameObject.transform.position = new Vector3(float.Parse(positionXmlNode.Attributes["x"].Value), float.Parse(positionXmlNode.Attributes["y"].Value), float.Parse(positionXmlNode.Attributes["z"].Value));
gameObject.transform.rotation = Quaternion.Euler(new Vector3(float.Parse(rotationXmlNode.Attributes["x"].Value), float.Parse(rotationXmlNode.Attributes["y"].Value), float.Parse(rotationXmlNode.Attributes["z"].Value)));
gameObject.transform.localScale = new Vector3(float.Parse(scaleXmlNode.Attributes["x"].Value), float.Parse(scaleXmlNode.Attributes["y"].Value), float.Parse(scaleXmlNode.Attributes["z"].Value));
}
}
// 卸載引用的加載資源,釋放內存
assetBundle.Unload(false);
}
}
xmlDocument = null;
}
}


然后我們在空的場景中新建立一個空對象,并且把代碼掛載到這個空對象上面,如圖:

再然后我們把這個場景打包成 .unity3d 文件,方便從網絡上面加載(詳情可以查看這篇文章),這樣所有的準備工作都已經做好了,全部的配置文件以及資源文件如下:

我們從加載場景運行項目,我們可以先看到依次在加載主場景資源,加載完成之后進入主場景,根據 XML 的內容,原場景被還原了回來,如圖:

百度網盤下載地址:http://pan.baidu.com/s/1sj0RkHv 密碼: vbjd

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
97婷婷涩涩精品一区| 久久久精品电影| 日韩在线观看视频免费| 亚洲成人在线网| 国产性色av一区二区| 久久伊人精品一区二区三区| 亚洲国产精品视频在线观看| 久久香蕉国产线看观看网| 成人亲热视频网站| 亚洲男人7777| 另类美女黄大片| 成人福利在线视频| 成人免费在线视频网站| 一本色道久久88精品综合| 国产精品久久久久久久一区探花| 亚洲精品成人av| 国产视频欧美视频| 日本韩国在线不卡| 欧美限制级电影在线观看| 成人亲热视频网站| 日韩高清电影好看的电视剧电影| 美女999久久久精品视频| 91在线观看免费观看| 亚洲欧美国产一区二区三区| 亚洲美女av在线播放| 国产精品海角社区在线观看| 国产精品一区二区在线| 95av在线视频| 7m精品福利视频导航| 久久精品视频免费播放| 欧美美女18p| 成人激情视频在线播放| 亚洲欧美日韩国产成人| 欧美亚洲免费电影| 最新91在线视频| 国产亚洲欧美日韩一区二区| 国产精品对白刺激| 欧美在线一区二区视频| 亚洲欧美日韩久久久久久| 国产一区二区三区在线观看视频| 欧美成人中文字幕在线| 亚洲国产日韩欧美在线动漫| 久久亚洲一区二区三区四区五区高| 草民午夜欧美限制a级福利片| 色偷偷偷综合中文字幕;dd| 亚洲精品视频免费在线观看| 不卡伊人av在线播放| 亚洲曰本av电影| 日韩精品福利网站| 午夜精品三级视频福利| 91理论片午午论夜理片久久| 欧美高清视频免费观看| 日本午夜精品理论片a级appf发布| 国产精品www色诱视频| 亚洲美女喷白浆| 亚洲欧美日韩一区二区三区在线| 国产色婷婷国产综合在线理论片a| 欧美国产日韩xxxxx| 91精品国产91久久久久久| 欧美黑人一区二区三区| 91国内揄拍国内精品对白| 亚洲午夜性刺激影院| 国产不卡视频在线| 欧美高清视频在线播放| 久久久久久久91| 国产精品吊钟奶在线| 精品少妇v888av| 日韩成人网免费视频| 久久久999精品| 精品国产福利在线| 欧美日韩一区二区三区| 欧美日韩成人在线观看| …久久精品99久久香蕉国产| 国产精品99久久久久久白浆小说| 欧美在线精品免播放器视频| 欧美激情小视频| 欧美裸体xxxx极品少妇| 国内揄拍国内精品少妇国语| 国产日韩av在线播放| 日韩激情视频在线播放| 色999日韩欧美国产| 成人精品一区二区三区电影黑人| 国产精品成人av在线| 国产成人精品999| 色无极影院亚洲| 欧美大成色www永久网站婷| 亚洲国产高潮在线观看| 成人www视频在线观看| 国产精品久久久久久久久免费看| 亚洲自拍另类欧美丝袜| 精品日本美女福利在线观看| 亚洲综合精品一区二区| 57pao成人永久免费视频| 亚洲天堂网站在线观看视频| 国产欧美精品va在线观看| 欧美午夜精品在线| 国产精品入口夜色视频大尺度| 成人免费自拍视频| 青青草精品毛片| 国产精品丝袜白浆摸在线| 亚洲国产精品悠悠久久琪琪| 一本色道久久88精品综合| 午夜精品福利视频| 国产精品人成电影在线观看| 韩曰欧美视频免费观看| 日韩高清av一区二区三区| 欧美激情xxxxx| 国产精品pans私拍| 伊是香蕉大人久久| 2025国产精品视频| 伦伦影院午夜日韩欧美限制| 成人免费淫片aa视频免费| 日韩精品视频在线观看免费| 亚洲国产欧美在线成人app| 91在线视频导航| 亚洲香蕉伊综合在人在线视看| 色偷偷av一区二区三区| 国产亚洲aⅴaaaaaa毛片| 久久精品中文字幕| 91久久国产婷婷一区二区| 亚洲淫片在线视频| 亚洲伊人久久大香线蕉av| 欧美国产日韩一区二区三区| 亚洲一区二区三区xxx视频| 国产精品人成电影在线观看| 中文字幕亚洲专区| 中文字幕在线观看亚洲| 欧美午夜www高清视频| 91在线视频免费| 国产欧美在线观看| 国产精品欧美在线| 国产精品久久久久久久天堂| 久久99久久亚洲国产| 96精品视频在线| 国产aⅴ夜夜欢一区二区三区| 亚洲影视中文字幕| 国产欧美一区二区三区久久| 97福利一区二区| 国产suv精品一区二区三区88区| 欧美日韩午夜剧场| 国产精品视频免费观看www| 中文字幕亚洲一区二区三区五十路| 中文字幕av一区二区三区谷原希美| 日韩av在线影视| 激情成人在线视频| 成人激情春色网| 色综合色综合久久综合频道88| 久久久久99精品久久久久| 国产97色在线| 国产欧美一区二区白浆黑人| 欧美在线视频导航| 亚洲一区二区三区sesese| 久久久噜噜噜久噜久久| 国产高清在线不卡| 久久久噜久噜久久综合| 国产在线一区二区三区| 亚洲第一网站男人都懂| 亚洲欧美在线看| 日韩在线观看免费全| 中文字幕亚洲综合| 91中文字幕一区| 久久久伊人日本| 欧美国产日产韩国视频| 一二美女精品欧洲|