Unity Editor 实现保存还原节点对象.Asset

2020-1-6 雨辰 Unity3D

<->保存节点对象数据结构。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityChan;
using UnityEngine;

namespace Assets.Scripts.Editor.SwingUtil
{
    [CreateAssetMenu]
    public class SwingAsset : ScriptableObject
    {
        /// <summary>
        /// 资源名
        /// </summary>
        public string assetName;
        /// <summary>
        /// 原预制体路径
        /// </summary>
        public string prefabPath;
        /// <summary>
        /// 配置文件保存路径
        /// </summary>
        public string assetPaht;

        /// <summary>
        /// 绑定 柔体脚本属性信息SpringManager
        /// </summary>
        [SerializeField]
        public List<NodeSpringManagerInfo> nodeSpringManagerList = new List<NodeSpringManagerInfo>();

        /// <summary>
        /// 绑定 柔体脚本属性信息SpringCollider
        /// </summary>
        [SerializeField]
        public List<NodeSpringColliderInfo> nodeSpringColliderList = new List<NodeSpringColliderInfo>();

        /// <summary>
        /// 绑定 柔体脚本属性信息SpringBone
        /// </summary>
        [SerializeField]
        public List<NodeSpringBoneInfo> nodeSpringBoneInfoList = new List<NodeSpringBoneInfo>();
    }

    /// <summary>
    /// SpringManager Node
    /// </summary>
    [Serializable]
    public class NodeSpringManagerInfo
    {
        /// <summary>
        /// 节点路径
        /// </summary>
        public string nodePath;

        ///////////////////////////////SpringManager/////////////////////////////////////
        [SerializeField] public SpringManagerInfo springManagerInfo; 

    }

    /// <summary>
    /// SpringManager 数据对象
    /// </summary>
    [Serializable]
    public class SpringManagerInfo
    {
        public float dynamicRatio;
        //Ebata
        public float stiffnessForce;
        public AnimationCurve stiffnessCurve;
        public float dragForce;
        public AnimationCurve dragCurve;
        //public SpringBone[] springBones;
        [SerializeField]
        public List<string> springBonesList;
    }

    /// <summary>
    /// SpringCollider Node
    /// </summary>
    [Serializable]
    public class NodeSpringColliderInfo
    {
        /// <summary>
        /// 节点路径
        /// </summary>
        public string nodePath;
       
        /// <summary>
        /// 节点pos
        /// </summary>
        public Vector3 pos;

        /// <summary>
        /// 节点旋转
        /// </summary>
        public Quaternion pot;

        /// <summary>
        /// 节点缩放信息
        /// </summary>
        public Vector3 scale;

        [SerializeField]public SpringColliderInfo springColliderInfo;
    }

    /// <summary>
    /// SpringCollider 数据对象
    /// </summary>
    [Serializable]
    public class SpringColliderInfo
    {
        public float radius;
    }

    /// <summary>
    /// SpringBoneInfo Node
    /// </summary>
    [Serializable]
    public class NodeSpringBoneInfo
    {
        /// <summary>
        /// 节点路径
        /// </summary>
        public string nodePath;
        
        [SerializeField] public SpringBoneInfo springBoneInfo;
    }

    /// <summary>
    /// SpringBone info
    /// </summary>
    [Serializable]
    public class SpringBoneInfo
    {
        public string childPath;
        
        public Vector3 boneAxis = new Vector3(-1.0f, 0.0f, 0.0f);
        public float radius = 0.05f;
        public bool isUseEachBoneForceSettings = false;
        public float stiffnessForce = 0.01f;
        public float dragForce = 0.4f;
        public Vector3 springForce = new Vector3(0.0f, -0.0001f, 0.0f);
       
        [SerializeField]
        public List<string> collidersList;
        public bool debug = true;
        public float threshold = 0.01f;
    }
}

<二> 保存导出导入节点结构信息
using System.Collections;
using System.Collections.Generic;
using UnityChan;
using UnityEditor;
using UnityEngine;

