南天竹种子播种时间几月最好?

小说:南天竹种子播种时间几月最好?作者:秉文王戏更新时间:2019-04-22字数:49483

“你已经不是我的对手了!”纪太虚言道,在王子夜惊骇的表情之中,纪太虚一把抓过王子夜将其封入到了扬雄碑之中!

上次谁求购瓜子黄杨的,抓紧下单,有涨价苗头了

柳二龙几乎是下意识的朝着唐三的方向看去,而迎接她的,却是两束紫金般的光芒。
这里进行着大战,而在外面,军队早已经将大学城封锁起来了。不过即便是这样,这里的大战也将会被世人所知道。毕竟虽然能够防的了人民,却防不了天上卫星的窥探。

因此他甚至渴望有比他强大无数倍的人和他在一起,这样他就不会孤独,也不需要顾忌,而刘皓比较对他的口味,也足够强大,所以对于他来说都是无所谓的。

聊聊Unity3d动态加载场景物件那些事儿。

众所周知,在策划或美术设计完游戏场景地图后,一个场景中可能会存在成千上万个小的物件,比如石头,木箱子,油桶,栅栏等等等等,这些物件并不是游戏中的道具,仅仅只是为了点缀场景,让画面更丰富,当然也可以被打碎之类的。那么基于手机平台内存等限制,如果我们在场景加载时就把所有的物件都加载进去,就会导致几个问题:1.游戏场景进入过慢,因为要加载完所有物件,2.游戏手机可能内存不够,直接崩溃,没办法,你加载的物件实在是太多了。而且更重要的是我们没必要都加载进去这些物件,因为某些物件可能玩家从始至终都没有遇到过,即使你加载了也不会被看到,无端浪费效率而已。基于此,我们需要设计一个根据中心点(一般是玩家位置)来加载与卸载一定范围内物件的功能,这就是我们要说的动态加载场景物件。功能需要做到,在玩家移动到过程中,不断加载半径r之内的物件,不断卸载半径r2之内的物件,以此来剔除无用物件所占的空间,节省内存,优化游戏。

功能的设计有部分参考:http://blog.csdn.net/qinyuanpei/article/details/46499779,以示感谢。

 

要做到动态加载物件,我们需要先做到几件事:

1.保存原始场景中的物件信息到xml。

2.玩家移动过程中根据位置与xml保存的信息比对,找到需要加载的物件与需要卸载的物件,do it。

3.由于频繁加载与卸载物件会造成GC卡顿,我们需要用到缓冲池来保存一定数量的物件以循环利用,当达到最大缓冲数量时才进行卸载。

 

在开始实现之前,我先加入几张图片用来示例场景的一些信息。

                         图1  原始场景信息

图1的场景就是美术设计好地形后的静态物件信息,该场景不会在游戏运行时加载,仅用于设计场景。1处DGOM是用来管理所有物件的父节点,类似2处的cubes是管理相同类型物件的一个父节点,该结点没有预制体,仅仅是一个空的对象,3处就是具体的物件信息,在该功能设计中具体的物件需要有对应的prefab文件,但是prefab只取到第二层,即就是Model下的Cube不再细化到prefab级别,4处表示一些没有父节点的物件

                           图2  游戏场景信息

图2就是运行游戏是要加载的场景,此场景有一个DGOM对象用以跟图1中的DGOM对应,也就是后续动态加载物件的父节点

                         图3  预制体信息

图3表示场景中物件所对应的prefab路径信息,文件夹名字与图1中的层级对应

                        图4   游戏场景展示(请保持低调围观)

 

舞台已经搭建完成,我们开始吧。。。

 

1.保存原始场景中的物件信息到xml

这里我们使用C#中的XmlDocument与XmlElement将场景物件信息进行保存,需要保存的主要属性包括:名字,prefab路径,tag,layer,位置,旋转,缩放,如果是子节点还需包括父节点名称Parent。场景中物件的信息只遍历到DGOM开始的下面两层,再深的子物体当作是跟父物体一起的预制,用以简化场景复杂度,当然可以自己酌情修改。另外场景中的物件名一定要与prefab名称相对应,Unity拖拽prefab到场景后会自动在物件后添加xxx (1)这样的序号,需要删除。类似图1和图3的对应关系。

