【为什么要做自动化工具】

工具类的创建是为了解决实际问题或者优化既有流程,我们来先看看一些项目里面经常遇到的问题。

下面这个工具就是可以直接创建一个功能的基础脚本类,就不用每次去复制上次的代码了。然后再帮我们把那些乱七八糟又数不胜数的按钮、文字、图片组件都自动生成在脚本里面,然后自己去关联好引用,一下就能节省好多重复的活。

效果图

####简单的 一层

####复杂点的 管理Panel 子管理Panel 孙管理


代码部分解析

####1 枚举类型 UIMarkType 对应指定的类型 UIType是默认自有的类型可以自己拓展

public enum UIMarkType{
DefaultUnityElement = 0,
Element = 1}
public enum UIType
{
Transform = 0,
Image = 1,
RawImage = 2,
Button = 3,
Toggle = 4,
Slider = 5,
Scrollbar = 6,
Dropdown = 7,
InputField = 8,
ScrollRect = 9,
Text = 10,
ToggleGroup = 11,
Canvas = 12,
RectTransform = 13,
Animator = 14,
IMark = 15,

}

#####2 接口IMark 主要用于拓展

public interface IMark
{
string ComponentName { get; }UIMarkType GetUIMarkType();}

ComponentName获取要创建的类型字符
GetUIMarkType() 获取当前UIMarkType

####3 UIMark标签类 用于标记生成什么样

public class UIMark : MonoBehaviour, IMark
{
[Header("指定类型")]
public UIMarkType MarkType = UIMarkType.DefaultUnityElement;
[Header("当前选择创建属性类型")]
public UIType CreateType;[Header("创建脚本类名")]
public string CustomComponentName;public UIMarkType GetUIMarkType()
{return MarkType;
}public virtual string ComponentName
{get{if (MarkType == UIMarkType.DefaultUnityElement){if (CreateType == UIType.IMark){return GetComponents<IMark>().First(v=>v.GetType()!=this.GetType()).ComponentName;}return CreateType.ToString();}return CustomComponentName;}
}public void InitCreateType()
{if (MarkType == UIMarkType.DefaultUnityElement){var TempMark = GetComponents<IMark>().Where(v => v.GetType() != this.GetType());if (TempMark.Count()>0)CreateType = UIType.IMark;else  if (null != GetComponent<ScrollRect>())CreateType = UIType.ScrollRect;else if (null != GetComponent<InputField>())CreateType = UIType.InputField;else if (null != GetComponent<Text>())CreateType = UIType.Text;else if (null != GetComponent<Button>())CreateType = UIType.Button;else if (null != GetComponent<RawImage>())CreateType = UIType.RawImage;else if (null != GetComponent<Toggle>())CreateType = UIType.Toggle;else if (null != GetComponent<Slider>())CreateType = UIType.Slider;else if (null != GetComponent<Scrollbar>())CreateType = UIType.Scrollbar;else if (null != GetComponent<Image>())CreateType = UIType.Image;else if (null != GetComponent<ToggleGroup>())CreateType = UIType.ToggleGroup;else if (null != GetComponent<Animator>())CreateType = UIType.Animator;else if (null != GetComponent<Canvas>())CreateType = UIType.Canvas;else if (null != GetComponent<RectTransform>())CreateType = UIType.RectTransform;else if (null != GetComponent<Transform>())CreateType = UIType.Transform;}
}}

实现了了IMark
[Header(“xxx”)]  在Inspector面板上给定义的字段的上一行加段描述
InitCreateType()是用来识别当前适合什么自有的类型 如果太多组件可能会错就要Inspector面板改了

####4 CustomEditorUIMarkEditor类 用于UIMark类的自定义Inspector面板

[CanEditMultipleObjects, CustomEditor(typeof(UIMark))]
public class CustomEditorUIMarkEditor : Editor
{
public override void OnInspectorGUI()
{EditorGUILayout.PropertyField(this.serializedObject.FindProperty("MarkType"));if (this.serializedObject.FindProperty("MarkType").enumValueIndex == 1){EditorGUILayout.PropertyField(this.serializedObject.FindProperty("CustomComponentName"));}else{EditorGUILayout.PropertyField(this.serializedObject.FindProperty("CreateType"));}// 应用属性修改this.serializedObject.ApplyModifiedProperties();
}}

