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