场景资源之解包(2)

来源:互联网 发布:风靡美国华人网络的菜 编辑:程序博客网 时间:2024/05/21 12:38

本篇接着上一篇继续和大家分享场景资源这一主题,主要包括两个方面:

(1)加载场景

场景异步加载的代码比较简单,如下所示:

复制代码
    private IEnumerator LoadLevelCoroutine()    {        string url = "ftp://127.0.0.1/TestScene.unity3d";        int verNum = 1;        WWW wwwForScene = WWW.LoadFromCacheOrDownload(url, verNum);        while (wwwForScene.isDone == false)            yield return null;        AssetBundle bundle = wwwForScene.assetBundle;        yield return Application.LoadLevelAsync("TestScene");        wwwForScene.assetBundle.Unload(false);    }
复制代码

(2)加载场景物件

主要包含以下细分步骤:

a、下载并解析场景配表,得到场景物件信息。场景物件的数据结构如下所示:

复制代码
public class XmlSceneGameobjectProp{    // Mesh信息    public class MeshInfo    {        public string name;        public string shader;        public bool hasColor = false;        public Vector4 color;        public bool isStatic = true;        public int lightmapIndex;        public Vector4 lightmapTilingOffset;    }    public string name;    public string group;    // Transform信息    public float posX, posY, posZ;    public float rotX, rotY, rotZ;    public float scaleX, scaleY, scaleZ;    // Mesh列表,一个模型可以包含多个MeshRenderer    public List<MeshInfo> LstMesh = new List<MeshInfo>();}
复制代码

xml解析的主体代码如下所示:

复制代码
 private void ParseChildNode(XmlElement xmlGroup, XmlElement xmlChild)    {        SceneGameobjectProp newChild = new SceneGameobjectProp();        newChild.group = xmlGroup.GetAttribute("name");        newChild.name = xmlChild.GetAttribute("name");        // 注册资源名字        if (lstRes.Contains(newChild.name) == false)        {            lstRes.Add(newChild.name);        }        // Tranform节点        XmlNode xmlTransform = xmlChild.SelectSingleNode("Transform");        // MeshRenderer节点        XmlNode xmlMeshRenderer = xmlChild.SelectSingleNode("MeshRenderer");        if (xmlTransform != null && xmlTransform is XmlElement)        {            CXmlRead goReader = new CXmlRead(xmlTransform as XmlElement);            newChild.posX = goReader.Float("posX", 0f);            newChild.posY = goReader.Float("posY", 0f);            newChild.posZ = goReader.Float("posZ", 0f);            newChild.rotX = goReader.Float("rotX", 0f);            newChild.rotY = goReader.Float("rotY", 0f);            newChild.rotZ = goReader.Float("rotZ", 0f);            newChild.scaleX = goReader.Float("scaleX", 1f);            newChild.scaleY = goReader.Float("scaleY", 1f);            newChild.scaleZ = goReader.Float("scaleZ", 1f);        }        if (xmlMeshRenderer != null && xmlMeshRenderer is XmlElement)        {            foreach (XmlNode node in xmlMeshRenderer.ChildNodes)            {                if ((node is XmlElement) == false)                    continue;                SceneGameobjectProp.MeshInfo mesh = new SceneGameobjectProp.MeshInfo();                mesh.name = (node as XmlElement).GetAttribute("Mesh");                mesh.shader = (node as XmlElement).GetAttribute("Shader");                XmlNode xmlLightmap = node.SelectSingleNode("Lightmap");                if (xmlLightmap != null && xmlLightmap is XmlElement)                {                    CXmlRead reader = new CXmlRead(xmlLightmap as XmlElement);                    mesh.isStatic = reader.Bool("IsStatic", true);                    mesh.lightmapIndex = reader.Int("LightmapIndex", -1);                    mesh.lightmapTilingOffset = new Vector4(reader.Float("OffsetX", 0f), reader.Float("OffsetY", 0f), reader.Float("OffsetZ", 0f), reader.Float("OffsetW", 0f));                }                XmlNode xmlColor = node.SelectSingleNode("Color");                if (xmlColor != null && xmlColor is XmlElement)                {                    CXmlRead reader = new CXmlRead(xmlColor as XmlElement);                    mesh.hasColor = reader.Bool("hasColor", false);                    mesh.color = new Vector4(reader.Float("r", 0f), reader.Float("g", 0f), reader.Float("b", 0f), reader.Float("a", 0f));                }                newChild.LstMesh.Add(mesh);            }        }        lstGameObjectProp.Add(newChild);    }
复制代码

b、加载场景物件asset

同时开启多个Coroutine进行WWW的LoadFromCacheOrDownload操作,经测试开启的WWW线程越多,速度会越快,但是需要考虑实际的机器或平台的承载能力。

注意,我这儿的WWW操作是直接从缓存里面载入内存,而不是从网上下载。所有更新的游戏物件,可以在游戏开始的时候一次从网上Download到Cache,这样,在游戏过程中就不需要从网上Download资源了,wifi下载3G玩,爽歪歪~

如果一定要在此处从网上Download资源的话,线程数最好设为5个,很多平台有自己的限制,比如有的网页浏览器只能同时开6个等等......

复制代码
    // 同时开启的Coroutine的数目    private const int ThreadNum = 100;    // 记录每个加载线程的进度,只有每个线程都加在结束了,场景加载才算完成    private int[] arrThreadProggress = new int[ThreadNum];    // 加载完成后的回掉    public delegate void LoadFinishDelegate();    public LoadFinishDelegate OnLoadFinish = null;      // 需要下载的资源列表    private List<string> lstRes = new List<string>();    // 是否加载完毕的标记    private bool hasFinished = false;    private void LoadAsset()    {for (int i = 0; i < ThreadNum; ++i)        {            CoroutineProvider.Instance().StartCoroutine(LoadAssetCoroutine(i));        }    }    private IEnumerator LoadAssetCoroutine(int threadIndex)    {        while (arrThreadProggress[threadIndex] < lstRes.Count)        {            // 载入资源            string name = lstRes[arrThreadProggress[threadIndex]];            GameApp.GetResourceManager().LoadAsync(GlobalSetting.SceneAssetPath + name, typeof(GameObject));            while (GameApp.GetResourceManager().IsResLoaded(GlobalSetting.SceneAssetPath + name) == false)            {                yield return null;            }            arrThreadProggress[threadIndex] += ThreadNum;        }        // 线程资源下载完毕,进行加载回掉        if (IsLoadFinished() && hasFinished == false)        {            hasFinished = true;if (OnLoadFinish != null)            {                OnLoadFinish();            }        }    }
复制代码

上面的黑体标出的代码是是实际的加载代码,具体实现已经在帖子“AssetBundle系列——资源的加载、简易的资源管理器”中讲解过了,此处不再赘述。

c、实例化场景物件

复制代码
  // 实例化    GameObject goIns = GameObject.Instantiate(asset) as GameObject;    goIns.name = goProp.name;    // 设置父节点    GameObject goGroup = null;    dicGroupGameobject.TryGetValue(goProp.group, out goGroup);    if (goGroup != null)        goIns.transform.parent = goGroup.transform;    else        goIns.transform.parent = goRoot.transform;    // 设置Transform    goIns.transform.position = new Vector3(goProp.posX, goProp.posY, goProp.posZ);    goIns.transform.eulerAngles = new Vector3(goProp.rotX, goProp.rotY, goProp.rotZ);    goIns.transform.localScale = new Vector3(goProp.scaleX, goProp.scaleY, goProp.scaleZ);    // 设置Shader、Lightmap    int index = 0;    int meshCount = goProp.LstMesh.Count;    foreach (MeshRenderer mr in goIns.gameObject.GetComponentsInChildren<MeshRenderer>(true))    {        if (mr.material != null)        {            if (index < meshCount)            {                SceneGameobjectProp.MeshInfo meshProp = goProp.LstMesh[index];                mr.material.shader = Shader.Find(meshProp.shader);                if (meshProp.hasColor)                    mr.material.color = meshProp.color;                bool isStatic = meshProp.isStatic;                mr.gameObject.isStatic = isStatic;                if (isStatic)                {                    mr.lightmapIndex = meshProp.lightmapIndex;                    mr.lightmapTilingOffset = meshProp.lightmapTilingOffset;                }            }            index++;        }    }
复制代码
0 0
原创粉丝点击