namespace Assets.Scripts.Editor.SwingUtil
{
    public class SwingUtilEditor
    {
        private static string assetObjPath = "Assets/Resources/SwingAsset";

        [MenuItem("Assets/SwingUtil/导出配置")]
        public static void ExportAssets()
        {
            EditorUtility.DisplayProgressBar("提示", "开始导出配置文件", 0);
            Object[] selection = Selection.GetFiltered(typeof(Object), SelectionMode.TopLevel);
            if (selection == null || selection.Length == 0)
            {
                Debug.Log("请选中预制体后操作");
                EditorUtility.ClearProgressBar();
                return;
            }

            int index = 0;
            foreach (var obj in selection)
            {
                EditorUtility.DisplayProgressBar("提示", string.Format("导出配置文件: {0}", obj.name), index);
                ExportAssetsInfo(obj);
                index++;
            }

            EditorUtility.ClearProgressBar();

            EditorUtility.DisplayDialog("提示", "导出配置成功", "确认");
        }


        [MenuItem("Assets/SwingUtil/导入配置")]
        public static void ImportAssets()
        {
            EditorUtility.DisplayProgressBar("提示", "开始导入配置文件", 0);
            Object[] selection = Selection.GetFiltered(typeof(Object), SelectionMode.TopLevel);
            if (selection == null || selection.Length == 0)
            {
                Debug.Log("请选中预制体后操作");
                EditorUtility.ClearProgressBar();
                return;
            }

            int index = 0;
            foreach (var obj in selection)
            {
                EditorUtility.DisplayProgressBar("提示", string.Format("导入配置文件: {0}", obj.name), index);
                ImportAssetsInfo(obj);
                index++;
            }

            EditorUtility.ClearProgressBar();

            EditorUtility.DisplayDialog("提示", "导入配置成功", "确认");
        }

