13.功能测试
13.1 知识点
如果存在同名控件生成失败的问题处理
InitInfo中每次都要清空panelBaseScript和panelScript
panelBaseScript = "";
panelScript = "";
如果panelBaseScript为空则只显示一个提升文本
if (panelBaseScript != "")
{
//...
}
else
{
GUILayout.Label("存在同名同类型控件,请先解决该问题");
}
存在同名控件效果
如果开着面板又生成其它内容,会存在数据清空不及时的问题
因为还开着面板的时候,控件字典和脚本位置不会清空的,字典会还存着上一次面板的控件信息,脚本位置也保留着上一面板的
在InitInfo清空字典和位置
//避免残留上一次的信息(比如工具窗口没关闭)
controlType.Clear();
nowPos = Vector2.zero;
nowPos2 = Vector2.zero;
13.2 知识点代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using TMPro;
using UnityEditor;
using UnityEditor.Compilation;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class UIPanelTool : EditorWindow
{
private string panelBaseScript;
private string panelScript;
private string panelName;
//GUI控件显示用
private Vector2 nowPos;
private Vector2 nowPos2;
private List<string> defaultName = new List<string>() { "Image",
"Text (TMP)",
"RawImage",
"Background",
"Checkmark",
"Label",
"Text (Legacy)",
"Arrow",
"Placeholder",
"Fill",
"Handle",
"Viewport",
"Scrollbar Horizontal",
"Scrollbar Vertical"};
//用于记录 对应控件类型的字典
private Dictionary<string, Type> controlType = new Dictionary<string, Type>();
[MenuItem("GameObject/UI/自动生成面板脚本文件")]
private static void CreateToolPanel()
{
UIPanelTool win = EditorWindow.GetWindow<UIPanelTool>("自动生成面板脚本工具");
win.Show();
//对面板上显示的相关信息进行初始化
//需要自动生成的代码 在这里 就应该拼接好
win.InitInfo();
}
public void InitInfo()
{
panelBaseScript = "";
panelScript = "";
//避免残留上一次的信息(比如工具窗口没关闭)
controlType.Clear();
nowPos = Vector2.zero;
nowPos2 = Vector2.zero;
//1.获取选择的对象
GameObject obj = Selection.activeGameObject;
if (obj == null)
return;
//获取面板名
panelName = obj.name;
//获取所有的按钮控件
ControlStrInfo strInfo = new ControlStrInfo();
//找按钮
ControlStrInfo controlInfo = FindControl<Button>(obj);
//如果为null 证明控件查找有问题 存在同名有用 控件
if (controlInfo == null)
return;
strInfo += controlInfo;
controlInfo = FindControl<Toggle>(obj);
//如果为null 证明控件查找有问题 存在同名有用 控件
if (controlInfo == null)
return;
strInfo += controlInfo;
controlInfo = FindControl<Slider>(obj);
//如果为null 证明控件查找有问题 存在同名有用 控件
if (controlInfo == null)
return;
strInfo += controlInfo;
controlInfo = FindControl<InputField>(obj);
//如果为null 证明控件查找有问题 存在同名有用 控件
if (controlInfo == null)
return;
strInfo += controlInfo;
controlInfo = FindControl<Dropdown>(obj);
//如果为null 证明控件查找有问题 存在同名有用 控件
if (controlInfo == null)
return;
strInfo += controlInfo;
controlInfo = FindControl<ScrollRect>(obj);
//如果为null 证明控件查找有问题 存在同名有用 控件
if (controlInfo == null)
return;
strInfo += controlInfo;
controlInfo = FindControl<Text>(obj);
//如果为null 证明控件查找有问题 存在同名有用 控件
if (controlInfo == null)
return;
strInfo += controlInfo;
controlInfo = FindControl<TextMeshProUGUI>(obj);
//如果为null 证明控件查找有问题 存在同名有用 控件
if (controlInfo == null)
return;
strInfo += controlInfo;
controlInfo = FindControl<Image>(obj);
//如果为null 证明控件查找有问题 存在同名有用 控件
if (controlInfo == null)
return;
strInfo += controlInfo;
controlInfo = FindControl<RawImage>(obj);
//如果为null 证明控件查找有问题 存在同名有用 控件
if (controlInfo == null)
return;
strInfo += controlInfo;
//已经获取到了对应的脚本代码 需要拼接进模板当中
TextAsset baseStr = AssetDatabase.LoadAssetAtPath<TextAsset>("Assets/Editor/UIPanelTool/UIConfigBase.txt");
panelBaseScript = string.Format( baseStr.text, //模板文件中的字符串信息
obj.name,//{0} 面板名
strInfo.nameStr,//{1} 控件变量的声明
strInfo.findStr, //{2} 控件的查找
strInfo.listenerStr, //{3} 控件事件的监听
strInfo.funcStr);//{4} 控件事件对应的响应函数 虚函数
TextAsset str = AssetDatabase.LoadAssetAtPath<TextAsset>("Assets/Editor/UIPanelTool/UIConfig.txt");
panelScript = string.Format(str.text, obj.name, obj.name);
}
private ControlStrInfo FindControl<T>(GameObject obj) where T:UIBehaviour
{
ControlStrInfo info = new ControlStrInfo();
T[] controls = obj.GetComponentsInChildren<T>();
Type type = typeof(T);
for (int i = 0; i < controls.Length; i++)
{
//通过判断该控件名字是否是不需要进行代码生成的 如果是 就直接跳过
//1.不用的控件,不记录
if( defaultName.Contains(controls[i].name) ||
controls[i].name == obj.name)
continue;
if(controlType.ContainsKey(controls[i].name))
{
//2.重复名字的相同控件判断
if (controlType[controls[i].name] == type)
{
EditorUtility.DisplayDialog("重复控件名", $"有两个控件类型相同的对象重名了{controls[i].name}", "确定");
return null;
}
//3.同名对象,不同类型的控件 比如 Button和Image会出现在一个对象上
// 只需要保证重要的控件已经生成代码了就可以了 相对不重要的控件 直接忽略不记录
else
continue;
}
controlType.Add(controls[i].name, type);
//声明相关的拼接
info.nameStr += $"public {type.Name} {controls[i].gameObject.name};\n\t";
info.findStr += $"{controls[i].gameObject.name} = this.transform.Find(\"{GetPath(controls[i].transform, obj.transform)}\").GetComponent<{type.Name}>();\n\t\t";
switch (type.Name)
{
case "Button":
info.listenerStr += $"{controls[i].gameObject.name}.onClick.AddListener(On{controls[i].gameObject.name}Click);\n\t\t";
info.funcStr += $"protected virtual void On{controls[i].gameObject.name}Click(){{}}\n\t";
break;
case "Toggle":
info.listenerStr += $"{controls[i].gameObject.name}.onValueChanged.AddListener(On{controls[i].gameObject.name}ValueChanged);\n\t\t";
info.funcStr += $"protected virtual void On{controls[i].gameObject.name}ValueChanged(bool value){{}}\n\t";
break;
case "Slider":
info.listenerStr += $"{controls[i].gameObject.name}.onValueChanged.AddListener(On{controls[i].gameObject.name}ValueChanged);\n\t\t";
info.funcStr += $"protected virtual void On{controls[i].gameObject.name}ValueChanged(float value){{}}\n\t";
break;
default:
break;
}
}
return info;
}
/// <summary>
/// 获取对象的父对象关系,拼接 路径 用于获取控件
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
private string GetPath(Transform obj, Transform panelTrans)
{
string path = obj.name;
while (obj.parent != panelTrans)
{
path = obj.parent.name + "/" + path;
obj = obj.parent;
}
return path;
}
private void OnGUI()
{
if (panelBaseScript != "")
{
nowPos = EditorGUILayout.BeginScrollView(nowPos);
GUILayout.Label(panelBaseScript);
EditorGUILayout.EndScrollView();
GUILayout.Label("-----------------------------------");
nowPos2 = EditorGUILayout.BeginScrollView(nowPos2);
GUILayout.Label(panelScript);
EditorGUILayout.EndScrollView();
if (GUILayout.Button("选择保存路径"))
{
string path = EditorUtility.SaveFilePanel("脚本保存路径", Application.dataPath + "/Scripts/", panelName + "Base", "cs");
if (path != "")
{
//脚本存储相关的逻辑
File.WriteAllText(path, panelBaseScript);
//path = path.Replace("Base", "");
int index = path.LastIndexOf("Base");
path = path.Substring(0, index) + ".cs";
//如果已经存在子类脚本 就不要再去覆盖生成了 避免把我们已经写好的 面板相关的逻辑覆盖掉
//如果基类当中对控件等内容进行了修改 我们只需要在子类当中根据需求手动修改即可
if (!File.Exists(path))
File.WriteAllText(path, panelScript);
CompilationPipeline.assemblyCompilationFinished += CompilationPipeline_assemblyCompilationFinished;
//刷新文件系统
AssetDatabase.Refresh();
}
}
}
else
{
GUILayout.Label("存在同名同类型控件,请先解决该问题");
}
}
private void CompilationPipeline_assemblyCompilationFinished(string arg1, CompilerMessage[] arg2)
{
//非编辑器的程序集编译完成
if(arg1.Contains("Assembly-CSharp.dll"))
{
//这样无法添加成功
//Selection.activeGameObject.AddComponent(Type.GetType(panelName));
//我们需要用到一些反射的知识 读取程序集 通过程序集去获取对应类型的组件
System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFrom(Application.dataPath.Substring(0, Application.dataPath.LastIndexOf("Assets")) + arg1);
Selection.activeGameObject.AddComponent(assembly.GetType(panelName));
//事件 有加就有减
CompilationPipeline.assemblyCompilationFinished -= CompilationPipeline_assemblyCompilationFinished;
}
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com