• Unity场景道具模型拓展自定义编辑器


    (一)适用情况

    当游戏主角进入特定的场景或者关卡,每个关卡需要加载不同位置的模型,道具等。这些信息需要先在unity编辑器里面配置好,一般由策划干这事,然后把这些位置道具信息保存在文件,当游戏主角进入后根据保存的文件信息加载模型道具。如 跑酷场景的金币 赛车赛道的道具 

    (二)实例文件格式 Json

    需要导入SimpleJson 具体使用方法可以看我另外一篇《Unity游戏数据用Json保存》,有详细介绍 http://www.cnblogs.com/July7th/p/4808095.html

    (三)图例

    PathPropManager节点管理所有的道具信息.

    (四)示例代码

    //道具类型;
    public enum PropsType
    {
        PT_ACCEL = 0,
        PT_MISSILE = 1,
        PT_BULLET = 2,
        PT_SHIELD = 3,
        PT_NONE = 4,
    }
    /*
     * filename : PathPropManager.cs ;
     * function : 道具点管理编辑;
     *
    */
    #if UNITY_EDITOR
    
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using System.IO;
    using UnityEditor;
    using PathEdit;
    
    public class PathPropManager : MonoBehaviour {
    
        private PathProp[] mPathPropList; // 所有的道具点;
    
        public TextAsset mData = null;  //道具点xml存储文件;
        public PropsType type = PropsType.PT_ACCEL; //默认道具;
        public bool AlignGround = true;     //是否对齐地面;
        public int Layer = 0;               //地面层级;
        public float GroundHeight = 0.5f;  //离地面距离;
        public bool ShowIcon = true;    //是否用图片显示路点上的道具;
        public bool ShowCube = true;    //是否用方块显示路点上的道具;
    
        void Awake()
        {
        }
    
        //刷新所有道具点;
        private void UpdateList()
        {
            mPathPropList = transform.GetComponentsInChildren<PathProp>();
        }
    
        //当删除某个道具点后自动重新计算序号;
        public void ResetList()
        {
            UpdateList();
            for (int i = 0; i < mPathPropList.Length; i++)
            {
                mPathPropList[i].gameObject.name = i.ToString();
                mPathPropList[i].index = i;
            }
        }
    
        //从json表中重新加载道具会清除当前编辑的所有道具;
        public bool CreatePropBySaveData()
        {
            if (mPathPropList == null)
            {
                return false;
            }
            string fullPath = UnityEditor.AssetDatabase.GetAssetPath(mData);
            if (string.IsNullOrEmpty(fullPath))
            {
                Debug.LogError("文件路径发生错误.");
                return false;
            }
    
            int startIndex = ("Assets/Resources/").Length;
            string filestr = fullPath.Substring(startIndex, fullPath.LastIndexOf('.') - startIndex);
    
            PathPropReader wpr = new PathPropReader(filestr);
            List<PathPropAttributes> ppsa =  wpr.Reader();
    
            if (ppsa == null)
            {
                Debug.LogError("加载道具配置表失败");
            }
    
            Transform[] trans = transform.GetComponentsInChildren<Transform>();
            foreach (Transform child in trans)
            {
                if (child == transform)
                {
                    continue;
                }
                DestroyImmediate(child.gameObject);
            }
            for (int i = 0; i < ppsa.Count; i++)
            {
                GameObject go = new GameObject();
                go.transform.parent = transform;
                go.name = ppsa[i].index.ToString();           
                go.transform.position = ppsa[i].position;
                go.transform.rotation = Quaternion.Euler(ppsa[i].rotation);
                go.transform.localScale = ppsa[i].scale;
                PathProp pp = go.AddComponent<PathProp>();
                pp.index = ppsa[i].index;
                pp.type = ppsa[i].type;
            }
            return true;
        }
    
        //保存道具点信息到json;
        public bool CreateXmlByProps()
        {
            UpdateList();
            if (mData == null)
            {
                Debug.LogError("没有找到保存的路径,请拖动一个json文件到PathPropManager的第一个参数.");
                return false;
            }
            string fullPath = UnityEditor.AssetDatabase.GetAssetPath(mData);
            if (string.IsNullOrEmpty(fullPath))
            {
                Debug.LogError("文件路径发生错误.");
                return false;
            }
            int startIndex = ("Assets/Resources/").Length;
            string filestr = fullPath.Substring(startIndex, fullPath.LastIndexOf('.') - startIndex);
            PathPropReader pr = new PathPropReader(filestr);
            return pr.SaveData(mPathPropList);
        }
    
        //添加新的道具点;
        public void AddProp()
        {
            UpdateList();
            GameObject go = new GameObject();
            go.transform.parent = transform;
            go.name = (mPathPropList.Length).ToString();
            PathProp pp = go.AddComponent<PathProp>();
    
            if (mPathPropList != null)
            {
                if (mPathPropList.Length < 1)
                {
                    //生成的路标点移动到视窗内;
                    Debug.Log("move to view");
                    UnityEditor.EditorApplication.ExecuteMenuItem("GameObject/Move To View");
                }
                else
                {
                    SetPathPropPos(go.transform, mPathPropList.Length - 1);
                }
            }
            pp.index = mPathPropList.Length;
            UnityEditor.Selection.activeTransform = go.transform;
            //UnityEditor.EditorApplication.ExecuteMenuItem("Edit/Lock View to Selected");
        }
    
        //生成的道具点在最后一个路标点的前方,index为前一个路标的index;
        private bool SetPathPropPos(Transform trans, int index)
        {
            if (index < 0 || index >= mPathPropList.Length)
            {
                return false;
            }
            Vector3 pos = mPathPropList[index].transform.position + Vector3.up * 10f;
            Quaternion q = mPathPropList[index].transform.rotation;
    
            //生成的路标点在最后一个路标点的前方;
            //当前位置 = 上个路标点位置 + 上个路标点旋转 * 世界位置前 * 最大两点距离;
            trans.position = pos + q * Vector3.forward * (10);
            trans.rotation = q;
            return true;
        }
    
        void OnDrawGizmos()
        {
            UpdateList();
            if (UnityEditor.Selection.activeTransform == null)
            {
                return;
            }
    
            //移动路点更新数据;
            if (UnityEditor.Selection.activeTransform.parent == transform)
            {
                int temIndex = int.Parse(UnityEditor.Selection.activeTransform.name);
                for (int i = 0; i < mPathPropList.Length; i++)
                {
                    PathProp pp = mPathPropList[i].GetComponent<PathProp>();
                    if (pp == null)
                    {
                        Debug.LogError("get PathProp failed,i=" + i);
                        return;
                    }
                    if (temIndex == pp.index)
                    {
                        if (AlignGround == false)
                        {
                            break;
                        }
                        //对齐地面;
                        RaycastHit hit;
                        if (Physics.Raycast(UnityEditor.Selection.activeTransform.position, -Vector3.up, out hit, 100.0f, 1 << Layer))
                        {
                            //float dis = Vector3.Distance(Selection.activeTransform.position, hit.point);
                            //调整高度;
                            UnityEditor.Selection.activeTransform.position = new Vector3(UnityEditor.Selection.activeTransform.position.x, hit.point.y + GroundHeight, UnityEditor.Selection.activeTransform.position.z);
                        }
                    }
                }
            }
    
            //绘图;    
            for (int i = 0; i < mPathPropList.Length; i++)
            {
                if (ShowIcon)
                {
                    string str = "";
                    switch(mPathPropList[i].type)
                    {
                        case PropsType.PT_ACCEL: str = "js"; break;
                        case PropsType.PT_BULLET: str = "zd"; break;
                        case PropsType.PT_MISSILE: str = "dd"; break;
                        case PropsType.PT_SHIELD: str = "fy"; break;
    
                    }
                    Gizmos.DrawIcon(mPathPropList[i].transform.position, str + ".png");
                }
                if (ShowCube)
                {
                    Gizmos.color = Color.red;
                    Gizmos.DrawCube(mPathPropList[i].transform.position,Vector3.one);
                }
            }
        }
    }
    
    #endif
    PathPropManager.cs
    /*
     * filename : PathPropManagerWindow.cs ;
     * function : 道具点管理自定义编辑;
     *
    */
    using UnityEngine;
    using System.Collections;
    using UnityEditor;
    using System.IO;
    
    [CustomEditor(typeof(PathPropManager))]
    public class PathPropManagerWindow : Editor
    {
        private PathPropManager mPathPropManager = null;
    
        void OnEnable()
        {
    
        }
    
        public override void OnInspectorGUI()
        {
            mPathPropManager = target as PathPropManager;
            if (mPathPropManager == null)
                return;
    
            EditorGUILayout.Space();
            GUILayout.BeginHorizontal();
    
            //刷新路标点;
            if (GUILayout.Button("ReLoad", GUILayout.Height(20)))
            {
                mPathPropManager.CreatePropBySaveData();
            }            
            //获取Json文件数据
            mPathPropManager.mData = (TextAsset)EditorGUILayout.ObjectField(mPathPropManager.mData, typeof(TextAsset), false);
            GUILayout.EndHorizontal();
            EditorGUILayout.Space();
    
            mPathPropManager.type = (PropsType)EditorGUILayout.EnumPopup("DefaultProp", mPathPropManager.type);
            mPathPropManager.Layer = EditorGUILayout.LayerField("AligndLayer", LayerMask.NameToLayer("Floor"));
            mPathPropManager.AlignGround = EditorGUILayout.Toggle("AlignGround", mPathPropManager.AlignGround);
            mPathPropManager.GroundHeight = EditorGUILayout.FloatField("GroundHeight", mPathPropManager.GroundHeight);
            mPathPropManager.ShowIcon = EditorGUILayout.Toggle("ShowIcon", mPathPropManager.ShowIcon);
            mPathPropManager.ShowCube = EditorGUILayout.Toggle("ShowCube", mPathPropManager.ShowCube);
            
            EditorGUILayout.Space();
            GUILayout.BeginHorizontal();
            //保存到Json文件;
            if (GUILayout.Button("SaveToXml", GUILayout.Height(20)))
            {
                if (mPathPropManager.CreateXmlByProps())
                {
                    Debug.Log("保存成功");
                }
            }
    
            GUILayout.EndHorizontal();
            EditorGUILayout.Space();
    
            //标记路点已改变;
            EditorUtility.SetDirty(mPathPropManager);
        }
    
    }
    PathPropManagerWindow.cs
    /*
     * filename : PathPropReader.cs ;
     * function : 道具点l读取;
     *
    */
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
     
       public class PathPropAttributes
        {
            public int index { get; set; }
            public Vector3 position { get; set; }
            public Vector3 rotation { get; set; }
            public Vector3 scale { get; set; }
            public PropsType type { get; set; }
        }
    
        public class PathPropReader
        {
            private string mPath { get; set; }
            private List<PathPropAttributes> mWpAList = new List<PathPropAttributes>();
    
            // resources目录下的相对路径;如路径为Assets/Resouces/Xml/PathWayPoint/test.xml,path = Xml/PathWayPoint/test</param>
            public PathPropReader(string path)
            {
                if (mWpAList == null)
                {
                    mWpAList = new List<PathPropAttributes>();
                }
                if (string.IsNullOrEmpty(path))
                {
                    return;
                }
                mPath = path;
            }
            public List<PathPropAttributes> GetPositionList()
            {
                return mWpAList;
            }
    
            public List<PathPropAttributes> Reader()
            {
                if (string.IsNullOrEmpty(mPath))
                {
                    Debug.LogError("没有找到读取的路径.");
                    return null;
                }
                mWpAList.Clear();
                //读入;
                TextAsset ta = (TextAsset)Resources.Load(mPath);
                if (ta == null)
                {
                    Debug.LogError("load props txt failed.path = "+mPath);
                    return null;
                }
                string txt = ta.text;
                SimpleJSON.JSONArray jsArray = SimpleJSON.JSON.Parse(txt).AsArray;
    
                for (int i = 0; i < jsArray.Count; i++)
                {
                    SimpleJSON.JSONNode node = jsArray[i];
                    PathPropAttributes wpa = new PathPropAttributes();
                    wpa.index = node["index"].AsInt;
                    wpa.position = Helper.StringToVector3(Helper.DeleteChar(node["position"], '(', ')'));
                    wpa.rotation = Helper.StringToVector3(Helper.DeleteChar(node["rotation"], '(', ')'));
                    wpa.scale = Helper.StringToVector3(Helper.DeleteChar(node["scale"], '(', ')'));
                    wpa.type = (PropsType)System.Enum.Parse(typeof(PropsType), node["type"]);
                    mWpAList.Add(wpa);
                }
                return mWpAList;
            }
    
    #if UNITY_EDITOR
            public bool SaveData(PathProp[] pathProps)
            {
                if (string.IsNullOrEmpty(mPath))
                {
                    Debug.LogError("没有找到保存的路径.");
                    return false;
                }
                if (pathProps.Length <= 0)
                {
                    Debug.LogError("至少有一个道具点才能保存.");
                    return false;
                }
                //读入;
                TextAsset ta = (TextAsset)Resources.Load(mPath);
                string txt = ta.text;
                SimpleJSON.JSONArray jsArray = SimpleJSON.JSON.Parse(txt).AsArray;
                jsArray.RemoveAll();
                string str = "{\"index\":\"0000\", \"position\":\"0000\" , \"rotation\":\"0000\", \"scale\":\"0000\" , \"type\":\"0000\"}";
                for (int j = 0; j < pathProps.Length; j++)
                {
                    SimpleJSON.JSONNode newNode = SimpleJSON.JSON.Parse(str);
                    newNode["index"].Value = pathProps[j].index.ToString();
                    newNode["position"] = pathProps[j].gameObject.transform.position.ToString();
                    newNode["rotation"] = pathProps[j].gameObject.transform.rotation.eulerAngles.ToString();
                    newNode["scale"] = pathProps[j].gameObject.transform.localScale.ToString();
                    newNode["type"] = pathProps[j].type.ToString();
                    jsArray.Add(newNode);
                }
                //写入;
                string fp = Application.dataPath + "/Resources/" + mPath + ".json";
                byte[] myByte = System.Text.Encoding.UTF8.GetBytes(jsArray.ToString());
                using (System.IO.FileStream stream = new System.IO.FileStream(fp, System.IO.FileMode.Create))
                {
                    stream.Write(myByte, 0, myByte.Length);
                }
                return true;
            }
    #endif
        }
    PathPropReader.cs
  • 相关阅读:
    SpringMVC:com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: You have an error in your SQL syntax;
    SpringMVC DELETE,PUT请求报错 添加支持Http的DELETE、PUT请求
    HashMap源码总结
    ArrayList动态扩容大小
    Java中的可选操作
    Java中深拷贝与浅拷贝理解
    String在内存中如何存储
    异常处理—checked exception 和 unchecked exception
    Comparable和Comparator区别
    Scanner类与Readable接口
  • 原文地址:https://www.cnblogs.com/July7th/p/4812813.html
Copyright © 2020-2023  润新知