Unity 编辑器开发实战【Editor Window】- Duplicator复制机

2022-08-29 16:52:59 浏览数 (2)

1.Name Duplicator:名称复制机(根据层级结构复制名称)

2.Material Duplicator:材质复制机(根据层级结构复制材质)

代码如下:

代码语言:javascript复制
namespace SK.Framework
{
    public interface IDuplicator
    {
        string InvalidatedInfo { get; }

        bool IsValidated();

        void Duplicate();
    }
}
代码语言:javascript复制
代码语言:javascript复制
namespace SK.Framework
{
    public abstract class AbstractDuplicator<T> : IDuplicator
    {
        public virtual string InvalidatedInfo
        {
            get
            {
                return "Is invalidated.";
            }
        }

        protected T from;
        protected T to;
        
        public abstract bool IsValidated();

        public abstract void Duplicate();
    }
}
代码语言:javascript复制
using UnityEngine;
using System.Text;
using System.Collections.Generic;

namespace SK.Framework
{
    public class NameDuplicator : AbstractDuplicator<Transform>
    {
        private readonly Dictionary<string, Transform> fromHierarchy;
        private readonly Dictionary<string, Transform> toHierarchy;

        public override string InvalidatedInfo
        {
            get
            {
                return "Is invalidated:请先验证层级结构是否一致";
            }
        }

        public NameDuplicator(Transform from, Transform to)
{
            this.from = from;
            this.to = to;
            fromHierarchy = new Dictionary<string, Transform>();
            toHierarchy = new Dictionary<string, Transform>();
        }

        //递归遍历From层级
        private void ForEachFromHierarchy(Transform t)
{
            foreach (Transform child in t)
            {
                string fullName = GetFullName(child);
                fromHierarchy.Add(fullName, child);
                ForEachFromHierarchy(child);
            }
        }
        //递归遍历To层级
        private void ForEachToHierarchy(Transform t)
{
            foreach (Transform child in t)
            {
                string fullName = GetFullName(child);
                toHierarchy.Add(fullName, child);
                ForEachToHierarchy(child);
            }
        }
        //获取层级结构
        private string GetFullName(Transform t)
{
            const string flag = "hierarchy";
            List<Transform> tfs = new List<Transform>();
            Transform tf = t.transform;
            tfs.Add(tf);
            while (tf.parent)
            {
                tf = tf.parent;
                tfs.Add(tf);
            }
            StringBuilder sb = new StringBuilder();
            sb.Append($"{flag}{tfs[tfs.Count - 2].GetSiblingIndex()}");
            for (int i = tfs.Count - 3; i >= 0; i--)
            {
                sb.Append($"/{flag}{tfs[i].GetSiblingIndex()}");
            }
            return sb.ToString();
        }

        public override bool IsValidated()
{
            ForEachFromHierarchy(from);
            ForEachToHierarchy(to);
            bool retV = true;
            retV &= fromHierarchy.Count == toHierarchy.Count;
            foreach (var kv in toHierarchy)
            {
                if (!fromHierarchy.ContainsKey(kv.Key))
                {
                    retV = false;
                    break;
                }
            }
            return retV;
        }

        public override void Duplicate()
{
            foreach (var kv in toHierarchy)
            {
                kv.Value.name = fromHierarchy[kv.Key].name;
            }
        }
    }
}
代码语言:javascript复制
using UnityEngine;
using System.Text;
using System.Collections.Generic;

namespace SK.Framework
{
    public class MaterialDuplicator : AbstractDuplicator<Transform>
    {
        private readonly Dictionary<string, Renderer> fromDic;
        private readonly Dictionary<string, Renderer> toDic;

        public MaterialDuplicator(Transform from, Transform to)
{
            this.from = from;
            this.to = to;
            fromDic = new Dictionary<string, Renderer>();
            toDic = new Dictionary<string, Renderer>();
        }

