2024-02-25 Unity 编辑器开发之编辑器拓展7 —— Inspector 窗口拓展

2024-02-26 01:44

本文主要是介绍2024-02-25 Unity 编辑器开发之编辑器拓展7 —— Inspector 窗口拓展,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 1 SerializedObject 和 SerializedProperty
  • 2 自定义显示步骤
  • 3 数组、List 自定义显示
    • 3.1 基础方式
    • 3.2 自定义方式
  • 4 自定义属性自定义显示
    • 4.1 基础方式
    • 4.2 自定义方式
  • 5 字典自定义显示
    • 5.1 SerizlizeField
    • 5.2 ISerializationCallbackReceiver
    • 5.3 代码示例

1 SerializedObject 和 SerializedProperty

​ 在 Unity 中,可以完全自定义某一个脚本在 Inspector 窗口的相关显示。

​ SerializedObject 和 SerializedProperty 主要用于在 Unity 编辑器中操作和修改序列化对象的属性,通常在自定义编辑器中使用,以创建更灵活、可定制的属性面板。

​ 只需记住简单的规则:

  • SerializedObject:代表脚本对象。

    参考文档:https://docs.unity.cn/cn/2022.1/ScriptReference/SerializedObject.html。

  • SerializedProperty:代表脚本对象中的属性。

    参考文档:https://docs.unity.cn/cn/2022.1/ScriptReference/SerializedProperty.html。

2 自定义显示步骤

  1. 单独为某一个脚本实现一个自定义脚本,并且脚本需要继承 Editor。

    一般该脚本命名为:自定义脚本名 + Editor。

image-20240225145626645
  1. 在该脚本前加上特性。
    命名空间:UnityEditor
    特性名:CustomEditor(想要自定义脚本类名的 Type)
using UnityEditor;
using UnityEngine;// 通过该特性,可以为 Lesson22 脚本自定义 Inspector 窗口中的显示
[CustomEditor(typeof(Lesson22))]
public class Lesson22Editor : Editor
{...
}
  1. 声明对应 SerializedProperty 序列化属性对象,主要通过它和自定义脚本中的成员进行关联。

    可以利用继承 Editor 后的成员 serializedObject 中的 FindProperty("成员变量名") 方法关联对应成员。

    一般在 OnEnable 函数中初始化。当选中对象后并在 Inspector 窗口进行显示时,OnEnable 函数会被执行;同理,选择其他对象使 Inspector 窗口取消显示时,OnDisable 函数会被执行。

using UnityEditor;
using UnityEngine;// 通过该特性,可以为 Lesson22 脚本自定义 Inspector 窗口中的显示
[CustomEditor(typeof(Lesson22))]
public class Lesson22Editor : Editor
{private SerializedProperty atk;private SerializedProperty def;private SerializedProperty obj;private void OnEnable() {// 关联序列化属性atk = serializedObject.FindProperty("atk");def = serializedObject.FindProperty("def");obj = serializedObject.FindProperty("obj");}
}
  1. 重写 OnInspectorGUI 函数。

    该函数控制 Inspector 窗口中显示的内容,只需在其中重写内容便可自定义窗口。

    注意:其中的逻辑需要包裹在这两句代码之间:

