使用oldin插件 + Unity自带拓展编辑器编写

实现效果:

界面配置基类:UIDialogConfig

using Sirenix.OdinInspector;
using UnityEngine;public class UIDialogConfig : MonoBehaviour
{[LabelText("界面层级")]public UIDialogLayerType layerType = UIDialogLayerType.PANEL;}

在为界面配置类 编写一个专门的Inspector显示类:DialogConfigEditor

using System;
using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities.Editor;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;namespace Editor.UI.Dialog
{[CustomEditor(typeof(UIDialogConfig))]public class DialogConfigEditor : OdinEditor{public override void OnInspectorGUI(){base.OnInspectorGUI();GUIHelper.PushColor(Color.green);if(GUILayout.Button("导出",GUILayout.Height(40))){UIDialogExport.ExportDialog((target as UIDialogConfig)?.gameObject);}GUIHelper.PopColor();SirenixEditorGUI.BeginBox("导出文件",true);UIDialogExport.GetDialogExportPathAndName((target as UIDialogConfig)?.gameObject, out string dialogPath, out string dialogName);UIDialogExport.GetDialogSkinExportPathAndName((target as UIDialogConfig)?.gameObject, out string dialogSkinPath, out string dialogSkinName);UIDialogExport.GetDialogConfigExportPathAndName((target as UIDialogConfig)?.gameObject, out string dialogConfigPath, out string dialogConfigName);CreatePath("Skin:",dialogName,dialogPath);CreatePath("Dialog:",dialogSkinName,dialogSkinPath);CreatePath("DialogConfig:",dialogConfigName,dialogConfigPath);SirenixEditorGUI.EndBox();}public void CreatePath(string title,string cname,string path){GUILayout.BeginHorizontal();string filePath = path + cname + ".lua"; var obj = AssetDatabase.LoadAssetAtPath<Object>(filePath);EditorGUILayout.TextField(title,obj == null ? String.Empty : filePath);if (GUILayout.Button("定位",GUILayout.Width(40))){if(obj != null)EditorGUIUtility.PingObject(obj);}GUILayout.EndHorizontal();}}
}

编写一个组件收集器 用于提取出需要动态修改、操作的组件如:按钮,图片等

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sirenix.OdinInspector;
using UnityEditor;
using UnityEngine;/// <summary>
/// 组件收集器
/// </summary>
public class UIComponentGatherer : UIComponentBase
{public override UIComponentType CompType => UIComponentType.None;[BoxGroup("基础属性",true,true,1),Button("收集组件",ButtonSizes.Large),GUIColor(0,1,0)]public void GathererComponents(){Gatherer();}[ReadOnly][SerializeField][PropertyOrder(2)][LabelText("动态组件列表")][ListDrawerSettings(DraggableItems = false, IsReadOnly = true,NumberOfItemsPerPage = 10, ShowItemCount = true,OnBeginListElementGUI = "BeginDrawListElement",OnEndListElementGUI = "EndDrawListElement")]public List<UIBaseProxy> dynamicProxies;[ReadOnly][PropertyOrder(3)][LabelText("静态组件列表")][ListDrawerSettings(DraggableItems = false,IsReadOnly = true,NumberOfItemsPerPage = 10, ShowItemCount = true)]public List<UIBaseProxy> staticProxies; private void BeginDrawListElement(int index){if (dynamicProxies[index] != null){UIBaseProxy baseProxy = dynamicProxies[index] as UIBaseProxy;Sirenix.Utilities.Editor.SirenixEditorGUI.BeginBox(baseProxy != null? baseProxy.SelfName: "default");}}private void EndDrawListElement(int index){if (dynamicProxies != null && dynamicProxies[index] != null)Sirenix.Utilities.Editor.SirenixEditorGUI.EndBox();}private bool Gatherer(){Dictionary<string, Component> componentDic = new Dictionary<string, Component>();dynamicProxies = new List<UIBaseProxy>();   staticProxies = new List<UIBaseProxy>();UIBaseProxy[] proxies = transform.GetComponentsInChildren<UIBaseProxy>();for (int i = 0; i < proxies.Length; i++){if(proxies[i] == this) continue;if (componentDic.ContainsKey(proxies[i].SelfName)){string path1 = GetInspectorPath(componentDic[proxies[i].SelfName].transform);string path2 = GetInspectorPath(proxies[i].transform);if (EditorUtility.DisplayDialog("收集组件",path1 + "\r\n" + path2 + "\r\n组件名称相同请修改","确定")){dynamicProxies = null;staticProxies = null;}return false;}if (proxies[i].IsDynamic)dynamicProxies.Add(proxies[i]);elsestaticProxies.Add(proxies[i]);componentDic.Add(proxies[i].SelfName,proxies[i]);}return true;}private string GetInspectorPath(Transform tran){string path = tran.name;while (true){if(tran.parent == null) break;path = tran.parent.name + "/" + path;tran = tran.parent;}return path;}
}

