123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515 |
- using UnityEngine;
- using System.Collections;
- using UnityEditor;
- using System.Collections.Generic;
- using UnityEngine.EventSystems;
- using UnityEngine.Events;
- using UnityEngine.UI;
- using System.Text;
- using System;
- using System.IO;
- using System.Reflection;
- /// <summary>
- /// 描述:编辑器插件,快速生成UI代码(只检索以特定文本开头的组件,img_图片 btn_按钮 txt_文本)
- /// 作者:WJ
- /// </summary>
- public class QuickUI
- {
- /// <summary>
- /// UI的根游戏体
- /// </summary>
- private static GameObject mRoot = null;
- /// <summary>
- /// ui控件列表
- /// </summary>
- private static List<UIBehaviour> mUIWidgets = new List<UIBehaviour>();
- /// <summary>
- /// 缓存所有变量名和对应控件对象,对重名作处理
- /// </summary>
- private static Dictionary<string, object> mVariableNameDic = new Dictionary<string, object>();
- /// <summary>
- /// 组件名称检索列表(只检索以列表开头命名的组件)
- /// </summary>
- private static List<string> mWidgetsNameSearchList = new List<string> { "btn_", "img_", "txt_" };
- /// <summary>
- /// 组件类型检索列表(只检索里的组件)
- /// </summary>
- private static List<string> mWidgetsTypeSearchList = new List<string> { "Button", "Image", "Text" };
- /// <summary>
- /// 变量编号
- /// </summary>
- private static int mVariableNum = 0;
- /// <summary>
- /// 变量代码
- /// </summary>
- private static StringBuilder mCodeStateText = null;
- /// <summary>
- /// 事件代码
- /// </summary>
- private static StringBuilder mCodeEventText = null;
- /// <summary>
- /// 初始化变量代码
- /// </summary>
- private static StringBuilder mCodeAssignText = null;
- /// <summary>
- /// 开始函数
- /// </summary>
- private static StringBuilder mStartText = null;
- /// <summary>
- /// 更新函数
- /// </summary>
- private static StringBuilder mUpdateText = null;
- /// <summary>
- /// 函数注释
- /// </summary>
- private static string funNotes = "\n\t/// <summary>\n\t/// {0}\n\t/// </summary>";
- /// <summary>
- /// 生成UI代码
- /// </summary>
- [MenuItem("Tools/GenerateUICode")]
- public static void GenerateUICode()
- {
- // 自动赋值选中的GameObject
- mRoot = Selection.activeGameObject;
- if (mRoot == null)
- {
- Debug.LogError("未选中UI根节点");
- return;
- }
- // 创建开始函数
- StartFunCode();
- // 创建更新函数
- UpdateFunCode();
- // 查找UI组件
- FindUIWidgets();
- // 生成UI组件变量
- GenerateVariable();
- // 给UI组件变量赋值
- AssignmentVariable();
- // 给UI组件绑定事件
- BuildEventCode();
- // 生成脚本
- CreateUIScript();
- }
- /// <summary>
- /// 查找UI组件
- /// </summary>
- private static void FindUIWidgets()
- {
- // 查找节点下所有UI元素
- RecursiveUI(mRoot.transform, (tran) =>
- {
- UIBehaviour[] widgets = tran.GetComponents<UIBehaviour>();
- for (int i = 0; i < widgets.Length; i++)
- {
- var widget = widgets[i];
- if (widget != null && !mUIWidgets.Contains(widget))
- {
- // 只检测特定类型
- Type type = widget.GetType();
- if (mWidgetsTypeSearchList.Contains(type.Name) == false)
- {
- continue;
- }
- // 图片组件中有按钮,则不添加
- if (type.Name == "Image")
- {
- Button button = widget.GetComponent<Button>();
- if (button != null)
- {
- continue;
- }
- }
- string widName = widget.name;
- for (int j = 0; j < mWidgetsNameSearchList.Count; j++)
- {
- if (widName.Contains(mWidgetsNameSearchList[j]))
- {
- mUIWidgets.Add(widget);
- break;
- }
- }
- }
- }
- });
- }
- /// <summary>
- /// 控件遍历声明,0:类型 1:名称
- /// </summary>
- private const string variableCodeFmt = "\tprivate {0} {1}; \n";
- /// <summary>
- /// 生成变量
- /// </summary>
- /// <returns></returns>
- private static string GenerateVariable()
- {
- mVariableNum = 0;
- mVariableNameDic.Clear();
- mCodeStateText = null;
- mCodeStateText = new StringBuilder();
- //控件列表
- for (int i = 0; i < mUIWidgets.Count; i++)
- {
- if (mUIWidgets[i] == null) continue;
- Type type = mUIWidgets[i].GetType();
- if (type == null)
- {
- Debug.LogError("BuildUICode type error !");
- return "";
- }
- string typeName = type.Name;
- string variableName = mUIWidgets[i].name;
- variableName = variableName.Replace(' ', '_'); //命名有空格的情况
- //重名处理
- ++mVariableNum;
- if (mVariableNameDic.ContainsKey(variableName))
- {
- variableName += mVariableNum;
- }
- mVariableNameDic.Add(variableName, mUIWidgets[i]);
- mCodeStateText.AppendFormat(variableCodeFmt, typeName, variableName);
- }
- return mCodeStateText.ToString();
- }
- /// <summary>
- /// 函数开始格式
- /// </summary>
- public const string funStartFmt = "\n\tprivate void {0}() \n\t{{\n";
- /// <summary>
- /// 函数结束格式
- /// </summary>
- public const string funEndFmt = "\n\t}\n";
- /// <summary>
- /// 查找组件相关格式
- /// </summary>
- public const string findCodeFmt = "\t\t{0} = transform.Find(\"{1}\").GetComponent<{2}>(); \n";
- public const string findGameObjectCodeFmt = "\t\t{0} = transform.Find(\"{1}\").gameObject; \n";
- public const string findRootCodeFmt = "\t\t{0} = transform.GetComponent<{1}>(); \n";
- /// <summary>
- /// 给变量赋值
- /// </summary>
- private static void AssignmentVariable()
- {
- mCodeAssignText = new StringBuilder();
- mCodeAssignText.AppendFormat(funNotes, "初始化UI");
- mCodeAssignText.AppendFormat(funStartFmt, "InitUI");
- var allPath = GetChildrenPaths(mRoot);
- if (mVariableNameDic == null)
- {
- return;
- }
- //格式:变量名 = transform.Find("").Getcomponent<>();
- foreach (var name in mVariableNameDic.Keys)
- {
- var obj = mVariableNameDic[name];
- if (obj == null) continue;
- string path = "";
- bool isRootComponent = false;
- foreach (var tran in allPath.Keys)
- {
- if (tran == null) continue;
- UIBehaviour behav = obj as UIBehaviour;
- if (behav != null)
- {
- //判断是否挂在根上,根上不需要路径
- isRootComponent = behav.gameObject == mRoot;
- if (isRootComponent) break;
- if (behav.gameObject == tran.gameObject)
- {
- path = allPath[tran];
- break;
- }
- }
- else
- {
- if (tran.gameObject == obj)
- {
- path = allPath[tran];
- break;
- }
- }
- }
- if (obj is GameObject)
- {
- mCodeAssignText.AppendFormat(findGameObjectCodeFmt, name, path);
- }
- else
- {
- if (isRootComponent)
- {
- mCodeAssignText.AppendFormat(findRootCodeFmt, name, obj.GetType().Name);
- }
- else
- {
- mCodeAssignText.AppendFormat(findCodeFmt, name, path, obj.GetType().Name);
- }
- }
- }
- mCodeAssignText.Append(funEndFmt);
- }
- // 按钮绑定事件
- public const string btnBindingEventCode = "\t\tEventTriggerListener.Get({0}.gameObject).onClick = On{1}Click; \n";
- public const string btnCallbackCode = "\n\tprivate void On{0}Click(GameObject go)\n\t{{\n\n\t}}\n";
- /// <summary>
- /// 构建注册控件事件的代码
- /// </summary>
- /// <returns></returns>
- private static string BuildEventCode()
- {
- mCodeEventText = null;
- mCodeEventText = new StringBuilder();
- mCodeEventText.AppendFormat(funNotes, "添加事件");
- mCodeEventText.AppendFormat(funStartFmt, "AddEvent");
- // 添加事件的列表
- List<string> EventWidgets = new List<string>();
- EventWidgets.Add("Button");
- bool hasEventWidget = false; //标识是否有控件注册了事件
- for (int i = 0; i < mUIWidgets.Count; i++)
- {
- if (mUIWidgets[i] == null) continue;
- //剔除不是事件或者是事件但未勾选toggle的控件
- string typeName = mUIWidgets[i].GetType().Name;
- foreach (var vName in mVariableNameDic.Keys)
- {
- if (mUIWidgets[i].Equals(mVariableNameDic[vName]))
- {
- if (EventWidgets.Contains(typeName) == false)
- {
- continue;
- }
- string variableName = vName;
- if (!string.IsNullOrEmpty(variableName))
- {
- string methodName = variableName.Substring(variableName.IndexOf('_') + 1);
- if (mUIWidgets[i] is Button)
- {
- string onClickStr = string.Format(btnBindingEventCode, variableName, methodName);
- if (hasEventWidget)
- {
- string str = mCodeEventText.ToString();
- mCodeEventText.Insert(str.LastIndexOf(';') + 1, "\n" + onClickStr);
- }
- else
- {
- mCodeEventText.Append(onClickStr);
- }
- mCodeEventText.AppendFormat(funNotes, methodName + "按钮事件");
- mCodeEventText.AppendFormat(btnCallbackCode, methodName);
- hasEventWidget = true;
- }
- else
- {
- Debug.LogError("暂不支持的类型:" + mUIWidgets[i]);
- }
- }
- break;
- }
- }
- }
- string codeStr = mCodeEventText.ToString();
- if (hasEventWidget)
- {
- mCodeEventText.Insert(codeStr.LastIndexOf(';') + 1, funEndFmt);
- }
- else
- {
- mCodeEventText.Append(funEndFmt);
- }
- return mCodeEventText.ToString();
- }
- /// <summary>
- /// 开始函数代码
- /// </summary>
- private static void StartFunCode()
- {
- mStartText = new StringBuilder();
- mStartText.AppendFormat(funNotes, "开始");
- mStartText.AppendFormat(funStartFmt, "Start");
- mStartText.AppendFormat("\t\tInitUI();\n");
- mStartText.AppendFormat("\t\tAddEvent();");
- mStartText.Append(funEndFmt);
- }
- /// <summary>
- /// 更新函数代码
- /// </summary>
- private static void UpdateFunCode()
- {
- mUpdateText = new StringBuilder();
- mUpdateText.AppendFormat(funNotes, "更新");
- mUpdateText.AppendFormat(funStartFmt, "Update");
- mUpdateText.Append(funEndFmt);
- }
- /// <summary>
- /// UI 类名
- /// </summary>
- private static string mClassName = "";
- /// <summary>
- /// 类注释
- /// </summary>
- public const string mCodeAnnotation = @"
- /// <summary>
- /// 描述:
- /// 作者:
- /// </summary>";
- /// <summary>
- /// 类默认使用的命名空间
- /// </summary>
- public const string mUsingNamespace = "using UnityEngine;\nusing System.Collections;\nusing UnityEngine.UI;\n";
- /// <summary>
- /// 继承MonoBehaviour的类开始格式
- /// </summary>
- public const string mClassMonoStart = "\npublic class {0} : MonoBehaviour\n{{\n";
- /// <summary>
- /// 类结束格式
- /// </summary>
- public const string mClassEnd = "\n}\n";
- /// <summary>
- /// 生成C# UI脚本
- /// </summary>
- private static void CreateUIScript()
- {
- string path = EditorPrefs.GetString("create_script_folder", "");
- path = EditorUtility.SaveFilePanel("Create Script", path, mRoot.name + ".cs", "cs");
- if (string.IsNullOrEmpty(path)) return;
- int index = path.LastIndexOf('/');
- mClassName = path.Substring(index + 1, path.LastIndexOf('.') - index - 1);
- StringBuilder scriptBuilder = new StringBuilder();
- scriptBuilder.Append(mUsingNamespace);
- scriptBuilder.Append(mCodeAnnotation);
- scriptBuilder.AppendFormat(mClassMonoStart, mClassName);
- scriptBuilder.Append(mCodeStateText);
- scriptBuilder.Append(mStartText);
- scriptBuilder.Append(mCodeAssignText);
- scriptBuilder.Append(mCodeEventText);
- scriptBuilder.Append(mUpdateText);
- scriptBuilder.Append(mClassEnd);
- File.WriteAllText(path, scriptBuilder.ToString(), new UTF8Encoding(false));
- AssetDatabase.Refresh();
- Debug.Log("脚本生成成功,生成路径为:" + path);
- EditorPrefs.SetString("create_script_folder", path);
- }
- /// <summary>
- /// 遍历UI
- /// </summary>
- /// <param name="parent">父节点</param>
- /// <param name="callback">回调</param>
- public static void RecursiveUI(Transform parent, UnityAction<Transform> callback)
- {
- if (callback != null)
- {
- callback(parent);
- }
- if (parent.childCount >= 0)
- {
- for (int i = 0; i < parent.childCount; i++)
- {
- Transform child = parent.GetChild(i);
- RecursiveUI(child, callback);
- }
- }
- }
- /// <summary>
- /// 获取子节点的路径
- /// </summary>
- /// <param name="rootGo">GameObject</param>
- /// <returns>路径</returns>
- private static Dictionary<Transform, string> GetChildrenPaths(GameObject rootGo)
- {
- Dictionary<Transform, string> pathDic = new Dictionary<Transform, string>();
- string path = string.Empty;
- Transform[] tfArray = rootGo.GetComponentsInChildren<Transform>(true);
- for (int i = 0; i < tfArray.Length; i++)
- {
- Transform node = tfArray[i];
- string str = node.name;
- while (node.parent != null && node.gameObject != rootGo && node.parent.gameObject != rootGo)
- {
- str = string.Format("{0}/{1}", node.parent.name, str);
- node = node.parent;
- }
- path += string.Format("{0}\n", str);
- if (!pathDic.ContainsKey(tfArray[i]))
- {
- pathDic.Add(tfArray[i], str);
- }
- }
- return pathDic;
- }
- }
|