开果 Unity工具类扩展——UGUI代码/脚本自动化生成 (一)

71
回复
1878
查看
打印 上一主题 下一主题
[ 复制链接 ]

12

主题

18

帖子

138

积分

Rank: 9Rank: 9Rank: 9

UID
327626
好友
3
蛮牛币
106
威望
0
注册时间
2019-7-19
在线时间
94 小时
最后登录
2019-8-29

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
本帖最后由 开果 于 2019-7-24 13:53 编辑

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

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

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

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



代码部分解析


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


[C#] 纯文本查看 复制代码
 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    主要用于拓展  


[C#] 纯文本查看 复制代码
 public interface IMark    {
    string ComponentName { get; }


    UIMarkType GetUIMarkType();

    }


ComponentName获取要创建的类型字符

GetUIMarkType() 获取当前UIMarkType


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


[C#] 纯文本查看 复制代码
   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面板


[C#] 纯文本查看 复制代码
    [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的


[C#] 纯文本查看 复制代码
  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();
            }

        }
    }
    }
[i][i][i]


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

6 GeneratorData 就一些静态数据


[C#] 纯文本查看 复制代码
    [/i][/i][/i][i][i][i] public class GeneratorData
[/i][/i][/i][i][i][i]    {
    #region UIClass

    public static string UIClass =
       @"using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.EventSystems;
    using System;
    public class #类名# : MonoBehaviour
    {

    //替换标签

    #region UIModule

    #成员#

    #endregion

     public void Awake()
    {
        InitFind();
    }

     public void InitFind()
    {
    #查找#
    }

    }
    ";
        #endregion
    #region ElementClass

      public static string ElementClass =
     @"using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.EventSystems;
    using System;
    public class #类名# : MonoBehaviour
    {
    //这是子类
    //替换标签

    #region UIModule

    #成员#

    #endregion

     public void Awake()
    {
        InitFind();
    }

     public void InitFind()
    {
    #查找#
    }

    }
    ";
        #endregion
        public 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 一键生成添加脚本

[C#] 纯文本查看 复制代码
   [/i][/i][/i][i][i][i] public class UICodeGenerator
[/i][/i][/i][i][i][i]    {
        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]用于脚本改动的回调

好了 以上就是 整个过程
工程地址
游客,如果您要查看本帖隐藏内容请回复



u3d萌新QQ群844087555 欢迎进来灌水=。=






参与人数 1鲜花 +2 收起 理由
lezard618 + 2 很给力!

查看全部评分总评分 : 鲜花 +2

回复

使用道具 举报

0

主题

44

帖子

58

积分

Rank: 2Rank: 2

UID
326141
好友
0
蛮牛币
68
威望
0
注册时间
2019-7-1
在线时间
14 小时
最后登录
2019-8-12
沙发
2019-7-22 14:51:01 只看该作者
6666666666666666666666666666666666666
回复 支持 反对

使用道具 举报

5熟悉之中
804/1000
排名
3900
昨日变化

9

主题

130

帖子

804

积分

Rank: 5Rank: 5

UID
232340
好友
0
蛮牛币
108
威望
0
注册时间
2017-7-15
在线时间
281 小时
最后登录
2019-8-29
板凳
2019-7-22 15:21:34 只看该作者
学习学习
回复

使用道具 举报

7日久生情
2679/5000
排名
286
昨日变化

0

主题

38

帖子

2679

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
45288
好友
0
蛮牛币
9016
威望
0
注册时间
2014-9-17
在线时间
721 小时
最后登录
2019-8-25
地板
2019-7-22 15:29:08 只看该作者
学习学习学习学习学习学习学习
回复 支持 反对

使用道具 举报

3偶尔光临
194/300
排名
34887
昨日变化

0

主题

51

帖子

194

积分

Rank: 3Rank: 3Rank: 3

UID
288889
好友
0
蛮牛币
9
威望
0
注册时间
2018-7-7
在线时间
135 小时
最后登录
2019-8-8
5#
2019-7-22 15:50:27 只看该作者
回复

使用道具 举报

5熟悉之中
926/1000
排名
3186
昨日变化

0

主题

118

帖子

926

积分

Rank: 5Rank: 5

UID
92192
好友
1
蛮牛币
1579
威望
0
注册时间
2015-4-14
在线时间
342 小时
最后登录
2019-8-29
6#
2019-7-22 15:52:58 只看该作者
谢谢 下载下来学习下
回复 支持 反对

使用道具 举报

6蛮牛粉丝
1457/1500
排名
2154
昨日变化

15

主题

209

帖子

1457

积分

Rank: 6Rank: 6Rank: 6

UID
131349
好友
3
蛮牛币
551
威望
0
注册时间
2015-12-9
在线时间
587 小时
最后登录
2019-8-26
7#
2019-7-22 18:00:08 只看该作者
谢谢分享
回复

使用道具 举报

排名
343
昨日变化

45

主题

389

帖子

4909

积分

Rank: 9Rank: 9Rank: 9

UID
42814
好友
38
蛮牛币
94
威望
0
注册时间
2014-8-31
在线时间
1561 小时
最后登录
2019-8-22

专栏作家

8#
2019-7-22 18:21:23 只看该作者
Unity工具类扩展——UGUI代码/脚本自动化生成 (一)
回复 支持 反对

使用道具 举报

排名
343
昨日变化

45

主题

389

帖子

4909

积分

Rank: 9Rank: 9Rank: 9

UID
42814
好友
38
蛮牛币
94
威望
0
注册时间
2014-8-31
在线时间
1561 小时
最后登录
2019-8-22

专栏作家

9#
2019-7-22 18:21:26 只看该作者
Unity工具类扩展——UGUI代码/脚本自动化生成 (一)
回复 支持 反对

使用道具 举报

排名
343
昨日变化

45

主题

389

帖子

4909

积分

Rank: 9Rank: 9Rank: 9

UID
42814
好友
38
蛮牛币
94
威望
0
注册时间
2014-8-31
在线时间
1561 小时
最后登录
2019-8-22

专栏作家

10#
2019-7-22 18:21:28 只看该作者
Unity工具类扩展——UGUI代码/脚本自动化生成 (一)
回复 支持 反对

使用道具 举报

排名
343
昨日变化

45

主题

389

帖子

4909

积分

Rank: 9Rank: 9Rank: 9

UID
42814
好友
38
蛮牛币
94
威望
0
注册时间
2014-8-31
在线时间
1561 小时
最后登录
2019-8-22

专栏作家

11#
2019-7-22 18:21:32 只看该作者
Unity工具类扩展——UGUI代码/脚本自动化生成 (一)
回复 支持 反对

使用道具 举报

2初来乍到
146/150
排名
26986
昨日变化

0

主题

48

帖子

146

积分

Rank: 2Rank: 2

UID
127902
好友
0
蛮牛币
19
威望
0
注册时间
2015-11-4
在线时间
84 小时
最后登录
2019-7-31
12#
2019-7-23 07:56:42 来自Mobile--- 只看该作者
学习学习
回复

使用道具 举报

7日久生情
3754/5000
排名
172
昨日变化

0

主题

123

帖子

3754

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
45275
好友
0
蛮牛币
2289
威望
0
注册时间
2014-9-17
在线时间
1373 小时
最后登录
2019-8-29
13#
2019-7-23 08:53:38 只看该作者
感谢分享
回复

使用道具 举报

7日久生情
2390/5000
排名
479
昨日变化

2

主题

97

帖子

2390

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
69739
好友
0
蛮牛币
3056
威望
0
注册时间
2015-1-20
在线时间
749 小时
最后登录
2019-8-2
14#
2019-7-23 08:58:15 只看该作者
学习学习
回复

使用道具 举报

6蛮牛粉丝
1067/1500
排名
3074
昨日变化

1

主题

68

帖子

1067

积分

Rank: 6Rank: 6Rank: 6

UID
196658
好友
0
蛮牛币
1398
威望
0
注册时间
2016-12-28
在线时间
516 小时
最后登录
2019-8-29
15#
2019-7-23 09:05:39 只看该作者
感谢分享
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

document.write ('