最后编写一个导出类:UIDialogExport,这里使用一个模板.txt的文件将里边的类名替换成界面或者模块的名称

using System;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;namespace Editor.UI.Dialog
{public static partial class UIDialogExport{private const string REPLACE_TEMPLATE_DIALOG_NAME = "$DIALOG_NAME$"; private const string UI_DIALOG_TEMPLATE_FILE = "Assets/Scripts/CS/Core/UI/LuaTemplate/UIDialogTemplate.txt";           // dialog模板文件private const string UI_DIALOG_SKIN_TEMPLATE_FILE = "Assets/Scripts/CS/Core/UI/LuaTemplate/UIDialogSkinTemplate.txt";  // dialogSkin模板文件private const string UI_DIALOG_ROOT_PATH = "Assets/Resources/UI/Prefab/";public const string UI_DIALOG_EXPORT_ROOT_PATH = "Assets/Scripts/Lua/Logic/UI/";public const string UI_DIALOG_EXPORT_ROOT_SKIN_PATH = "Assets/Scripts/Lua/Logic/UI/Export/";public static void ExportDialog(GameObject obj){var prefabAssetType = PrefabUtility.GetPrefabAssetType(obj);var canExportPrefab = prefabAssetType == PrefabAssetType.NotAPrefab ||(prefabAssetType == PrefabAssetType.Regular && PrefabUtility.HasPrefabInstanceAnyOverrides(obj, false));if (null == obj || canExportPrefab){if (EditorUtility.DisplayDialog("导出失败", "该游戏物体不是预制体", "确定")){}return;}GetDialogExportPathAndName(obj,out string exportPath,out string dialogName);GetDialogSkinExportPathAndName(obj,out string exportSkinPath,out string dialogSkinName);UIDialogConfig uIDialogConfig = obj.GetComponent<UIDialogConfig>();ExportDialogLua(exportPath,dialogName);ExportDialogSkin(uIDialogConfig,exportSkinPath,dialogSkinName);}public static void GetDialogExportPathAndName(GameObject obj,out string exportPath,out string dialogName){string prefabPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(obj);exportPath = prefabPath.Replace(UI_DIALOG_ROOT_PATH, UI_DIALOG_EXPORT_ROOT_PATH).Replace(obj.name + ".prefab",String.Empty);dialogName = obj.name.Replace("Win_", String.Empty).Replace("_",String.Empty);}public static void GetDialogSkinExportPathAndName(GameObject obj,out string exportPath,out string dialogSkinName){string prefabPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(obj);exportPath = prefabPath.Replace(UI_DIALOG_ROOT_PATH, UI_DIALOG_EXPORT_ROOT_SKIN_PATH).Replace(obj.name + ".prefab",String.Empty);dialogSkinName = obj.name.Replace("Win_", String.Empty).Replace("_",String.Empty) + "Skin";}public static void GetDialogConfigExportPathAndName(GameObject obj,out string exportPath,out string dialogConfigName){string prefabPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(obj);exportPath = prefabPath.Replace(UI_DIALOG_ROOT_PATH, UI_DIALOG_EXPORT_ROOT_SKIN_PATH).Replace(obj.name + ".prefab",String.Empty);dialogConfigName = obj.name.Replace("Win_", String.Empty).Replace("_",String.Empty) + "Config";}private static void ExportDialogLua(string exportPath,string dialogName){if (!Directory.Exists(exportPath)){Directory.CreateDirectory(exportPath);}string dailogFilePath = $"{exportPath}{dialogName}{".lua"}";if (File.Exists(dailogFilePath)) return;StreamReader sr = File.OpenText(UI_DIALOG_TEMPLATE_FILE);StreamWriter sw = File.CreateText(dailogFilePath);string template = sr.ReadToEnd();sw.Write(template.Replace(REPLACE_TEMPLATE_DIALOG_NAME ,dialogName));sw.Close();sr.Close();AssetDatabase.Refresh();}private static void ExportDialogSkin(UIDialogConfig uIDialogConfig,string exportPath,string dialogName){if (!Directory.Exists(exportPath)){Directory.CreateDirectory(exportPath);}string dailogFilePath = $"{exportPath}{dialogName}{".lua"}";StreamReader sr = File.OpenText(UI_DIALOG_SKIN_TEMPLATE_FILE);StreamWriter sw = File.CreateText(dailogFilePath);string template = sr.ReadToEnd();StringBuilder sb = new StringBuilder();UIBaseProxy[] proxies = uIDialogConfig.GetComponent<UIComponentGatherer>().dynamicProxies.ToArray();for (int i = 0; i < proxies.Length; i++){string parm = "self._" + proxies[i].SelfName + " = nil";sb.AppendLine(parm);}template = template.Replace("$DIALOG_SKIN$", sb.ToString());sw.Write(template.Replace(REPLACE_TEMPLATE_DIALOG_NAME ,dialogName));sw.Close();sr.Close();AssetDatabase.Refresh();}private static void ExportDialogConfig(){}}
}

至此基本算完事

最要API:

定位文件功能:

   string path = "Assets/Scripts/Lua/Core/UI/Component/UIBaseProxy.lua";var obj = AssetDatabase.LoadAssetAtPath<Object>(path);if(obj != null)EditorGUIUtility.PingObject(obj);

Unity系统弹窗:

EditorUtility.DisplayDialog("导出失败", "该游戏物体不是预制体", "确定")

创建文件夹

Directory.CreateDirectory(exportPath);

创建文件并写入文件:

 if (File.Exists(dailogFilePath)) return;StreamReader sr = File.OpenText(UI_DIALOG_TEMPLATE_FILE);StreamWriter sw = File.CreateText(dailogFilePath);string template = sr.ReadToEnd();sw.Write(template.Replace(REPLACE_TEMPLATE_DIALOG_NAME ,dialogName));sw.Close();sr.Close();

刷新unity Asset下的文件

AssetDatabase.Refresh();

oldin 特性使用

  • 只读特性 [ReadOnly]
  • 特性组 [BoxGroup("基础属性",true,true,1)]
  • 按钮特性 Button("收集组件",ButtonSizes.Large), GUIColor(0,1,0)]
  • 列表特性:[TableList]