代码如下:

 

using System.Xml;
using UnityEditor;
using UnityEngine;

namespace LightFramework
{
    /// <summary>
    /// 将场景资源信息导出到xml文件
    /// 注意:场景中物件的名称必须与prefab的名称一致,不可修改,否则加载失败
    /// 由于prefab拖动到场景后,相同名称的物件会被自动在末尾添加xxx (1),需删除" (1)"部分
    /// ref: http://blog.csdn.net/qinyuanpei/article/details/46499779
    /// </summary>
    public class CreateSceneGameObjectsXmlTool
    {
        [MenuItem("ExportSceneToXml/Export")]
        static void ExportGameObjectsToXml()
        {
            string scenePath = UnityEngine.SceneManagement.SceneManager.GetActiveScene().path;
            string sceneName = UnityEngine.SceneManagement.SceneManager.GetActiveScene().name;
            string savePath = EditorUtility.SaveFilePanel("将当前场景导出为Xml", "", sceneName, "xml");

            GameObject _dgom = GameObject.Find("DGOM");//场景资源父节点
            if (null == _dgom) return;

            //创建Xml文件
            XmlDocument xmlDoc = new XmlDocument();
            //创建根节点
            XmlElement scene = xmlDoc.CreateElement("Scene");
            scene.SetAttribute("Name", sceneName);
            scene.SetAttribute("Asset", scenePath);
            xmlDoc.AppendChild(scene);
            
            //Object.FindObjectsOfType()返回所有active的物体;Resources.FindObjectsOfTypeAll()返回包括非active的所有物体
            foreach (GameObject go in Object.FindObjectsOfType(typeof(GameObject))) //Resources.FindObjectsOfTypeAll(typeof(GameObject))
            {
                //仅导出场景中的父物体
                if (null != go.transform.parent && go.transform.parent.gameObject == _dgom)
                {
                    //创建每个物体Node
                    XmlElement gameObject = getGameObjectNode(xmlDoc, go);

                    //添加物体到根节点
                    scene.AppendChild(gameObject);
                }
            }

            xmlDoc.Save(savePath);
        }

        static XmlElement getGameObjectNode(XmlDocument xmlDoc, GameObject go, string parentName = null)
        {
            //创建每个物体,该物体必须存在对应的prefab文件
            XmlElement gameObject = null;
            if(string.IsNullOrEmpty(parentName))
            {
                gameObject = xmlDoc.CreateElement("GameObject");
                gameObject.SetAttribute("Name", go.name);
                gameObject.SetAttribute("Asset", "Prefabs/DGOM/" + go.name/* + ".prefab"*/);//物件所对应prefab路径
            }
            else
            {
                gameObject = xmlDoc.CreateElement("ChildObject");
                gameObject.SetAttribute("Name", go.name);
                gameObject.SetAttribute("Asset", "Prefabs/DGOM/" + parentName + "/" + go.name/* + ".prefab"*/);//物件所对应prefab路径
                gameObject.SetAttribute("Parent", parentName);
            }
            //创建Transform                                                                            
            XmlElement position = xmlDoc.CreateElement("Position");
            position.SetAttribute("x", go.transform.position.x.ToString());
            position.SetAttribute("y", go.transform.position.y.ToString());
            position.SetAttribute("z", go.transform.position.z.ToString());
            gameObject.AppendChild(position);
            //创建Rotation
            XmlElement rotation = xmlDoc.CreateElement("Rotation");
            rotation.SetAttribute("x", go.transform.eulerAngles.x.ToString());
            rotation.SetAttribute("y", go.transform.eulerAngles.y.ToString());
            rotation.SetAttribute("z", go.transform.eulerAngles.z.ToString());
            gameObject.AppendChild(rotation);
            //创建Scale
            XmlElement scale = xmlDoc.CreateElement("Scale");
            scale.SetAttribute("x", go.transform.localScale.x.ToString());
            scale.SetAttribute("y", go.transform.localScale.y.ToString());
            scale.SetAttribute("z", go.transform.localScale.z.ToString());
            gameObject.AppendChild(scale);
            //创建Tag
            XmlElement tag = xmlDoc.CreateElement("Tag");
            tag.SetAttribute("tag", go.tag);
            gameObject.AppendChild(tag);
            //创建Layer
            XmlElement layer = xmlDoc.CreateElement("Layer");
            layer.SetAttribute("layer", LayerMask.LayerToName(go.layer));
            gameObject.AppendChild(layer);

            //场景物件子节点只遍历到第二层
            if (string.IsNullOrEmpty(parentName))
            {
                int childCount = go.transform.childCount;
                int idx = 0;
                Transform childTrans = null;
                for (idx = 0; idx < childCount; ++idx)
                {
                    childTrans = go.transform.GetChild(idx);
                    XmlElement childObject = getGameObjectNode(xmlDoc, childTrans.gameObject, go.name);
                    gameObject.AppendChild(childObject);
                }
            }

            return gameObject;
        }
    }
}
View Code

 