        private void GetFromMeshRenderer()
{
            Renderer[] renderers = from.GetComponentsInChildren<Renderer>(true);
            for(int i = 0; i < renderers.Length; i  )
            {
                Renderer renderer = renderers[i];
                fromDic.Add(GetFullName(renderer.transform), renderer);
            }
        }
        private void GetToMeshRenderer()
{
            Renderer[] renderers = to.GetComponentsInChildren<Renderer>(true);
            for (int i = 0; i < renderers.Length; i  )
            {
                Renderer renderer = renderers[i];
                toDic.Add(GetFullName(renderer.transform), renderer);
            }
        }
        private string GetFullName(Transform t)
{
            List<Transform> tfs = new List<Transform>();
            Transform tf = t.transform;
            tfs.Add(tf);
            while (tf.parent)
            {
                tf = tf.parent;
                tfs.Add(tf);
            }
            StringBuilder sb = new StringBuilder();
            sb.Append(tfs[tfs.Count - 2].name);
            for (int i = tfs.Count - 3; i >= 0; i--)
            {
                sb.Append("/"   tfs[i].name);
            }
            return sb.ToString();
        }
        public override bool IsValidated()
{
            GetFromMeshRenderer();
            GetToMeshRenderer();
            bool retV = true;
            retV &= fromDic.Count == toDic.Count;
            foreach (var kv in toDic)
            {
                if (!fromDic.ContainsKey(kv.Key))
                {
                    retV = false;
                    break;
                }
            }
            return retV;
        }
        public override void Duplicate()
{
            foreach (var kv in toDic)
            {
                kv.Value.sharedMaterials = fromDic[kv.Key].sharedMaterials;
            }
        }
    }
}
代码语言:javascript复制
代码语言:javascript复制
using UnityEngine;
using UnityEditor;

namespace SK.Framework
{
    public class DuplicatorWindow : EditorWindow
    {
        [MenuItem("SKFramework/Duplicator")]
        private static void Open()
        {
            GetWindow<DuplicatorWindow>("Duplicator").Show();
        }

        private Transform from;
        private Transform to;
        private bool isValidated;
        private const float labelWidth = 80f;

        private enum Mode
        {
            Name,
            Material,
        }
        private Mode mode = Mode.Name;
        private IDuplicator duplicator;

        private void OnGUI()
        {
            OnModeGUI();

            OnFromToGUI();

            OnValidateGUI();

            OnDuplicateGUI();
        }
        private void OnModeGUI()
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label("Mode", GUILayout.Width(labelWidth));
            mode = (Mode)EditorGUILayout.EnumPopup(mode);
            GUILayout.EndHorizontal();
        }
        private void OnFromToGUI()
        {
            //From
            GUILayout.BeginHorizontal();
            GUILayout.Label("From", GUILayout.Width(labelWidth));
            Transform newFrom = EditorGUILayout.ObjectField(from, typeof(Transform), true) as Transform;
            if (newFrom != from)
            {
                from = newFrom;
                isValidated = false;
            }
            GUILayout.EndHorizontal();

            //To
            GUILayout.BeginHorizontal();
            GUILayout.Label("To", GUILayout.Width(labelWidth));
            Transform newTo = EditorGUILayout.ObjectField(to, typeof(Transform), true) as Transform;
            if (newTo != to)
            {
                to = newTo;
                isValidated = false;
            }
            GUILayout.EndHorizontal();
        }
        private void OnValidateGUI()
        {
            GUI.enabled = from != null && to != null;
            if (GUILayout.Button("Validate"))
            {
                switch (mode)
                {
                    case Mode.Name: duplicator = new NameDuplicator(from, to); break;
                    case Mode.Material: duplicator = new MaterialDuplicator(from, to); break;
                    default: break;
                }
                isValidated = duplicator.IsValidated();
            }
            GUI.enabled = true;
            if (duplicator != null && !isValidated)
            {
                EditorGUILayout.HelpBox(duplicator.InvalidatedInfo, MessageType.Warning);
            }
        }
        private void OnDuplicateGUI()
        {
            GUI.enabled = isValidated;
            if (GUILayout.Button("Duplicate"))
            {
                duplicator.Duplicate();
                EditorUtility.SetDirty(to);
            }
        }
    }
}

0 人点赞