[ListDrawerSettings( DraggableItems = false, IsReadOnly = true, NumberOfItemsPerPage = 10, ShowItemCount = true, OnBeginListElementGUI = "BeginDrawListElement", OnEndListElementGUI = "EndDrawListElement")]

Unity 拓展编辑器 - 导出UI预制体lua文件相关推荐

  1. Unity 自动化1.0(代码,预制体生成到指定模块)

    代码生成参考的 知乎[Unity]工具类系列教程-- 代码自动化生成! - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/30716595 操作流程: 一,创建 ...

  2. Unity 运行状态下动态保存 预制体/预制体上脚本参数

    前言:在Unity游戏制作过程中为了方便策划调试保存 通常会让策划可以在游戏运行时直接保存调整好的预制体 在此背景下,出现了以下代码: 一.运行状态下动态保存预制体 代码: public class ...

  3. Unity中 批量设置成 预制体

    在unity 中 设置预制体时,一般情况下 是一个一个的拖拽 ,很方便. 但是,遇到需求是 制作大量的预支体时, 一个一个的拖拽,效率很低, 也很无聊.查找资料, 发现 是可以批量的制作预制体的.步骤 ...

  4. Unity粒子特效系列-下雨预制体做好了,拿走直接就用!

    欢迎评论或私信,只要是小空知道的一定会逐一回复的!

  5. Unity 在编辑器菜单栏里添加清除空文件夹

    在 Assets/App/Editor 路径下新建 ClearEmptyFolder 文件夹,并在该文件夹下新建文件 EmptyFolderClear.cs using System.IO; usin ...

  6. Unity的使用(四):预制体,创建地形和地形导航

    前面介绍了Unity游戏引擎的基础功能,现在终于要进入到游戏开发中了.那么,一款游戏开发要有资源,这个一般是由美术提供的,我们只需要负责程序方面的事.那么,怎么将获得的资源应用起来呢? 一. 导入资源 ...

  7. 【Unity入门】21.预制体

    [Unity入门]预制体     大家好,我是Lampard~~     欢迎来到Unity入门系列博客,所学知识来自B站阿发老师~感谢  (一)预制体制作 (1)什么是预制体     这一章节的博客 ...

  8. Unity 蓝湖 关于UI工作流优化的思考(二)

    背景和历史版本在下面这篇博客中查看: Unity & 蓝湖 关于UI工作流优化的思考 最新版本: 本文旨在让不会使用Unity的其他人员在简单了解该工具后,可以帮助研发人员搭建Unity中的U ...

  9. 【Unity编辑器扩展实践】、查找所有引用该图片的预制体

    上一篇Unity编辑器扩展实践二.通过代码查找所有预制中已经查到到所有的预制体了. 然后我们就可以用这些预制体做一些其他的操作了,比如查找该预制的资源引用.可以直接遍历预制,找到预制里面的所有Imag ...

最新文章

  1. ubuntu开机出现:system program problem detected
  2. 062_html多媒体
  3. 为什么我的C4C Service Request没办法Release到ERP?
  4. AUTOSAR从入门到精通100讲(六)-AUTOSAR中的PostBuild Data Set Generation Phase
  5. angularjs 同步請求_angularjs $q、$http 处理多个异步请求
  6. 设置为自动获得IP地址,如何查看当前的IP地址
  7. Hive和hdfs的关系与区别
  8. 软件配置管理的作用?软件配置包括什么?
  9. python代码美化工具
  10. 钣金行业精益化生产和管理的必要性
  11. visual studio出现的0xc0000135问题
  12. NCM转MP3神奇的网页
  13. 蓝牙地址BD_ADDR组成
  14. 一定不要想当然啊!!
  15. 【社交网络分析】映射主题网络:从两极分化的人群到社区集群(一)
  16. adb常用命令以及使用
  17. pg事务篇(二)—— 事务ID回卷与事务冻结(freeze)
  18. 存储过程之八-java代码调用oracle存储过程
  19. 新系统上线的注意事项
  20. dmc预测控制 matlab,预测控制动态矩阵DMC算法研究分析及仿真.doc

热门文章

  1. Fastjson处理复杂层级关系的json对象
  2. YXCMS靶场实验报告
  3. [转帖]我在北京当了两个月“地老鼠”--底层生活散记(续的续)
  4. [易语言] 百宝云+迅雷引擎:满速、直链下载文件!
  5. 查看IC中文文档的网站
  6. Netty进阶:粘包与半包-解决方案
  7. 形变(Deform)开关的本质
  8. 收费企业邮箱哪个好用,如何选择合适的公司企业邮箱?
  9. 蔡徐坤正式成为FILA全新代言人
  10. baocms伪静态_PHP源码:BAOCMS v5.0白金版 本地O2O生活电商门户系统+微信+同步wap手机版宝...