EditorGUILayout.PropertyField 搜索自定义的类里面的属性名称 然后绘制
特性[CanEditMultipleObjects, CustomEditor(typeof(UIMark))] 每个需要重新自定义面板都需要打上这个特性标签

效果大概这样


####5 AddUIMark类 右键添加按钮UIMark的

public class AddUIMark
{
[MenuItem("GameObject/KGUI/AddUIMark", priority = 0)]
static void AddUIMarkMenu(){GameObject[] obj = Selection.gameObjects;for (int i = 0; i < obj.Length; i++){if (!obj[i].GetComponent<UIMark>()){obj[i].AddComponent<UIMark>().InitCreateType();}else{obj[i].GetComponent<UIMark>().InitCreateType();}}
}
}

MenuItem 按钮的定义 想要在Hierarchy视图右键的话 路径就要GameObject/下的 然后要选层级 默认层级是不出现在右键的

6 GeneratorData 就一些静态数据

public class GeneratorData
{
#region UIClasspublic static string UIClass =@"using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;
public class #类名# : MonoBehaviour
{//替换标签#region UIModule#成员##endregionpublic void Awake()
{InitFind();
}public void InitFind()
{
#查找#
}}
";#endregion
#region ElementClasspublic static string ElementClass =@"using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;
public class #类名# : MonoBehaviour
{
//这是子类
//替换标签#region UIModule#成员##endregionpublic void Awake()
{InitFind();
}public void InitFind()
{
#查找#
}}
";#endregionpublic static Type GetType(string name){// Type type=null;var AssemblyCSharp = AppDomain.CurrentDomain.GetAssemblies().First(v =>     v.FullName.StartsWith("Assembly-CSharp,"));return AssemblyCSharp.GetType(name);}
}

var AssemblyCSharp 是获取所有程序集筛选Assembly-CSharp 这个集

7 UICodeGenerator 一键生成添加脚本

