当前位置:   article > 正文

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

unityui框架代码自动化

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

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

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

效果图

####简单的 一层
qqw12.gif

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

image


代码部分解析

####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,
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

}

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

public interface IMark
{
string ComponentName { get; }


UIMarkType GetUIMarkType();

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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;

    }
}

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82

实现了了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();
}

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

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

效果大概这样
image.png
image.png


####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();
        }

    }
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

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

6 GeneratorData 就一些静态数据
public class GeneratorData
{
#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);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71

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);
  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205

}

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

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

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

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

 if (!Directory.Exists(Application.dataPath + "/Scripts"))
        {
            Directory.CreateDirectory(Application.dataPath + "/Scripts");
        }
  • 1
  • 2
  • 3
  • 4

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

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

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

好了 以上就是 整个过程

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/115291
推荐阅读
相关标签
  

闽ICP备14008679号