保存完成的xml文件如下:

<Scene Name="TestSource" Asset="Assets/Test/Scenes/TestSource.unity">
  <GameObject Name="Capsule" Asset="Prefabs/DGOM/Capsule">
    <Transform x="-1.25" y="-2.06" z="3.244" />
    <Rotation x="0" y="0" z="1.344026E-06" />
    <Scale x="1" y="1" z="1" />
    <Tag tag="Untagged" />
    <Layer layer="Default" />
  </GameObject>
  <GameObject Name="Sphere" Asset="Prefabs/DGOM/Sphere">
    <Transform x="-0.58" y="2.53" z="0" />
    <Rotation x="358.4108" y="2.544795" z="301.9647" />
    <Scale x="0.6404072" y="0.8599776" z="0.9996151" />
    <Tag tag="Untagged" />
    <Layer layer="Default" />
  </GameObject>
  <GameObject Name="capsules" Asset="Prefabs/DGOM/capsules">
    <Transform x="1" y="0" z="0" />
    <Rotation x="0" y="0" z="0" />
    <Scale x="1" y="1" z="1" />
    <Tag tag="Untagged" />
    <Layer layer="Default" />
    <ChildObject Name="Capsule" Asset="Prefabs/DGOM/capsules/Capsule" Parent="capsules">
      <Transform x="1" y="0" z="2.12" />
      <Rotation x="0" y="0" z="1.344026E-06" />
      <Scale x="1" y="1" z="1" />
      <Tag tag="Untagged" />
      <Layer layer="Default" />
    </ChildObject>
    <ChildObject Name="Capsule" Asset="Prefabs/DGOM/capsules/Capsule" Parent="capsules">
      <Transform x="-3.19" y="0" z="-0.09" />
      <Rotation x="0" y="0" z="1.344026E-06" />
      <Scale x="1" y="1" z="1" />
      <Tag tag="Untagged" />
      <Layer layer="Default" />
    </ChildObject>
    <ChildObject Name="Capsule" Asset="Prefabs/DGOM/capsules/Capsule" Parent="capsules">
      <Transform x="3.401" y="0" z="2.12" />
      <Rotation x="0" y="0" z="1.344026E-06" />
      <Scale x="1" y="1" z="1" />
      <Tag tag="Untagged" />
      <Layer layer="Default" />
    </ChildObject>
  </GameObject>
  <GameObject Name="models" Asset="Prefabs/DGOM/models">
    <Transform x="1" y="0" z="0" />
    <Rotation x="0" y="0" z="0" />
    <Scale x="1" y="1" z="1" />
    <Tag tag="Untagged" />
    <Layer layer="Default" />
    <ChildObject Name="Model" Asset="Prefabs/DGOM/models/Model" Parent="models">
      <Transform x="-0.13" y="1.76" z="-3.91" />
      <Rotation x="0" y="0" z="0" />
      <Scale x="1" y="1" z="1" />
      <Tag tag="Untagged" />
      <Layer layer="Default" />
    </ChildObject>
    <ChildObject Name="Model" Asset="Prefabs/DGOM/models/Model" Parent="models">
      <Transform x="-2.26" y="3.36" z="-2.79" />
      <Rotation x="0" y="0" z="0" />
      <Scale x="1" y="1" z="1" />
      <Tag tag="Untagged" />
      <Layer layer="Default" />
    </ChildObject>
  </GameObject>
  <GameObject Name="cubes" Asset="Prefabs/DGOM/cubes">
    <Transform x="1" y="0" z="0" />
    <Rotation x="0" y="0" z="0" />
    <Scale x="1" y="1" z="1" />
    <Tag tag="Untagged" />
    <Layer layer="Default" />
    <ChildObject Name="Cube" Asset="Prefabs/DGOM/cubes/Cube" Parent="cubes">
      <Transform x="3.56" y="1.6" z="-4.66" />
      <Rotation x="16.77504" y="331.1571" z="297.6572" />
      <Scale x="0.6404073" y="0.9012424" z="0.9583509" />
      <Tag tag="Untagged" />
      <Layer layer="Default" />
    </ChildObject>
    <ChildObject Name="Cube" Asset="Prefabs/DGOM/cubes/Cube" Parent="cubes">
      <Transform x="3.36" y="-1.08" z="-2.21" />
      <Rotation x="16.77504" y="331.1571" z="297.6572" />
      <Scale x="0.6404103" y="0.9012403" z="0.9583499" />
      <Tag tag="Untagged" />
      <Layer layer="Default" />
    </ChildObject>
  </GameObject>
  <GameObject Name="spheres" Asset="Prefabs/DGOM/spheres">
    <Transform x="1" y="0" z="0" />
    <Rotation x="0" y="0" z="0" />
    <Scale x="1" y="1" z="1" />
    <Tag tag="Untagged" />
    <Layer layer="Default" />
    <ChildObject Name="Sphere" Asset="Prefabs/DGOM/spheres/Sphere" Parent="spheres">
      <Transform x="0.74" y="-0.16" z="-5.85" />
      <Rotation x="358.4108" y="2.544795" z="301.9647" />
      <Scale x="0.64041" y="0.8599803" z="0.99962" />
      <Tag tag="Untagged" />
      <Layer layer="Default" />
    </ChildObject>
    <ChildObject Name="Sphere" Asset="Prefabs/DGOM/spheres/Sphere" Parent="spheres">
      <Transform x="-2.98" y="-3.88" z="0.28" />
      <Rotation x="358.4108" y="2.544795" z="301.9647" />
      <Scale x="0.64041" y="0.8599803" z="0.99962" />
      <Tag tag="Untagged" />
      <Layer layer="Default" />
    </ChildObject>
  </GameObject>