public class UICodeGenerator
{private static Action ff;public static GameObject gg;public static string tt="fff";[MenuItem("GameObject/KGUI/生成脚本", priority = 0)]public static void UIScriptGenerator(){if (EditorPrefs.GetBool("ScriptGenerator")){return;}GameObject[] selectobjs = Selection.gameObjects;foreach (GameObject go in selectobjs){Generator(go);        }
}public static void ScriptGenerator(GameObject go,string UIClass, string Classname="")
{//选择的物体GameObject selectobj = go;//物体的子物体List<Transform> childList = selectobj.GetComponentsInChildren<Transform>(true).ToList();Debug.Log(childList);List<Transform> ElementList = childList.Where(v => { return v.GetComponent<UIMark>() && v.GetComponent<UIMark>().MarkType == UIMarkType.Element&&v!= go.transform; }).ToList();ElementList.ForEach(v =>{v.GetComponentsInChildren<Transform>(true).Where(Obj => {return Obj.GetComponent<UIMark>()&& Obj != v;}).ToList().ForEach(remove =>{childList.Remove(remove);});});if (childList.Contains(go.transform)){childList.Remove(go.transform);}//  List<Transform> childList = new List<Transform>(_transforms);//UI需要查询的物体var mainNode = childList.Where(v => v.GetComponent<UIMark>());var nodePathList = new Dictionary<string, string>();string ClassName = Classname == "" ? go.name : Classname;//循环得到物体路径foreach (Transform node in mainNode){Transform tempNode = node;string nodePath = "/" + tempNode.name;while (tempNode != go.transform){tempNode = tempNode.parent;if (tempNode != go.transform){int index = nodePath.IndexOf('/');nodePath = nodePath.Insert(index, "/" + tempNode.name);}}nodePath = nodePath.Substring(1);nodePathList.Add(node.name, nodePath);}//成员变量字符串string memberstring = "";//查询代码字符串string loadedcontant = "";foreach (Transform itemtran in mainNode){//每个类的名字 字符string typeStr = itemtran.GetComponent<UIMark>().ComponentName;// Debug.Log();memberstring += "public " + typeStr + " " + itemtran.gameObject.name + " = null;\r\n\t";//物体的路劲寻找 字符loadedcontant += "\t\t" + itemtran.name + " = " + "gameObject.transform.Find(\"" + nodePathList[itemtran.name] + "\").GetComponent<" + typeStr + ">();\r\n";}string scriptPath = Application.dataPath + "/Scripts/" + ClassName + ".cs";string classStr = "";gg = selectobj;tt = selectobj.name;if (!Directory.Exists(Application.dataPath + "/Scripts")){Directory.CreateDirectory(Application.dataPath + "/Scripts");}if (File.Exists(scriptPath)){FileStream classfile = new FileStream(scriptPath, FileMode.Open);StreamReader read = new StreamReader(classfile);classStr = read.ReadToEnd();read.Close();classfile.Close();File.Delete(scriptPath);//分割 区分手写和 生成的string splitStr = "//替换标签";string unchangeStr = Regex.Split(classStr, splitStr)[0];string changeStr = Regex.Split(GeneratorData.UIClass, splitStr)[1];StringBuilder build = new StringBuilder();build.Append(unchangeStr);build.Append(splitStr);build.Append(changeStr);classStr = build.ToString();}else{classStr =UIClass;}classStr = classStr.Replace("#类名#", ClassName);classStr = classStr.Replace("#查找#", loadedcontant);classStr = classStr.Replace("#成员#", memberstring);FileStream file = new FileStream(scriptPath, FileMode.CreateNew);StreamWriter fileW = new StreamWriter(file, System.Text.Encoding.UTF8);fileW.Write(classStr);fileW.Flush();fileW.Close();file.Close();Debug.Log("创建脚本 " + Application.dataPath + "/Scripts/" + ClassName + ".cs 成功!");
}public static void Generator(GameObject go)
{ScriptGenerator(go, GeneratorData.UIClass);go.GetComponentsInChildren<UIMark>(true).Where(v=>v.MarkType==UIMarkType.Element).ToList().ForEach(v=> {ScriptGenerator(v.gameObject, GeneratorData.ElementClass,v.CustomComponentName);});EditorPrefs.SetBool("ScriptGenerator", true);AssetDatabase.SaveAssets();AssetDatabase.Refresh();}[UnityEditor.Callbacks.DidReloadScripts]
public static void AddScript()
{if (!EditorPrefs.GetBool("ScriptGenerator")){return;          }EditorPrefs.SetBool("ScriptGenerator", false);AssetDatabase.Refresh();Selection.gameObjects.ToList().ForEach(v =>{if (!v.GetComponent(GeneratorData.GetType(v.name)))v.AddComponent(GeneratorData.GetType(v.name));v.GetComponentsInChildren<UIMark>(true).Where(element => element.MarkType == UIMarkType.Element).ToList().ForEach(elementMark =>{if (!elementMark.GetComponent(GeneratorData.GetType(elementMark.CustomComponentName))){elementMark.gameObject.AddComponent(GeneratorData.GetType(elementMark.CustomComponentName));UnityEngine.Object.DestroyImmediate(elementMark);}});});Debug.Log(tt+12344);}

}

EditorPrefs.Set/GetBool 用于面板存取数据的

UIScriptGenerator()会遍历当前选择的物体进行生成脚本
Generator() 处理生成脚本的逻辑

ScriptGenerator() 指定物体为他生成相应的脚本

先筛选出符合条件的属性的 mainNode
循环得到 物体的路径 生成路径字符
判断是否含有该文件夹没有则创建

 if (!Directory.Exists(Application.dataPath + "/Scripts")){Directory.CreateDirectory(Application.dataPath + "/Scripts");}

通过File.Exists判断是否有该脚本 有的就只是修改脚本没有就创建

AddScript() 代码生成后 的添加操作

特性[UnityEditor.Callbacks.DidReloadScripts] 用于脚本改动的回调

好了 以上就是 整个过程


工程地址 https://github.com/LKaiGuo/KGScriptGenerator 喜欢给个星星

