unity学习笔记之不通过路径通过拖拽获取lua脚本里定义的UI组件

哇这简直是个革命性的功能!先感谢一下某位不愿意透露姓名的贝贝大佬提供的想法和技术支持!

先简述一下这是个啥功能,就是我们项目之前在lua里获取UI组件都是通过路径来获取,

类似这种,定义的时候需要每个组件都复制路径不方便而且容易出错就不说了,这几天美术在重新设计原有的一些UI界面,各种调整物体父节点或者更换预制体,每次美术那边动一次都需要程序这边更改路径名字,真的挺烦,于是在大佬提示下,我这边就实现了一个可以读取lua里定义的组件,然后像C#一样直接把组件拖拽进框框里就可以了的脚本,像这样:

(这是lua里定义的组件) 

 

这是在脚本里解析之后,就可以直接把目标组件拖拽进来,更改路径啥的再也不用动代码了!鼓掌!撒花!

接下来说说具体实现过程。

大佬教的,做一个大功能需要拆分成一个个的小需求。上面这些拆成小需求就是 首先读目标lua文件的路径,然后解析定义好的字符串,把字符串转换成对应的组件类型,然后再在编辑器面板里显示出来就可以啦。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System.Text.RegularExpressions;
using System;
using UnityEngine.UI;
using SLG.UI;
using TMPro;

namespace Game.UI
{

    [System.Serializable]
    public class LuaUIComponentParams
    {
        public string key;
        public string componentType;
        public string node;
        public UnityEngine.Object obj;
        //public GameObject gameObject;
    }

    public class LuaUIComponent : MonoBehaviour
    {
        public string luaPath = "";
        public string paramsName = "ComponentParams";


        [HideInInspector]
        public List<LuaUIComponentParams> paramsList;

        public void ReadLuaUIComponentParams(string path)
        {
            Debug.Log(path);
            string text = File.ReadAllText(path);
            text = DeleteLog(text);
            text = text.Replace("\n", "");
            text = text.Replace("\r", "");
            text = text.Replace(" ", "");
            text = text.Replace("\"", "");
            text = CutOutStr(text, paramsName + "={", "}");
            convertStrToList(text);
            //Debug.Log(paramsList);

        }

        //获取指定的字符串区间
        private string CutOutStr(string source, string startStr = "", string endStr = "")
        {
            Regex rg;
            if (endStr.Equals(""))
            {
                rg = new Regex("(?<=(" + startStr + "))[.\\s\\S]*");
            }
            else if (startStr.Equals(""))
            {
                rg = new Regex(".*?(?=(" + endStr + "))");
            }
            else
            {
                rg = new Regex("(?<=(" + startStr + "))[.\\s\\S]*?(?=(" + endStr + "))");
            }
            return rg.Match(source).Value;
        }

        //删除注释
        private string DeleteLog(string text)
        {
            Regex stringReg = new Regex("(\".*?)--(.*?\")(.*?\n)");

            var ms = stringReg.Matches(text);

            for (int i = 0; i < ms.Count; i++)
            {
                string newString = ms[i].Value.Replace('-', '☠');
                text = text.Replace(ms[i].Value, newString);
            }

            stringReg = new Regex("(\'.*?)--(.*?\')(.*?\n)");

            ms = stringReg.Matches(text);
            //if (ms.Count > 0)
            //{
            //    Debug.Log(file);
            //}
            for (int i = 0; i < ms.Count; i++)
            {
                string newString = ms[i].Value.Replace('-', '☠');
                text = text.Replace(ms[i].Value, newString);
            }



            Regex reg = new Regex(@"--\[[\c\=]*\[[\s\S]*?\][\c\=]*\]|--[\s\S]*?\n");
            text = reg.Replace(text, "\n");

            stringReg = new Regex("(\".*?)(.*?\")(.*?\n)");

            ms = stringReg.Matches(text);
            for (int i = 0; i < ms.Count; i++)
            {
                string newString = ms[i].Value.Replace('☠', '-');
                // Debug.Log(newString);

                text = text.Replace(ms[i].Value, newString);
            }

            stringReg = new Regex("(\'.*?)(.*?\')(.*?\n)");

            ms = stringReg.Matches(text);
            for (int i = 0; i < ms.Count; i++)
            {
                string newString = ms[i].Value.Replace('☠', '-');
                // Debug.Log(newString);

                text = text.Replace(ms[i].Value, newString);
            }
            return text;
        }