</Scene>
View Code

 

 

2.玩家移动过程中根据位置与xml保存的信息比对,找到需要加载的物件与需要卸载的物件,do it。

在将信息保存到TestSource.xml后,我们将该文件放置到StreamingAssets文件夹下用于在游戏启动时加载。将所有物件的信息保存到一个Dictionary中,Dictionary的key值为一个自增的id,从1开始累加,value值为包含了物件各个属性的一个对象。需要定义一个枚举用以标识当前物件的加载状态,如WillLoad,Loaded等。游戏运行时需要每帧调用函数计算出距离玩家为圆心半径为r的范围内所有需要加载对象个数,进行加载,但是如果个数较多同时加载会卡顿,所以要分帧处理,限制每帧加载的最大个数,卸载同理,这里有个设置,如果计算需要加载的对象信息判断出其在将要卸载的物件列表中,那么只需要将其从将要删除列表移出即可,然后改变器状态,不再需要重复加载,这个设计好处是避免玩家在一个小范围进出导致不断加载与卸载物件,浪费效率。

当然还需要提供另外一个接口,用户输入一个点,我们将其范围内的所有物件都加载完成后再通知用户,这是为了处理断线重连进入时,让玩家进入场景后可以看到一个真实的场景而非逐渐加载的场景,更符合现实。

