哇这简直是个革命性的功能!先感谢一下某位不愿意透露姓名的贝贝大佬提供的想法和技术支持!
先简述一下这是个啥功能,就是我们项目之前在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的话拖入组件是不会被被监测到改变的~
今天的笔记就到这里~希望可以帮到看到这篇笔记的大家~~