        //解析指定字符串,转化成List
        private void convertStrToList(string str)
        {
            string[] array = str.Split(',');
            List<LuaUIComponentParams> result = new List<LuaUIComponentParams>();
            foreach (var content in array)
            {
                string[] arr = content.Split(':');
                if (arr.Length < 2)
                {
                    continue;
                }
                LuaUIComponentParams lcp = new LuaUIComponentParams();
                lcp.key = arr[0];
                lcp.componentType = arr[1];
                // lcp.component = convertStrToType(lcp.componentType);
                lcp.node = arr[2];

                var oldLcp = getLcpFromList(lcp.key, lcp.componentType);

                Debug.Log(lcp.key + "   " + lcp.componentType);
                if (oldLcp != null)
                {
                    lcp.obj = oldLcp.obj;
                }
                result.Add(lcp);

            }
            paramsList = result;
        }

        //获取原有List里的数据
        private LuaUIComponentParams getLcpFromList(string key, string componentType)
        {
            foreach (var param in paramsList)
            {
                if (param.key == key && param.componentType == componentType)
                {
                    return param;
                }
            }
            return null;
        }

        //private 
    }
}

这是组件部分的逻辑

然后是编辑器部分的代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEngine.UI;
using System;
using SLG.UI;
using TMPro;

namespace Game.UI
{
    [CustomEditor(typeof(LuaUIComponent))]
    public class LuaUIComponentEditor : Editor
    {

        public override void OnInspectorGUI()
        {
            DrawDefaultInspector();

            LuaUIComponent lc = (LuaUIComponent)target;
            if (GUILayout.Button("读取组件"))
            {
                string prvPath = Application.dataPath + "/../../../client/project_s_client/game_assets/scripts/ui/";
                string endPath = ".lua";
                string path = prvPath + lc.luaPath + endPath;
                lc.ReadLuaUIComponentParams(path);

            }
            if (lc.paramsList != null && lc.paramsList.Count > 0)
            {
                EditorGUILayout.BeginVertical();
                foreach (var param in lc.paramsList)
                {
                    param.obj = EditorGUILayout.ObjectField(param.key, param.obj, convertStrToType(param.componentType), null);

                }

                EditorGUILayout.EndVertical();
            }

            if (GUI.changed)
            {

                EditorUtility.SetDirty(target);
                AssetDatabase.SaveAssets();
                EditorUtility.ClearDirty(target);
            }

        }

        private Type convertStrToType(string str)
        {
            switch (str)
            {
                case "Transform":
                    return typeof(Transform);
                case "RectTransform":
                    return typeof(RectTransform);
                case "Button":
                    return typeof(Button);
                case "Image":
                    return typeof(Image);
                case "GameObject":
                    return typeof(GameObject);
                case "UIScrollRect":
                    return typeof(UIScrollRect);
                case "UIImage":
                    return typeof(UIImage);
                case "TextMeshPro":
                    return typeof(TextMeshProUGUI);
                case "TMP_InputField":
                    return typeof(TMP_InputField);
                case "Input":
                    return typeof(TMP_InputField);
                case "Toggle":
                    return typeof(Toggle);
                case "Slider":
                    return typeof(Slider);
                default:
                    return typeof(GameObject);
            }
        }


    }
}

比较一目了然也没啥好说的,编辑器脚本不用太考虑性能,所以获取组件部分暴力switch就可以啦。

这个地方有一个知识点:unity监测改变是脏标记模式,改变在被用到的时候才会被监测到,所以如果不自己setDirty的话拖入组件是不会被被监测到改变的~

今天的笔记就到这里~希望可以帮到看到这篇笔记的大家~~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值