代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace LightFramework.Utils
{
    public enum LoadState
    {
        None,
        WillLoad,
        Loaded,
        WillDetroy,
        Detroyed
    }

    public class GameObjectTransInfo
    {
        public int id;
        public string name;
        public string parentname;
        public string prefabname;
        public string tag;
        public string layer;
        public Vector3 position;
        public Vector3 rotation;
        public Vector3 scale;
        public LoadState state { get; set; }
        public GameObject go { get; set; }
        public GameObject parentGo { get; set; }

        public GameObjectTransInfo(int _id, string _name, string _parentname, string _prefabname, string _tag, string _layer, Vector3 _pos, Vector3 _rot, Vector3 _scale)
        {
            this.id = _id;
            this.name = _name;
            this.parentname = _parentname;
            this.prefabname = _prefabname;
            this.tag = _tag;
            this.layer = _layer;
            this.position = _pos;
            this.rotation = _rot;
            this.scale = _scale;

            this.state = LoadState.None;
            this.go = null;
            this.parentGo = null;
        }
    }

    /// <summary>
    /// 动态加载场景物件管理
    /// </summary>
    public class DynamicLoadSceneObjUtil : Singleton<DynamicLoadSceneObjUtil>
    {
        public GameObject DGOM { get; set; }
        /// <summary>
        /// 加载卸载对象判定中心
        /// </summary>
        public Vector3 centerPos { get; set; }
        /// <summary>
        /// 距centerPos小于等于该值的物件进行加载
        /// </summary>
        public int loadRadius { get; set; }
        /// <summary>
        /// 距centerPos大于该值的物件进行卸载
        /// </summary>
        public int destroyRadius { get; set; }
        /// <summary>
        /// 每帧加载数量
        /// </summary>
        public int loadNumPerFrame { get; set; }
        /// <summary>
        /// 每帧卸载数量
        /// </summary>
        public int destroyNumPerFrame { get; set; }
        public bool isManual { get; set; }
        private Dictionary<int, GameObjectTransInfo> allObjsDic = new Dictionary<int, GameObjectTransInfo>();
        private Dictionary<int, GameObjectTransInfo> alreadyLoadObjsDic = new Dictionary<int, GameObjectTransInfo>();
        private Queue<GameObjectTransInfo> willLoadObjInfoQueue = new Queue<GameObjectTransInfo>();
        private List<GameObjectTransInfo> willDestroyObjsInfoList = new List<GameObjectTransInfo>();

        private int id = 0;//物件的唯一id,递增

        public override void onInit()
        {
            centerPos = Vector3.zero;
            loadRadius = 5;
            destroyRadius = 5;
            loadNumPerFrame = 1;
            destroyNumPerFrame = 1;
            isManual = false;
            DGOM = GameObject.Find("DGOM");//场景资源父节点

            //GameObjectPoolUtil.instance.cacheMaxNum = 2;
        }

        public IEnumerator LoadDynamicScene(string sceneXml, System.Action callback)
        {
            string mainXml = UtilPath.WWWStreamingAssetPath + "/" + sceneXml;
            WWW www = new WWW(mainXml);
            yield return www;

            XmlCfgBase configDoc = new XmlCfgBase();
            configDoc.parseXml(www.text);

            if (configDoc.mXmlConfig.Tag == "Scene")
            {
                ArrayList nodes = new ArrayList();
                UtilXml.getXmlChildList(configDoc.mXmlConfig, "GameObject", ref nodes);

                getObjInfo(nodes);
            }

            callback.Invoke();
        }

        public void getObjInfo(ArrayList nodes)
        {
            string tag = "";
            string layer = "";
            //定义物体位置、旋转和缩放
            Vector3 position = Vector3.zero;
            Vector3 rotation = Vector3.zero;
            Vector3 scale = Vector3.zero;
            //遍历每一个物体
            foreach (System.Security.SecurityElement xe1 in nodes)
            {
                //遍历每一个物体的属性节点
                foreach (System.Security.SecurityElement xe2 in xe1.Children)
                {
                    //根据节点名称为相应的变量赋值
                    if (xe2.Tag == "Position")
                    {
                        float x = 0f;
                        UtilXml.getXmlAttrFloat(xe2, "x", ref x);
                        float y = 0f;
                        UtilXml.getXmlAttrFloat(xe2, "y", ref y);
                        float z = 0f;
                        UtilXml.getXmlAttrFloat(xe2, "z", ref z);
                        position = new Vector3(x, y, z);
                    }
                    else if (xe2.Tag == "Rotation")
                    {
                        float x = 0f;
                        UtilXml.getXmlAttrFloat(xe2, "x", ref x);
                        float y = 0f;
                        UtilXml.getXmlAttrFloat(xe2, "y", ref y);
                        float z = 0f;
                        UtilXml.getXmlAttrFloat(xe2, "z", ref z);
                        rotation = new Vector3(x, y, z);
                    }
                    else if (xe2.Tag == "Scale")
                    {
                        float x = 0f;
                        UtilXml.getXmlAttrFloat(xe2, "x", ref x);
                        float y = 0f;
                        UtilXml.getXmlAttrFloat(xe2, "y", ref y);
                        float z = 0f;
                        UtilXml.getXmlAttrFloat(xe2, "z", ref z);
                        scale = new Vector3(x, y, z);
                    }
                    else if (xe2.Tag == "Tag")
                    {
                        UtilXml.getXmlAttrStr(xe2, "tag", ref tag);
                    }
                    else if (xe2.Tag == "Layer")
                    {
                        UtilXml.getXmlAttrStr(xe2, "layer", ref layer);
                    }
                    else if (xe2.Tag == "TODO")
                    {
                        //and so on ...
                    }
                }

                string name = "";
                UtilXml.getXmlAttrStr(xe1, "Name", ref name);

                string parentname = "";
                UtilXml.getXmlAttrStr(xe1, "Parent", ref parentname);

                string prefabName = "";
                UtilXml.getXmlAttrStr(xe1, "Asset", ref prefabName);

                ++id;
                allObjsDic.Add(id, new GameObjectTransInfo(id, name, parentname, prefabName, tag, layer, position, rotation, scale));
                
                //子节点信息
                ArrayList childnodes = new ArrayList();
                UtilXml.getXmlChildList(xe1, "ChildObject", ref childnodes);
                if(childnodes.Count > 0)
                {
                    getObjInfo(childnodes);
                }
            }
        }

        public void GetWillLoadObjsInfo()
        {
            foreach (var item in allObjsDic)
            {
                var objinfo = item.Value;
                var offset = objinfo.position - centerPos;
                var sqrLen = offset.sqrMagnitude;
                if (sqrLen <= loadRadius * loadRadius)
                {
                    if(objinfo.state == LoadState.None || objinfo.state == LoadState.WillDetroy || objinfo.state == LoadState.Detroyed)
                    {
                        if(willDestroyObjsInfoList.Contains(objinfo))
                        {
                            int index = willDestroyObjsInfoList.IndexOf(objinfo);
                            objinfo.state = LoadState.Loaded;
                            alreadyLoadObjsDic.Add(item.Key, objinfo);
                            willDestroyObjsInfoList.RemoveAt(index);
                        }
                        else
                        {
                            objinfo.state = LoadState.WillLoad;
                            willLoadObjInfoQueue.Enqueue(objinfo);
                        }
                    }
                }
            }
        }

        public void _LoadPrefabs()
        {
            int curNum = 0;
            while(willLoadObjInfoQueue.Count > 0 && curNum < loadNumPerFrame)
            {
                var item = willLoadObjInfoQueue.Peek();
                if(st

编辑:安密华

发布:2019-04-22 11:25:16

当前文章:http://scycxh.com/news/2019041499437/index.html

馒头柳报价哪家准确? 7公分花石榴的价格哪里便宜? 爬藤月季当年能开花吗? 广西腊梅花树什么价格? 紫藤树有什么作用? 云南的萱草都在哪里买的? 史上最全春夏秋冬各种花开的时间表 基地优质大叶美人蕉批发,量大从优

92884 94380 50975 47743 41268 88772 92633 80566 92772 87766 26308 63063 61276 98902 44038 20993 88982 66891 51488 54522

我要说两句: (0人参与)

发布