找回密碼
 注冊帳號

掃一掃,訪問微社區

開果 Unity工具類擴展——UGUI代碼/腳本自動化生成 (一)

63
回復
1322
查看
打印 上一主題 下一主題
[ 復制鏈接 ]

6

主題

10

帖子

87

積分

Rank: 9Rank: 9Rank: 9

UID
327626
好友
1
蠻牛幣
59
威望
0
注冊時間
2019-7-19
在線時間
59 小時
最后登錄
2019-8-13

馬上注冊,結交更多好友,享用更多功能,讓你輕松玩轉社區。

您需要 登錄 才可以下載或查看,沒有帳號?注冊帳號

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熟悉之中
795/1000
排名
3900
昨日變化

9

主題

127

帖子

795

積分

Rank: 5Rank: 5

UID
232340
好友
0
蠻牛幣
116
威望
0
注冊時間
2017-7-15
在線時間
275 小時
最后登錄
2019-8-11
板凳
2019-7-22 15:21:34 只看該作者
學習學習
回復

使用道具 舉報

7日久生情
2674/5000
排名
286
昨日變化

0

主題

37

帖子

2674

積分

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

UID
45288
好友
0
蠻牛幣
9021
威望
0
注冊時間
2014-9-17
在線時間
717 小時
最后登錄
2019-8-8
地板
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熟悉之中
920/1000
排名
3186
昨日變化

0

主題

116

帖子

920

積分

Rank: 5Rank: 5

UID
92192
好友
1
蠻牛幣
1565
威望
0
注冊時間
2015-4-14
在線時間
338 小時
最后登錄
2019-8-13
6#
2019-7-22 15:52:58 只看該作者
謝謝 下載下來學習下
回復 支持 反對

使用道具 舉報

6蠻牛粉絲
1454/1500
排名
2154
昨日變化

15

主題

209

帖子

1454

積分

Rank: 6Rank: 6Rank: 6

UID
131349
好友
3
蠻牛幣
553
威望
0
注冊時間
2015-12-9
在線時間
584 小時
最后登錄
2019-8-12
7#
2019-7-22 18:00:08 只看該作者
謝謝分享
回復

使用道具 舉報

排名
343
昨日變化

45

主題

389

帖子

4907

積分

Rank: 9Rank: 9Rank: 9

UID
42814
好友
38
蠻牛幣
85
威望
0
注冊時間
2014-8-31
在線時間
1559 小時
最后登錄
2019-8-13

專欄作家

QQ
8#
2019-7-22 18:21:23 只看該作者
Unity工具類擴展——UGUI代碼/腳本自動化生成 (一)
回復 支持 反對

使用道具 舉報

排名
343
昨日變化

45

主題

389

帖子

4907

積分

Rank: 9Rank: 9Rank: 9

UID
42814
好友
38
蠻牛幣
85
威望
0
注冊時間
2014-8-31
在線時間
1559 小時
最后登錄
2019-8-13

專欄作家

QQ
9#
2019-7-22 18:21:26 只看該作者
Unity工具類擴展——UGUI代碼/腳本自動化生成 (一)
回復 支持 反對

使用道具 舉報

排名
343
昨日變化

45

主題

389

帖子

4907

積分

Rank: 9Rank: 9Rank: 9

UID
42814
好友
38
蠻牛幣
85
威望
0
注冊時間
2014-8-31
在線時間
1559 小時
最后登錄
2019-8-13

專欄作家

QQ
10#
2019-7-22 18:21:28 只看該作者
Unity工具類擴展——UGUI代碼/腳本自動化生成 (一)
回復 支持 反對

使用道具 舉報

排名
343
昨日變化

45

主題

389

帖子

4907

積分

Rank: 9Rank: 9Rank: 9

UID
42814
好友
38
蠻牛幣
85
威望
0
注冊時間
2014-8-31
在線時間
1559 小時
最后登錄
2019-8-13

專欄作家

QQ
11#
2019-7-22 18:21:32 只看該作者
Unity工具類擴展——UGUI代碼/腳本自動化生成 (一)
回復 支持 反對

使用道具 舉報

2初來乍到
146/150
排名
26985
昨日變化

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日久生情
3741/5000
排名
172
昨日變化

0

主題

123

帖子

3741

積分

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

UID
45275
好友
0
蠻牛幣
2152
威望
0
注冊時間
2014-9-17
在線時間
1360 小時
最后登錄
2019-8-13
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蠻牛粉絲
1058/1500
排名
3074
昨日變化

1

主題

68

帖子

1058

積分

Rank: 6Rank: 6Rank: 6

UID
196658
好友
0
蠻牛幣
1361
威望
0
注冊時間
2016-12-28
在線時間
507 小時
最后登錄
2019-8-13
15#
2019-7-23 09:05:39 只看該作者
感謝分享
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 注冊帳號

本版積分規則

捕鱼王怎么进不去 宝马五系 娱乐套 怎么用 彩票绑定银行卡安全吗 棋牌斗牛如何看牌抢庄 白小如三肖六码期期准百度网 四川时时app 篮球即时比分 8天游 欢乐生肖规则 十一选五九码复式 北京pk10赛车稳赚技巧 秒速时时有假吗 重庆时时猜龙虎走势图 河北时时怎么玩法 时时彩大小单双投注法 计划软件免费版 幸运28的计算方法