Unity工具类扩展——UGUI代码/脚本自动化生成 (一)相关推荐

  1. Unity 工具类 之 编辑扩展器 之 简单的音效管理编辑扩展器面板实现

    Unity 工具类 之 编辑扩展器 之 简单的音效管理编辑扩展器面板实现 目录 Unity 工具类 之 编辑扩展器 之 简单的音效管理编辑扩展器面板实现 一.简单介绍 二.实现原理 三.注意事项 四. ...

  2. Unity 工具类 之 Excel 转换为 json、csv、xml、lua格式

    Unity 工具类 之 Excel 转换为 json.csv.xml.csv 格式 目录 Unity 工具类 之 Excel 转换为 json.csv.xml.csv 格式 一.介绍 二.操作原理 三 ...

  3. Unity 工具类 之 WWW/UnityWebRequest 下载压缩文件(zip),解压到本地且加载使用解压数据的简单案例(内也含压缩文件例子)

    Unity 工具类 之 WWW/UnityWebRequest 网络下载压缩文件(zip),解压到本地,且加载使用解压数据的简单案例(内也含压缩文件例子) 目录 Unity 工具类 之 WWW/Uni ...

  4. Unity 工具类 之 贝塞尔 Bezier 曲线

    Unity 工具类 之 贝塞尔 Bezier 曲线 目录 Unity 工具类 之 贝塞尔 Bezier 曲线 一.简单介绍 二.原理与分类 三.公式与原理图演示 五.注意事项 六.样例使用步骤(三次贝 ...

  5. Unity 工具类 之 简单快速 获取当前所在位置,所在城市,经纬度等

    Unity  工具类 之 简单快速 获取当前所在位置,所在城市,经纬度等 目录 Unity  工具类 之 简单快速 获取当前所在位置,所在城市,经纬度等 一.方法提要: 二.使用注意: 三.json ...

  6. php解析命令行参数选项,PHP 命令行参数解析工具类的示例代码

    PHP 命令行参数解析工具类的示例代码 /** * 命令行参数解析工具类 * @author guolinchao */ class CommandLine { // 临时记录短选项的选项值 priv ...

  7. Java操作百万数据量Excel导入导出工具类(程序代码教程)

    Java操作百万数据量Excel导入导出工具类(程序代码教程): # 功能实现1.自定义导入数据格式,支持配置时间.小数点类型(支持单/多sheet)(2种方式:本地文件路径导入(只支持xls.xls ...

  8. Unity 工具类 之 Blender 的下载和简单使用(为捏脸做准备)

    Unity 工具类 之 Blender 的下载和使用(为捏脸做准备) 目录 Unity 工具类 之 Blender 的下载和使用 一.简单介绍 二.下载地址 三.安装 四.简单使用 1.设置成中文界面 ...

  9. PDF转换工具类(byte[]转PDF并生成文件)

    PDF转换工具类(byte[]转PDF并生成文件) 对html转为标准的xhtml public byte[] transferHtml2XHtml(byte[] html){Tidy tidy = ...

最新文章

  1. Python查找-二分查找
  2. vue父子组件写法,数据传递,顺便封装 element-ui的弹窗组建
  3. flask_入门教程之一
  4. CentOS中无法使用setup命令 -bash:setup: command not found
  5. 画圆怎么编程python_简单实现python画圆功能
  6. excel自动保存_萌新必看!python处理excel实例
  7. mysql 命令限制_MySQL 命令总结
  8. JS学习总结(5)——循环语句
  9. 宠物管理系统CLI版本(Python实现/内附完整代码)
  10. hive3.1.2 flink写数据到hive报错Reading or writing ACID table.....
  11. CentOS换源、linux配置IP、腾讯云SHH秘钥、公钥
  12. Aspose.Words.FileCorruptedException: The document appears to be corrupted and cannot be loaded
  13. Rasa 聊天机器人Rasa_NLU_Chi
  14. 天津大学计算机学院王思宇,复杂计算精准化,天津大学选择了宝德HPC
  15. 微信7.0.10正式版来了!朋友圈斗图彻底关闭了!
  16. 企业中如何做好文化建设?
  17. 短信(SMS)的解释分类以及原理
  18. Qt报错:XXX does not name a type
  19. 小鼠心肌细胞培养方法
  20. Spring Actuator介绍及使用

热门文章

  1. 5G毫米波和超宽带信号的验证和测试
  2. 日均100w次登陆请求, 8G 内存该如何设置JVM参数?
  3. 结构体和类的区别 (objective c)
  4. mysql dns 注入_数据库DNSLog外带注入-总结
  5. android layout_margintop,layout_margintop
  6. 2018年工作年度总结(前端开发)
  7. maven Implementing class
  8. Structured Streaming整合kafka
  9. 如何在 R 中使用 Fisher 的最小显着性差异 (LSD)
  10. filecoin lotus deal(交易)状态及 sectors(扇区)状态