    serializedObject.Update(); // 更新序列化对象的表示形式 ... serializedObject.ApplyModifiedProperties(); // 应用属性修改

using UnityEditor;
using UnityEngine;// 通过该特性,可以为 Lesson22 脚本自定义 Inspector 窗口中的显示
[CustomEditor(typeof(Lesson22))]
public class Lesson22Editor : Editor
{private SerializedProperty atk;private SerializedProperty def;private SerializedProperty obj;private bool foldOut;private void OnEnable() {// 关联序列化属性atk = serializedObject.FindProperty("atk");def = serializedObject.FindProperty("def");obj = serializedObject.FindProperty("obj");}// 该函数控制了 Inspector 窗口中显示的内容// 只需要在其中重写内容便可以自定义窗口public override void OnInspectorGUI() {// base.OnInspectorGUI(); 不要调用父类的方法,而是去自定义serializedObject.Update(); // 更新序列化对象的表示形式// 自定义Inspector窗口的内容foldOut = EditorGUILayout.BeginFoldoutHeaderGroup(foldOut, "基础属性");if (foldOut) {if (GUILayout.Button("测试自定义 Inspector 窗口")) {Debug.Log(target.name); // 获取 Lesson22 脚本对象}EditorGUILayout.IntSlider(atk, 0, 100, "攻击力");def.floatValue = EditorGUILayout.FloatField("防御力", def.floatValue);EditorGUILayout.ObjectField(obj, new GUIContent("敌对对象"));}EditorGUILayout.EndFoldoutHeaderGroup();serializedObject.ApplyModifiedProperties(); // 应用属性修改}
}
image-20240225150537536

3 数组、List 自定义显示

3.1 基础方式

EditorGUILayout.PropertyField(SerializedProperty对象, 标题);

​ 该 API 会按照属性类型默认处理控件绘制的逻辑。

using UnityEditor;
using UnityEngine;// 通过该特性,可以为 Lesson22 脚本自定义 Inspector 窗口中的显示
[CustomEditor(typeof(Lesson22))]
public class Lesson22Editor : Editor
{private SerializedProperty strs;private SerializedProperty ints;private SerializedProperty gameObjects;private SerializedProperty listObjs;private void OnEnable() {// 默认得到的数组和 List 容量为空strs = serializedObject.FindProperty("strs");ints = serializedObject.FindProperty("ints");gameObjects = serializedObject.FindProperty("gameObjects");listObjs = serializedObject.FindProperty("listObjs");}public override void OnInspectorGUI() {serializedObject.Update();EditorGUILayout.PropertyField(strs, new GUIContent("字符串数组"));EditorGUILayout.PropertyField(ints, new GUIContent("整形数组"));EditorGUILayout.PropertyField(gameObjects, new GUIContent("游戏对象数组"));EditorGUILayout.PropertyField(listObjs, new GUIContent("游戏对象List"));serializedObject.ApplyModifiedProperties();}
}
image-20240225152856784

3.2 自定义方式

​ 利用 SerializedProperty 中数组相关的 API 来完成自定义。

API说明
arraySize获取数组或 List 容量。
InsertArrayElementAtIndex(索引)为数组在指定索引插入默认元素(容量会变化)。
DeleteArrayElementAtIndex(索引)为数组在指定索引删除元素(容量会变化)。
GetArrayElementAtIndex(索引)获取数组中指定索引位置的 SerializedProperty 对象。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;// 通过该特性,可以为 Lesson22 脚本自定义 Inspector 窗口中的显示
[CustomEditor(typeof(Lesson22))]
public class Lesson22Editor : Editor
{private SerializedProperty strs;private SerializedProperty ints;private SerializedProperty gameObjects;private SerializedProperty listObjs;private int count;private void OnEnable() {// 默认得到的数组和 List 容量为空strs = serializedObject.FindProperty("strs");ints = serializedObject.FindProperty("ints");gameObjects = serializedObject.FindProperty("gameObjects");listObjs = serializedObject.FindProperty("listObjs");// 初始化当前容量,否则每次开始都是 0count = listObjs.arraySize;}public override void OnInspectorGUI() {serializedObject.Update();// 容量设置count = EditorGUILayout.IntField("List容量", count);// 移除尾部内容,从后往前移除for (int i = listObjs.arraySize - 1; i >= count; i--)listObjs.DeleteArrayElementAtIndex(i);// 根据容量绘制需要设置的每一个索引位置的对象for (int i = 0; i < count; i++) {// 如果数组或 List 容量不够,通过插入的形式扩容if (listObjs.arraySize <= i)listObjs.InsertArrayElementAtIndex(i);SerializedProperty indexPro = listObjs.GetArrayElementAtIndex(i);EditorGUILayout.ObjectField(indexPro, new GUIContent($"索引{i}"));}serializedObject.ApplyModifiedProperties();}
}
image-20240225153514603

4 自定义属性自定义显示

4.1 基础方式

EditorGUILayout.PropertyField(SerializedProperty对象, 标题);

​ 需要为自定义类添加 Serializable 特性。

using System;
using UnityEngine;[Serializable]
public class MyCustomPro
{public int   i;public float f;
}public class Lesson22 : MonoBehaviour
{public MyCustomPro myCustom;
}
using UnityEditor;
using UnityEngine;[CustomEditor(typeof(Lesson22))]
public class Lesson22Editor : Editor
{private SerializedProperty myCustom;private void OnEnable() {myCustom = serializedObject.FindProperty("myCustom");}public override void OnInspectorGUI() {serializedObject.Update();EditorGUILayout.PropertyField(myCustom, new GUIContent("我的自定义属性"));serializedObject.ApplyModifiedProperties();}
}
image-20240225154307517

4.2 自定义方式

​ 使用如下方法寻找自定义属性的成员:

  1. SerializedProperty.FindPropertyRelative(属性)
  2. SerializedObject.FindProperty(属性.子属性)
using UnityEditor;
using UnityEngine;[CustomEditor(typeof(Lesson22))]
public class Lesson22Editor : Editor
{private SerializedProperty myCustomI;private SerializedProperty myCustomF;private void OnEnable() {// myCustomI = myCustom.FindPropertyRelative("i");// myCustomF = myCustom.FindPropertyRelative("f");myCustomI = serializedObject.FindProperty("myCustom.i");myCustomF = serializedObject.FindProperty("myCustom.f");}public override void OnInspectorGUI() {serializedObject.Update();myCustomI.intValue = EditorGUILayout.IntField("自定义属性中的I", myCustomI.intValue);myCustomF.floatValue = EditorGUILayout.FloatField("自定义属性中的F", myCustomF.floatValue);serializedObject.ApplyModifiedProperties();}
}
image-20240225154447107

5 字典自定义显示

5.1 SerizlizeField

​ SerizlizeField 特性让私有字段可以被序列化(能够在 Unity 的 Inspector 窗口被看到)。

5.2 ISerializationCallbackReceiver

​ 该接口是 Unity 用于序列化和反序列化时执行自定义逻辑的接口,实现该接口的类能够在对象被序列化到磁盘或从磁盘反序列化时执行一些额外代码。

​ 接口中函数:

