Unity 编辑拓展(UI拖拽师失业)

先来看看效果

设计思路

  • 找到子gameObject身上的组件
  • 找到父gameObject的位置
  • 生成父类
  • 写入内存

CreateMember.cs

using UnityEngine;
using UnityEditor;
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;

namespace MLSpace.Editor
{
    public class CreateMember
    {
        private const string BR = "\n";
        private const string YH = "\"";
        private const string publicMember = "_b";
        private const string privateMember = "_i";
        private const string protectedMember = "_o";

        private static List<string> _memberNames = new List<string>();
        private static readonly string[] regularName = new string[] { "Image" };
        private const string TempTextPath = "CreateMember/Editor/MemberTemp.txt";
        private static bool _getChildByChild = false;

        [MenuItem("GameObject/CreateChildMember", priority = 0)]
        private static void CreateChildMember()
        {
            _getChildByChild = false;
            //找组件
            GameObject gameObject = (GameObject)Selection.activeObject;
            if (!gameObject)
            {
                Debug.LogWarning("Selection activeObject is empty!");
                return;
            }
            Component[] comps = gameObject.GetComponents<MonoBehaviour>();
            if (comps.Length == 0)
            {
                Debug.LogWarning(gameObject.name + " no component expand MonoBehaviour!");
                return;
            }
            GenerateCode(gameObject);
        }

        [MenuItem("GameObject/CreateChildByChildMember", priority = 0)]
        private static void CreateChildByChildMember()
        {
            _getChildByChild = true;
            //找组件
            GameObject gameObject = (GameObject)Selection.activeObject;
            if (!gameObject)
            {
                Debug.LogWarning("Selection activeObject is empty!");
                return;
            }
            Component[] comps = gameObject.GetComponents<MonoBehaviour>();
            if (comps.Length == 0)
            {
                Debug.LogWarning(gameObject.name + " no component expand MonoBehaviour!");
                return;
            }
            GenerateCode(gameObject);
        }

        private static void GenerateCode(GameObject gameObject)
        {
            //脚本位置
            string CodePath = GetPath(GetBriefComponentName(gameObject));
            if (CodePath == "")
            {
                Debug.Log("找不到脚本位置");
                return;
            }
            Debug.Log(CodePath);
            if (CodePath.IndexOf("Packages/com") != -1)
            {
                Debug.LogWarning(CodePath + " is system folder");
                return;
            }
            //生成分类
            string newCodePath = CodePath.Remove(CodePath.Length - 2) + "Member.cs";
            string templatePath = Path.Combine(Application.dataPath, TempTextPath);
            string codePath = newCodePath;
            string templateContents = File.ReadAllText(templatePath);
            string result = "";
            using (TextReader reader = new StringReader(templateContents))
            {
                while (reader.Peek() != -1)
                {
                    string line = reader.ReadLine();
                    if (line.Contains("__DATA_TABLE_CREATE_TIME__"))
                    {
                        line = line.Replace("__DATA_TABLE_CREATE_TIME__", DateTime.UtcNow.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss.fff"));
                    }
                    if (line.Contains("__CLASSNAME__"))
                    {
                        line = line.Replace("__CLASSNAME__", GetBriefComponentName(gameObject));
                    }
                    if (line.Trim().Equals("__MEMBERNAME__"))
                    {
                        result += GetMemberNameStr(gameObject);
                        continue;
                    }
                    if (line.Trim().Equals("__GETCOMPONENT__"))
                    {
                        result += GetGetComponentStr(gameObject);
                        continue;
                    }
                    result += line + "\n";
                }
                reader.Close();
            }
            File.WriteAllText(codePath, result);
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
            Debug.Log(newCodePath + "create success");
        }

        /// <summary>
        /// 获取成员str
        /// </summary>
        /// <param name="go"></param>
        /// <returns></returns>
        private static string GetMemberNameStr(GameObject go)
        {
            string str = "";
            _memberNames.Clear();
            Transform[] childs = _getChildByChild ? GetChildsByChild(go) : GetChilds(go);
            for (int i = 0; i < childs.Length; i++)
            {
                if (childs[i].name.StartsWith(publicMember))
                {
                    string memberName = InitialsCapitalize(childs[i].name);
                    _memberNames.Add(memberName);
                    str += "" +
                        "        public " + GetBriefComponentName(childs[i].gameObject) + " " + memberName + ";" + BR;
                }
                if (childs[i].name.StartsWith(privateMember))
                {
                    string memberName = InitialsLowercase(childs[i].name);
                    _memberNames.Add(memberName);
                    str += "" +
                        "        private " + GetBriefComponentName(childs[i].gameObject) + " " + memberName + "; " + BR;
                }
                if (childs[i].name.StartsWith(protectedMember))
                {
                    string memberName = InitialsCapitalize(childs[i].name);
                    _memberNames.Add(memberName);
                    str += "" +
                        "        protected " + GetBriefComponentName(childs[i].gameObject) + " " + memberName + "; " + BR;
                }
            }
            return str;
        }

        /// <summary>
        /// 方法体内
        /// </summary>
        /// <param name="go"></param>
        /// <returns></returns>
        private static string GetGetComponentStr(GameObject go)
        {
            string str = "";
            int index = 0;
            Transform[] childs = _getChildByChild ? GetChildsByChild(go) : GetChilds(go);
            for (int i = 0; i < childs.Length; i++)
            {
                if (childs[i].name.StartsWith(publicMember)
                    || childs[i].name.StartsWith(privateMember)
                    || childs[i].name.StartsWith(protectedMember))
                {
                    str += "" +
                        "            " + _memberNames[index] + " = " +
                        "transform.FindChildByChild(" + YH + childs[i].name + YH + ")." +
                        "GetComponent<" + GetBriefComponentName(childs[i].gameObject) + ">();" + BR;
                    index++;
                }
            }
            return str;
        }

        private static Transform[] GetChilds(GameObject go)
        {
            Transform[] ts = new Transform[go.transform.childCount];
            for (int i = 0; i < ts.Length; i++)
            {
                ts[i] = go.transform.GetChild(i);
            }
            return ts;
        }

        private static Transform[] GetChildsByChild(GameObject go)
        {
            Transform[] ts = go.transform.GetComponentsInChildren<Transform>();
            return ts;
        }

        #region Tools
        //大写
        private static string InitialsCapitalize(string str)
        {
            string newStr = CropCharTwo(str);
            return newStr.First().ToString().ToUpper() + newStr.Substring(1);
        }
        //小写
        private static string InitialsLowercase(string str)
        {
            string newStr = CropCharTwo(str);
            return "_" + newStr.First().ToString().ToLower() + newStr.Substring(1);
        }
        //裁剪
        private static string CropCharTwo(string str)
        {
            return str.Remove(0, 2);
        }
        /// <summary>
        /// 获取组件名字(包含命名空间)
        /// </summary>
        /// <param name="go"></param>
        /// <returns></returns>
        private static string GetComponentName(GameObject go)
        {
            Component[] comps = go.GetComponents<MonoBehaviour>();
            if (comps.Length == 0)
            {
                Debug.LogWarning(go.name + " no component expand MonoBehaviour!");
                return "Transform";
            }
            return comps[comps.Length - 1].GetType().ToString();
        }

        /// <summary>
        /// 获取组件简单名字
        /// </summary>
        /// <param name="go"></param>
        /// <returns></returns>
        private static string GetBriefComponentName(GameObject go)
        {
            string name = GetComponentName(go);
            string[] newNames = name.Split('.');
            string BriefName = newNames[newNames.Length - 1];
            return BriefName;
        }

        /// <summary>
        /// 获取脚本路径
        /// </summary>
        /// <param name="_scriptName"></param>
        /// <returns></returns>
        static string GetPath(string _scriptName)
        {
            Debug.Log("scriptName " + _scriptName);
            for (int i = 0; i < regularName.Length; i++)
            {
                if (regularName[i] == _scriptName) return "";
            }
            string[] newPath = _scriptName.Split('.');
            string[] path = UnityEditor.AssetDatabase.FindAssets(newPath[newPath.Length - 1]);
            for (int i = 0; i < path.Length; i++)
            {
                string _path = AssetDatabase.GUIDToAssetPath(path[i]);
                string[] names = _path.Split('/');
                if (names[names.Length - 1].Equals(string.Format("{0}.cs", _scriptName)))
                {
                    if (File.Exists(_path) && _path.EndsWith(".cs"))
                    {
                        return _path;
                    }
                }
            }
            return "";
        }
        #endregion
    }
}

MemberTemp.txt


using System;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using UnityGameFramework.Runtime;
//------------------------------------------------------------
// 此文件由工具自动生成,请勿直接修改。
// 生成时间:__DATA_TABLE_CREATE_TIME__
//------------------------------------------------------------
namespace MLSpace
{
    public partial class __CLASSNAME__
    {

        __MEMBERNAME__

        protected virtual void InitMember()
        {
            __GETCOMPONENT__
        }
    }
}

编辑器拓展真有意思!🤡