        /// <summary>
        /// 导入配置
        /// </summary>
        public static void ImportAssetsInfo(Object obj, ScriptableObject data = null)
        {
            //string selectObjPath = AssetDatabase.GetAssetPath(obj);
            //string objPath = selectObjPath.Substring(0, selectObjPath.IndexOf(string.Format("/{0}{1}", obj.name, ".prefab")));
            string path = string.Format("{0}/{1}.asset", assetObjPath, obj.name);
            SwingAsset realConfig = null;
            if (data == null)
            {
                realConfig = AssetDatabase.LoadAssetAtPath<SwingAsset>(path);
            }
            else
            {
                realConfig = data as SwingAsset;
            }

            if (realConfig == null)
            {
                Debug.LogError(string.Format("未能导入的文件,请先导出配置"));
                return;
            }
            if (realConfig.name.Equals(obj.name) || data != null)
            {
                //操作的是预制体相应配置
                Debug.Log(string.Format("导入配置: {0}", path));

                //导入 SpringCollider
                foreach (NodeSpringColliderInfo nci in realConfig.nodeSpringColliderList)
                {
                    GameObject rootObj = obj as GameObject;
                    Transform node = null;
                    if (nci.nodePath == "" || nci.nodePath == obj.name)
                    {
                        node = rootObj.transform;
                    }
                    else
                    {
                        node = rootObj.transform.Find(nci.nodePath);
                    }
                    
                    if (node == null)
                    {
                        //创建节点
                        string[] nodeNamees = nci.nodePath.Split('/');
                        string nodeName = nodeNamees[nodeNamees.Length - 1];
                        //父节点
                        string nodeParent = nci.nodePath.Substring(0, nci.nodePath.IndexOf(string.Format("/{0}", nodeName)));
                        //Debug.Log("nodeParent   " + nodeParent);
                        //添加缸体节点
                        GameObject tempEffectInstant = PrefabUtility.InstantiatePrefab(rootObj) as GameObject;
                        Transform parent = tempEffectInstant.transform.Find(nodeParent);

                        GameObject nodeObj = new GameObject(nodeName);
                        nodeObj.transform.parent = parent;
                        //替换保存
                        PrefabUtility.ReplacePrefab(tempEffectInstant, rootObj, ReplacePrefabOptions.ConnectToPrefab);
                        GameObject.DestroyImmediate(tempEffectInstant);

                        Transform nodeTf = rootObj.transform.Find(nci.nodePath);
                        node = nodeTf;
                    }

                    SpringCollider sm = node.gameObject.GetComponent<SpringCollider>();
                    if (sm == null)
                    {
                        sm = node.gameObject.AddComponent<SpringCollider>();
                    }

                    node.transform.localPosition = nci.pos;
                    node.transform.localRotation = nci.pot;
                    node.transform.localScale = nci.scale;
                    sm.radius = nci.springColliderInfo.radius;

                    EditorUtility.SetDirty(sm);
                }
                //导入 SpringBone
                foreach (NodeSpringBoneInfo nsbi in realConfig.nodeSpringBoneInfoList)
                {
                    GameObject rootObj = obj as GameObject;
                    Transform node = null;
                    if (nsbi.nodePath == "" || nsbi.nodePath == obj.name)
                    {
                        node = rootObj.transform;
                    }
                    else
                    {
                        node = rootObj.transform.Find(nsbi.nodePath);
                    }

                    if (node == null)
                    {
                        continue;
                    }

                    SpringBone sm = node.gameObject.GetComponent<SpringBone>();
                    if (sm == null)
                    {
                        sm = node.gameObject.AddComponent<SpringBone>();
                    }

                    if (string.IsNullOrEmpty(nsbi.springBoneInfo.childPath))
                    {
                        sm.child = null;
                    }
                    else
                    {
                        sm.child = rootObj.transform.Find(nsbi.springBoneInfo.childPath);
                    }

                    if (nsbi.springBoneInfo.collidersList != null)
                    {
                        List<SpringCollider> springColliderList = new List<SpringCollider>();
                        foreach (string collider in nsbi.springBoneInfo.collidersList)
                        {
                            if (string.IsNullOrEmpty(collider))
                            {
                                continue;
                            }
                            Transform colliderTf = rootObj.transform.Find(collider);
                            if (colliderTf != null)
                            {
                                SpringCollider ac = colliderTf.gameObject.GetComponent<SpringCollider>();
                                if (ac != null)
                                {
                                    springColliderList.Add(ac);
                                }
                            }
                        }
                        sm.colliders = springColliderList.ToArray();
                    }
                    
                    sm.boneAxis = nsbi.springBoneInfo.boneAxis;
                    sm.radius = nsbi.springBoneInfo.radius;
                    sm.isUseEachBoneForceSettings = nsbi.springBoneInfo.isUseEachBoneForceSettings;
                    sm.stiffnessForce = nsbi.springBoneInfo.stiffnessForce;
                    sm.dragForce = nsbi.springBoneInfo.dragForce;
                    sm.springForce = nsbi.springBoneInfo.springForce;
                    sm.debug = nsbi.springBoneInfo.debug;
                    sm.threshold = nsbi.springBoneInfo.threshold;

                    EditorUtility.SetDirty(sm);

                }
                //导入 SpringManager

                foreach (NodeSpringManagerInfo info in realConfig.nodeSpringManagerList)
                {
                    GameObject rootObj = obj as GameObject;
                    Transform node = null;
                    if (info.nodePath == "" || info.nodePath == obj.name || data != null)
                    {
                        node = rootObj.transform;
                    }
                    else
                    {
                        node = rootObj.transform.Find(info.nodePath);
                    }

                    if (node == null)
                    {
                        continue;
                    }

                    SpringManager sm = node.gameObject.GetComponent<SpringManager>();
                    if (sm == null)
                    {
                        sm = node.gameObject.AddComponent<SpringManager>();
                    }

                    if (info.springManagerInfo.springBonesList != null)
                    {
                        List<SpringBone> springBoneList = new List<SpringBone>();
                        foreach (string springBone in info.springManagerInfo.springBonesList)
                        {
                            if (string.IsNullOrEmpty(springBone))
                            {
                                continue;
                            }

                            Transform springBoneTf = rootObj.transform.Find(springBone);
                            if (springBoneTf != null)
                            {
                                SpringBone ac = springBoneTf.gameObject.GetComponent<SpringBone>();
                                if (ac != null)
                                {
                                    springBoneList.Add(ac);
                                }
                            }
                        }
                        sm.springBones = springBoneList.ToArray();
                    }

                    sm.dynamicRatio = info.springManagerInfo.dynamicRatio;
                    sm.stiffnessForce = info.springManagerInfo.stiffnessForce;
                    sm.stiffnessCurve = info.springManagerInfo.stiffnessCurve;
                    sm.dragForce = info.springManagerInfo.dragForce;
                    sm.dragCurve = info.springManagerInfo.dragCurve;
                    EditorUtility.SetDirty(sm);
                    
                    //Debug.Log("node name " + node.name);
                }
            }
            else
            {
                Debug.LogError(string.Format("导入的文件与预制体不匹配 :{0}", path));
            }
        }