  • OnBeforeSerialize: 在对象被序列化之前调用。
  • OnAfterDeserialize: 在对象从磁盘反序列化后调用。

​ 由于需要用两个 List 存储 Dictionary 的键值对,所以需要在

  • OnBeforeSerialize 序列化之前:将 Dictionary 里的数据存入 List 中进行序列化。
  • OnAfterDeserialize 反序列化之后:将 List 中反序列化出来的数据存储到 Dictionary 中。

5.3 代码示例

using System.Collections.Generic;
using UnityEngine;public class Lesson22 : MonoBehaviour, ISerializationCallbackReceiver
{public Dictionary<int, string> myDic = new Dictionary<int, string>() { { 1, "123" }, { 2, "234" } };[SerializeField]private List<int> keys = new List<int>();[SerializeField]private List<string> values = new List<string>();public void OnAfterDeserialize() {myDic.Clear();for (int i = 0; i < keys.Count; i++) {if (!myDic.ContainsKey(keys[i]))myDic.Add(keys[i], values[i]);elseDebug.LogWarning("字典Dictionary容器中不允许有相同的键");}}public void OnBeforeSerialize() {keys.Clear();values.Clear();foreach (var item in myDic) {keys.Add(item.Key);values.Add(item.Value);}}
}
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;[CustomEditor(typeof(Lesson22))]
public class Lesson22Editor : Editor
{private SerializedProperty keys;private SerializedProperty values;private int dicCount;private void OnEnable() {keys = serializedObject.FindProperty("keys");values = serializedObject.FindProperty("values");dicCount = keys.arraySize;}public override void OnInspectorGUI() {serializedObject.Update();dicCount = EditorGUILayout.IntField("字典容量", dicCount);// 容量变少时,把多的删了for (int i = keys.arraySize - 1; i >= dicCount; i--) {keys.DeleteArrayElementAtIndex(i);values.DeleteArrayElementAtIndex(i);}for (int i = 0; i < dicCount; i++) {// 如果容量不够,扩容if (keys.arraySize <= i) {keys.InsertArrayElementAtIndex(i);values.InsertArrayElementAtIndex(i);}// 自定义键值对的修改SerializedProperty indexKey   = keys.GetArrayElementAtIndex(i);SerializedProperty indexValue = values.GetArrayElementAtIndex(i);EditorGUILayout.BeginHorizontal();indexKey.intValue = EditorGUILayout.IntField("字典的键", indexKey.intValue);indexValue.stringValue = EditorGUILayout.TextField("字典的值", indexValue.stringValue);EditorGUILayout.EndHorizontal();}serializedObject.ApplyModifiedProperties();}
}
image-20240225180102531

这篇关于2024-02-25 Unity 编辑器开发之编辑器拓展7 —— Inspector 窗口拓展的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/747346

相关文章

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

2024年流动式起重机司机证模拟考试题库及流动式起重机司机理论考试试题

题库来源:安全生产模拟考试一点通公众号小程序 2024年流动式起重机司机证模拟考试题库及流动式起重机司机理论考试试题是由安全生产模拟考试一点通提供,流动式起重机司机证模拟考试题库是根据流动式起重机司机最新版教材,流动式起重机司机大纲整理而成(含2024年流动式起重机司机证模拟考试题库及流动式起重机司机理论考试试题参考答案和部分工种参考解析),掌握本资料和学校方法,考试容易。流动式起重机司机考试技

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

【专题】2024飞行汽车技术全景报告合集PDF分享(附原数据表)

原文链接: https://tecdat.cn/?p=37628 6月16日,小鹏汇天旅航者X2在北京大兴国际机场临空经济区完成首飞,这也是小鹏汇天的产品在京津冀地区进行的首次飞行。小鹏汇天方面还表示,公司准备量产,并计划今年四季度开启预售小鹏汇天分体式飞行汽车,探索分体式飞行汽车城际通勤。阅读原文,获取专题报告合集全文,解锁文末271份飞行汽车相关行业研究报告。 据悉,业内人士对飞行汽车行业

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

高效录音转文字:2024年四大工具精选!

在快节奏的工作生活中,能够快速将录音转换成文字是一项非常实用的能力。特别是在需要记录会议纪要、讲座内容或者是采访素材的时候,一款优秀的在线录音转文字工具能派上大用场。以下推荐几个好用的录音转文字工具! 365在线转文字 直达链接:https://www.pdf365.cn/ 365在线转文字是一款提供在线录音转文字服务的工具,它以其高效、便捷的特点受到用户的青睐。用户无需下载安装任何软件,只

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta