【案例设计】Rainbow Hierarchy 设计思路与分享

开发平台:Unity 2021
编程平台:Visual Studio 2020

前言

  根据项目类型与参与工时的开发者规模作为参考,为加快项目开发效率,往往采取的是定制专业化工具代替投入人力成本的方式。于是编辑扩展成为了 Unity 开发者必须掌握的技能技巧。Rainbow Folders(彩虹文件夹)以修改编辑器内部视图颜色效果,加以区分项目资源类型、场景工程内资产类型等。有助于开发者快速区分资产。本文重点探讨 Rainbow Hierarchy 的实现思路与方式。

思考:如何篡改 Hierarchy 界面


  对 Hierarchy 界面进行篡改,优先考虑查询关于该界面的 API 文档。在 Unity 中文文档的解释中,对编辑器本身进行修改与扩展的 API 被归纳于 UnityEditor.DLL 中。即内部关联的 EditorApplication 类。查阅关键词 Editor、Hierarchy 与实际开发使用大致有以下 API 与其关联。

  • hierarchyWindowItemOnGUIHierarchy 面板中各可见元素的 GUI 委托。
  • HierarchyWindowItemCallback(int instanceID, Rect selectionRect)Hierarchy 面板中各可见元素的委托回调方法。
public static void OnEnable() { EditorApplication.hierarchyWindowItemOnGUI += OnHierarchyReDraw; }

public static void OnHierarchyWindowReDraw(int instanceID, Rect selectionRect)
{
	GameObject current = Selection.activeGameObject;
	Debug.Log($"{current} {current.name} {current.scene.name} {selectionRect}");
}

问题点

  1. 缺少可行的 Hierarchy 中单一 Element 的修改Element。
    解决方法:(见下板块)
  2. 即使脚本存放至 Editor 目录下,OnEnable() 并不会被执行。即使使用 ExecuteAlways / ExecuteInEditor 特性也无用。
    解决方法:使用 InitializeOnLoadInitializeOnLoadMethod 特性。该两特性应用于 EditorApplication 模式下的功能拓展。而前两种是用于期望 Application 模式在 EditorApplication 中运行。

思考:篡改 Element 的 Unity API


   Rainbow Hierarchy 的最终目的是篡改 Hierarchy 面板中 Element 元素呈现方式。意图通过重写Unity编辑器底层逻辑的思想无法实行。 因为无法确认 Unity Technology 是否提供该重写方法。以及大量性使用反射易造成计算机性能降低,为达到目的而降低性能不可取。于是实现 Rainbow 方式的落点在 EditorGUI 上,覆盖原 Element 图层成为当前可行的方法

图层文本EditorGUI.LabelField(Rect rect, string name, GUIStyle style)

  • 参数Rect:由 HierachyWindowItemCallback 提供。
  • 参数name:使用 Selection.activeGameObject.name 获取
  • 参数GUIStyle:创建配置表 或 配置模板。

  如下图所示:
在这里插入图片描述

问题点

  1. 覆盖的 EditorGUI 仅在发生选中时,激活与生成。
    解决方法:使用 InstanceID 反向定位 GameObject 获取信息。
    关联方法:EditorUtility.InstanceIDToObject(instanceID) as GameObject;
  2. 期望仅部分对象应用样式。
    解决方法:建立 List<T> 存储添加样式。添加、删除等方式可选择 MenuItem 实现或添加 GUI.Button
  3. 缺乏灵活的 Rainbow 样式配置。
    解决方法:(见下一模块)

思考:持续化 Hierarchy Element 刷新


  或许第一次使用 Rainbow Hierarchy 并未认为有什么问题,如果项目发生重启、工程迁移,亦或是希望颜色与样式发生变化。那么仅通过脚本内部识别检测是行不通的。于是,可视化配置 Rainbow Hierarchy 成为当前需要解决的难题。幸运的是 Unity 针对 Editor 提供了 ScriptableObject 持久化数据存储。

思考:ScriptableObject 的职责是什么?
答:根据目前 Hierarchy 的修改需求,其大致负责以下内容。

  1. 管理已有 Rainbow Element 样式信息。
    标签(字体、颜色、字号、粗体、斜体、)
    背景(颜色)
  2. 记录各 Scene 内资产的标记信息,以期望下次打开后直接读取配置。
[System.Serializable]
public class HierarchyConfig {
	public string GameObjectName;
	public Color FontColor = Color.white;
	public int FontSize = 15;
	public Color BackgroundColor = Color.black;
	public Rect InstanceRect;
}

  当发生 Rainbow 标记行为时,自行检查与创建对应匹配的 ScriptableObject。并索引数据目录下是否记录有该对象的标记数据,有则读取应用,无则忽略 Rainbow 生成。每次 Hierarchy 面板更新时,均按照此逻辑运行。

问题点

  1. 当场景发生变化时,InstanceID 将发生动态变化,每次加载新的场景,其场景内部资产均重新分配 InstanceID,原有记录的 InstanceID 将无效。
    解决方法:(见下一模块)
  2. ScriptableObject 在使用 MeuItem 或其他便捷操作,在场景发生变更时,已添加的数据将丢失。
    解决方法:每次完成后,对资产对象调用 EditorUtility.SetDirty() 进行缓存存储,避免丢失。

思考:解决资产识别唯一码


  资产识别码的作用是标识资产信息,如果场景内出现同命名的 GameObject 对象,在记录标记时会对已有对象的标记进行覆盖,或同名对象均应用同类型的标记信息。在设计上这种情况是不可取。于是 GUID 唯一码 成为当前最佳有效识别资产的参考标准。

获取:GameObject.GetType().GUID
类型:GUID
描述:该方法下的匹配规则用于甄别对象信息。
问题:Hierarchy 面板下资产信息持续返回 {0000-000000000000} 结果,无论 ScriptableObject 是否存在数据。

获取:AssetDatabase.TryGetGUIDAndLocalFileIdentifier(object, out string out ulong)
类型:string
描述:该方法下的匹配规则用于甄别对象信息。
问题:Hierarchy 面板下资产信息持续返回 {0000} 结果,无论 ScriptableObject 是否存在数据。

  从上述两种获取资产识别码中,注意到返回的结果均为 000 开头的无效结果。经分析与猜想,Hierarchy 面板中的资产数据严格意义上不属于 AssetsDatabase 中存储的资产,返回的结果固然是无效的。


  于是难题就来了,如何去获取这个场景内部资产的唯一码 或 是有从创建使用开始就不会因为场景变化、项目迁移导致的识别码变更。在翻遍Unity编辑器功能中,发现了一个满足要求的识别码 —— Local Identifier In File(Inspector 面板下 Debug 模式可见),如何获取该参数值,成为当前最需解决的问题。

使用反射方式获取信息
答:见 Unity 外网论坛 给出示例。

GlobalObject.GetGlobalObjectIDSlow() 推荐
答:这是上述论坛最底部的评论中了解,Unity 更新了 GlobalObject 协助开发者获取 Local Identifier In File 的类。参考文档说明,内部提供获取场景内资产唯一ID的方法。确切的帮助解决了获取这一途径的方法。

  于是问题得到了迎刃而解,以该ID作为辨识依据实现运行即执行的效果。无需每次启动配置的结果。

其他


可优化层面

  • 使用 UI Toolkit,制作编辑入口,以便利化调整参数。
  • 创建样式模板,每次选择准备好的样式即可,无需逐一配置。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值