        /// <summary>
        /// 导出配置文件
        /// </summary>
        /// <param name="obj"></param>
        private static void ExportAssetsInfo(Object obj)
        {
            //预制体路径
            string selectObjPath = AssetDatabase.GetAssetPath(obj);
            if (selectObjPath.IndexOf(".prefab") == -1)
            {
                Debug.LogError(string.Format("选中文件不是预制体: {0}", obj.name));
                return;
            }

            //string objPath = selectObjPath.Substring(0, selectObjPath.IndexOf(string.Format("/{0}{1}", obj.name, ".prefab")));
            //资源保存路径
            string path = string.Format("{0}/{1}.asset", assetObjPath, obj.name);
            SwingAsset swingAsset = ScriptableObject.CreateInstance<SwingAsset>();
            swingAsset.assetName = obj.name;
            swingAsset.prefabPath = selectObjPath;
            swingAsset.assetPaht = path;

            ///保存SpringManager脚本数据
            Object[] springManagerList = Selection.GetFiltered(typeof(SpringManager), SelectionMode.Deep);
            foreach (Object o in springManagerList)
            {
                SpringManager am = o as SpringManager;
                string selectPath = AssetDatabase.GetAssetPath(am);
                if (selectObjPath == selectPath)
                {
                    //Debug.Log(" nodePath: " + selectPath + "  obj Name: " + o.name);
                    string nodePath = "";
                    if (am.transform.parent == null)
                    {
                        //脚本在根节点上
                        nodePath = o.name;
                    }
                    else
                    {
                        nodePath = Deal(obj as GameObject, am.gameObject);
                    }
                    List<string> _springBonesList = new List<string>();
                    if (am.springBones != null)
                    {
                        foreach (SpringBone sb in am.springBones)
                        {
                            if (sb != null && sb.gameObject != null)
                            {
                                _springBonesList.Add(Deal(obj as GameObject, sb.gameObject));
                            }
                        }
                    }

                    swingAsset.nodeSpringManagerList.Add(new NodeSpringManagerInfo()
                    {
                        nodePath = nodePath,
                        springManagerInfo = new SpringManagerInfo()
                        {
                            dynamicRatio = am.dynamicRatio,
                            stiffnessForce = am.stiffnessForce,
                            stiffnessCurve = am.stiffnessCurve,
                            dragForce = am.dragForce,
                            dragCurve = am.dragCurve,
                            //springBones = am.springBones,
                            springBonesList = _springBonesList,
                        },
                    });
                }
            }

            //导出 SpringCollider节点信息
            Object[] springColliderList = Selection.GetFiltered(typeof(SpringCollider), SelectionMode.Deep);
            foreach (Object o in springColliderList)
            {
                SpringCollider ac = o as SpringCollider;
                string selectPath = AssetDatabase.GetAssetPath(ac);
                if (selectObjPath == selectPath)
                {
                    string nodePath = "";
                    if (ac.transform.parent == null)
                    {
                        //脚本在根节点上
                        nodePath = o.name;
                    }
                    else
                    {
                        nodePath = Deal(obj as GameObject, ac.gameObject);
                    }

                    swingAsset.nodeSpringColliderList.Add(new NodeSpringColliderInfo()
                    {
                        nodePath = nodePath,
                        pos = ac.transform.localPosition,
                        pot = ac.transform.localRotation,
                        scale = ac.transform.localScale,
                        springColliderInfo = new SpringColliderInfo()
                        {
                            radius = ac.radius
                        },
                    });
                }
            }

            //导出SpringBone 节点信息
            Object[] springBoneList = Selection.GetFiltered(typeof(SpringBone), SelectionMode.Deep);
            foreach (Object o in springBoneList)
            {
                SpringBone sb = o as SpringBone;
                string selectPath = AssetDatabase.GetAssetPath(sb);
                if (selectObjPath == selectPath)
                {
                    string nodePath = "";
                    if (sb.transform.parent == null)
                    {
                        //脚本在根节点上
                        nodePath = o.name;
                    }
                    else
                    {
                        nodePath = Deal(obj as GameObject, sb.gameObject);
                    }

                    List<string> _collidersList = new List<string>();
                    if (sb.colliders != null)
                    {
                        foreach (SpringCollider sc in sb.colliders)
                        {
                            if (sc != null && sc.gameObject != null)
                            {
                                _collidersList.Add(Deal(obj as GameObject, sc.gameObject));
                            }
                        }
                    }

                    string _childPath = "";
                    if (sb.child != null)
                    {
                        _childPath = Deal(obj as GameObject, sb.child.gameObject);
                    }

                    swingAsset.nodeSpringBoneInfoList.Add(new NodeSpringBoneInfo()
                    {
                        nodePath = nodePath,
                        springBoneInfo = new SpringBoneInfo()
                        {
                            childPath = _childPath,
                            boneAxis = sb.boneAxis,
                            radius = sb.radius,
                            isUseEachBoneForceSettings = sb.isUseEachBoneForceSettings,
                            stiffnessForce = sb.stiffnessForce,
                            dragForce = sb.dragForce,
                            springForce = sb.springForce,
                            collidersList = _collidersList,
                            debug = sb.debug,
                            threshold = sb.threshold,
                        },
                    });
                }
            }

            //导出
            AssetDatabase.CreateAsset(swingAsset, path);
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }

