当前位置:   article > 正文

Unity:使用预制体自动生成代码脚本的技术实现_unity 怎么将obj转成脚本

unity 怎么将obj转成脚本

1、简述

Unity游戏开发中,使用预制体(Prefab)是一种有效的方式来重复利用对象和组件,提高开发效率。然而,当项目规模逐渐增大时,手动编写与每个预制体相关联的代码脚本可能会变得繁琐。为了提高开发效率,我们可以通过自动生成代码的方式,根据预制体的属性和组件生成相应的代码脚本。

2、为什么需要自动生成代码?

手动编写每个预制体相关的代码脚本可能会导致以下问题:

  • 重复劳动: 随着预制体数量的增加,手动创建与之关联的代码变得冗长且容易出错。
  • 维护困难: 当需要修改预制体的结构或属性时,需要手动同步修改相关的代码,容易出现不一致性。

3、技术实现

3.1 反射(Reflection)

Unity中的反射机制允许我们在运行时获取和使用程序集中的类型信息。通过反射,我们可以动态地获取预制体的属性和组件信息,从而生成相应的代码。

using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;

public class AutoBuild
{
    [MenuItem("生成/创建或刷新界面")]
    public static void BuildUIScript()
    {
        var dicUIType = new Dictionary<string, string>();
        dicUIType.Add("Img", "Image");
        dicUIType.Add("Btn", "Button");
        dicUIType.Add("Txt", "Text");
        dicUIType.Add("Tran", "Transform");
        dicUIType.Add("Input", "InputField");
        dicUIType.Add("Raw", "RawImage");
        dicUIType.Add("Drop", "Dropdown");
        dicUIType.Add("Slider", "Slider");
        dicUIType.Add("Scr", "Scrollbar");

        GameObject[] selectobjs = Selection.gameObjects;

        foreach (GameObject go in selectobjs)
        {
            //选择的物体
            GameObject selectobj = go.transform.root.gameObject;
            //物体的子物体
            Transform[] _transforms = selectobj.GetComponentsInChildren<Transform>(true);
            List<Transform> childList = new List<Transform>(_transforms);
            //UI需要查询的物体
            var mainNode = from trans in childList where trans.name.Contains('_') && dicUIType.Keys.Contains(trans.name.Split('_')[0]) select trans;
            var nodePathList = new Dictionary<string, string>();
            //循环得到物体路径
            foreach (Transform node in mainNode)
            {
                Transform tempNode = node;
                string nodePath = tempNode.name;
                if (tempNode.parent != selectobj.transform)
                {
                    nodePath = "/" +  tempNode.name;
                }

                while (tempNode != tempNode.root && (tempNode.parent != selectobj.transform))
                {
                    tempNode = tempNode.parent;
                    int index = nodePath.IndexOf('/');
                    string nodeName =  tempNode.name;
                    if (tempNode.parent != selectobj.transform)
                    {
                        nodeName = "/" +  tempNode.name;
                    }
                    nodePath = nodePath.Insert(index, nodeName);
                }
                nodePathList.Add(node.name, nodePath);
            }

            //成员变量字符串
            string memberstring = "";
            //查询代码字符串
            string loadedcontant = "";

            foreach (Transform itemtran in mainNode)
            {
                string typeStr = dicUIType[itemtran.name.Split('_')[0]];

                memberstring += "private " + typeStr + " " + itemtran.name + " = null;\r\n\t";

                loadedcontant += itemtran.name + " = " + "transform.Find(\"" + nodePathList[itemtran.name] + "\").GetComponent<" + typeStr + ">();\r\n\t\t";
            }
            string scriptPath = Application.dataPath + "/Scripts/" + selectobj.name + ".cs";

            string classStr = "";

            //如果已经存在了脚本,则只替换//auto下方的字符串
            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 = "//auto";
                string unchangeStr = Regex.Split(classStr, splitStr, RegexOptions.IgnoreCase)[0];
                string changeStr = Regex.Split(AutoBuildTemplate.UIClass, splitStr, RegexOptions.IgnoreCase)[1];

                StringBuilder build = new StringBuilder();
                build.Append(unchangeStr);
                build.Append(splitStr);
                build.Append(changeStr);
                classStr = build.ToString();
            }
            else
            {
                classStr = AutoBuildTemplate.UIClass;
            }

            classStr = classStr.Replace("#类名#", selectobj.name);
            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/" + selectobj.name + ".cs 成功!");
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
    }
}
  • 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
3.2 模板生成

结合反射,我们可以使用模板生成技术,根据预制体的信息生成代码模板,然后填充相应的属性和方法。

public class AutoBuildTemplate
{
    public static string UIClass =
        @"using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.EventSystems;
    using System;
    public class #类名# : MonoBehaviour
    {
        #成员#
    //auto
        private void Awake()
	    {
		    #查找#
	    }

        private void OnDestroy()
        {
        }
    }
    ";
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

4、脚本解析

4.1 AutoBuildTemplate 模板类

AutoBuildTemplate 为UI基本样例类,很多项目开发都会有自己定义的UI基类,我们可以更改AutoBuildTemplate 类来迎合我们自己的项目。通过替换其中的 #类名#、#查找#、#成员#等关键词来加载对应参数展示,最终保存成cs文件。

4.2 UI样式列表映射

我们可以通过当前列表来映射UGUI的UI控件。这样在添加对应控件的时候,脚本就能够解析到,映射对应的控件:

var dicUIType = new Dictionary<string, string>();
dicUIType.Add("Img", "Image");
dicUIType.Add("Btn", "Button");
dicUIType.Add("Txt", "Text");
dicUIType.Add("Tran", "Transform");
dicUIType.Add("Input", "InputField");
dicUIType.Add("Raw", "RawImage");
dicUIType.Add("Drop", "Dropdown");
dicUIType.Add("Slider", "Slider");
dicUIType.Add("Scr", "Scrollbar");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

5、编辑生成

通过自定义的下划线(_)命名规则,来查找和解析预制体。
在这里插入图片描述
生成的代码样例:

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;
public class Page_Panel : MonoBehaviour
{
   private Text Txt_Text = null;
	private Image Img_Image = null;
	private Button Btn_Button = null;
	private Text Txt_ls = null;
	private RawImage Raw_Image = null;
	private InputField Input_Field = null;
	private Slider Slider_bg = null;
	private Scrollbar Scr_ollbar = null;
	
//auto
   private void Awake()
	{
		Txt_Text = transform.Find("Txt_Text").GetComponent<Text>();
		Img_Image = transform.Find("Img_Image").GetComponent<Image>();
		Btn_Button = transform.Find("Btn_Button").GetComponent<Button>();
		Txt_ls = transform.Find("Btn_Button/Txt_ls").GetComponent<Text>();
		Raw_Image = transform.Find("Raw_Image").GetComponent<RawImage>();
		Input_Field = transform.Find("Input_Field").GetComponent<InputField>();
		Slider_bg = transform.Find("Slider_bg").GetComponent<Slider>();
		Scr_ollbar = transform.Find("Scr_ollbar").GetComponent<Scrollbar>();
		
	}

   private void OnDestroy()
    {

    }
}

  • 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

5、总结

以上UnityUI预制体自动生成脚本,您可能需要根据项目需求和预制体的复杂性进行更复杂的代码生成。可以考虑生成属性的序列化、添加事件处理逻辑等。

总的来说,通过使用反射和模板生成技术,可以在一定程度上减轻手动编写与预制体相关的代码的负担,提高开发效率。但在实际应用中,请注意代码的质量和一致性,以确保生成的代码符合项目的规范和要求。

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

闽ICP备14008679号