        /// <summary>
        /// 根节点->当前节点的完整路径
        /// </summary>
        /// <param name="prefabRoot"></param>
        /// <param name="nodeGo"></param>
        /// <returns></returns>
        private static string Deal(GameObject prefabRoot, GameObject nodeGo)
        {
            // 根节点->当前节点的完整路径
            string m_FullPath = "";
            //不带根节点
            string m_PathNotIncludeRoot = "";
            Stack<string> nodeNameStack = new Stack<string>();
            nodeNameStack.Push(nodeGo.name);
            do
            {
                nodeGo = nodeGo.transform.parent.gameObject;
                nodeNameStack.Push(nodeGo.name);
            } while (!GameObject.Equals(nodeGo, prefabRoot));

            int i = 0;
            foreach (var nodeName in nodeNameStack)
            {
                if (i > 0)
                {
                    if (i > 1)
                    {
                        m_PathNotIncludeRoot += "/";
                    }
                    m_FullPath += "/";
                    m_PathNotIncludeRoot += nodeName;
                }
                m_FullPath += nodeName;
                i++;
            }
            return m_PathNotIncludeRoot;
        }
    }
}


<三>节点信息保存到.Asset文件后可修改,保存路径在
Assets/Resources/SwingAsset
目录需要手动创建。
 


标签: Unity3D-Editer

发表评论:

朱文华 joyimp|@2011-2019 京ICP备16030765号