编辑器扩展
功能层
MenuItem
-
作用:在指定路径添加自定义功能的按钮(该路径可以是导航栏、Hierarchy、Project以及组件)
-
使用:
-
eg: [MenuItem("CustomWindow/TinyBehaviourTreeEditor %w" , false , 0)]
-
在导航栏生成CustomWindow栏目并在该栏目生成按钮TinyBehaviourTreeEditor
-
按钮位于CustomWindow栏目的最上面
-
按钮可以通过ctrl + w快速响应
-
-
itemName -- 路径(路径 = 按钮位置 + 按钮快捷键)-- 对应示例的"CustomWindow/TinyBehaviourTreeEditor %w"
-
按钮位置(path/../ButtonPath)
-
导航栏:是MenuItem的默认路径,符合路径规范即可
-
Hierarchy:Gameobject / .. / ButtonPath
-
Project:Assets / .. / ButtonPath
-
组件:CONTEXT / .. / ButtonPath
-
-
按钮快捷键
-
%:ctrl
-
#: shift
-
&:alt
-
a - z
-
eg:%w 代表 ctrl + w
-
-
-
isValidateFunction -- 是否为无效函数 -- 对应示例的false
-
存在itemName相同的按钮时才能看到效果
-
如A和B的路径都是:Test/t
-
如果A的isValidateFunction为false,B的isValidateFunction为true,该按钮是无法响应的
-
-
priority -- 排序/优先级 -- 对应示例的0
-
数值越小,在栏目中显示得越靠上,同个路径下数值超过11就会在按钮下方产生一条分割线
-
-
Selection
-
作用:提供一个操作被选中物体的接口
-
常用属性
-
activeObject:当前选中的对象
-
objects:选中的所有对象
-
activeGameObject:当前选中的Hierarchy对象
-
selectionChanged:选中对象改变时的回调方法
-
-
常用方法
-
Contains():当前选中的对象中是否包含指定的对象
-
GetFiltered():获取当前对象经过过滤器后剩余的对象
-
Undo
-
作用:可以让操作撤销
-
使用:
-
常用方法
-
RecordObject(Object obj, string name):为对象记录一个撤销操作
-
DestroyObjectImmediate(Object obj):立即销毁对象,并记录撤销操作
-
PerformUndo():执行撤销操作
-
Redo():重做上一个操作
-
-
EditorWindow
-
作用:生成一个窗口
-
使用:
-
常用属性:
-
titleContent: 窗口名
-
-
常用方法:
-
GetWindow<T>():静态方法,用于获取或创建指定类型的EditorWindow实例
-
CreateGUI:绘制uitoolkit控件
-
OnGUI:绘制gui控件
-
OnSelectionChange:选中物体改变时调用
-
-
AssetDatabase
-
作用:操作Assets文件夹的资产
-
使用
-
常用方法
-
FindAssets(string searchFilter):按过滤条件查找资产的guid
-
GUIDToAssetPath(string guid):把guid转为资产路径
-
LoadAssetAtPath<T>(string path):从指定路径加载资源
-
CreateAsset(Object asset, string path):在指定路径创建资源
-
DeleteAsset(string path):删除指定路径的资源
-
AddObjectToAsset:将对象添加到资产
-
RemoveObjectFromAsset:将对象从资产中移除
-
Refresh():刷新资产数据库
-
SaveAssets():保存更改
-
-
SerializedProperty
-
作用:
-
使用:
-
常用属性
-
常用方法
-
SerializedObject
-
作用:
-
使用
-
常用属性
-
targetObject:被序列化的对象
-
-
常用方法
-
FindProperty(string path):按名称查找序列化属性
-
ApplyModifiedProperties():应用对序列化对象所做的更改
-
-
EditorGUI(GUI)
-
作用:绘制GUI控件
-
使用:
-
常用方法:
-
BeginChangeCheck() 和 EndChangeCheck():用于检测UI元素的值是否发生变化
-
FloatField()、IntField()、TextField()等:用于绘制不同类型的输入字段
-
Button():用于绘制按钮
-
-
EditorGUILayout(GUI)
-
作用:控制GUI控件布局
-
使用:
-
常用方法:
-
BeginHorizontal() 和 EndHorizontal():开始和结束一个水平布局组
-
BeginVertical() 和 EndVertical():开始和结束一个垂直布局组
-
Space():在当前布局组中插入空白元素
-
Field() 系列方法(如FloatField、IntField等):用于绘制输入字段,并自动处理布局
-
-
视图层 -- UIToolkit
扩展流程
添加控件
-
加载uxml文件
-
new 对应类型的控件
-
将实例添加到根视觉树
修改控件值
-
直接修改对应控件实例的成员
注册回调
-
如果控件存在value属性,则可以用RegisterValueChangedCallback监听value的值是否改变
数据绑定
-
注: 仅在编辑模式生效 , 只可绑定可序列化字段 ,只能绑定带有value属性的控件
-
数据绑定通过SerializedObject实现
-
SerializedObject介绍
-
用于编辑unity对象的可序列化字段
-
Unity Editor 中,所有unity对象都是通过SerializedObject 进行序列化,如预设体等
-
可以让ui数据和对象数据绑定,可以避免一方数据改变时显式利用事件回调处理另一数据
-
-
-
绑定步骤
-
创建 SerializedObject实例
-
确定要绑定的视觉元素(控件)
-
注意:如果是自定义控件需要使用数据绑定功能,有以下两种方式实现
-
让自定义控件继承自BaseField并指定value类型
-
需要实现IBindable接口 或 继承自BindableElement , 然后实现INotifyValueChanged接口 的 SetValueWithoutNotify() 以及 value属性
-
-
-
确定要绑定的对象
-
//设置 视觉元素 的 bindingpath 为 被绑定对象 的 对应字段名 public void CreateGUI() { m_ObjectNameBinding = new TextField("Object Name Binding"); // Note: the "name" property of a GameObject is "m_Name" in serialization. m_ObjectNameBinding.bindingPath = "m_Name"; rootVisualElement.Add(m_ObjectNameBinding); OnSelectionChange(); } //通过SerializedObject获取指定对象的序列化数据,并用bind方法将该数据视觉元素绑定 public void OnSelectionChange() { GameObject selectedObject = Selection.activeObject as GameObject; if (selectedObject != null) { SerializedObject so = new SerializedObject(selectedObject); rootVisualElement.Bind(so); // Alternatively you can instead bind it to the TextField itself. // m_ObjectNameBinding.Bind(so); } else { // Unbind the object from the actual visual element that was bound. rootVisualElement.Unbind(); // If you bound the TextField itself, you'd do this instead: // m_ObjectNameBinding.Unbind(); // Clear the TextField after the binding is removed m_ObjectNameBinding.value = ""; } }
-
状态管理
-
通过控件的SetEnabled方法实现控件是否生效
自定义控件
实现过程
-
满足前提条件
-
继承于以下命名空间的控件:UnityEditor.UIElement、UnityEditor.Experimental.GraphView
前提条件
-
实现默认构造
-
class StatusBar : VisualElement { public StatusBar() { m_Status = String.Empty; } string m_Status; public string status { get; set; } }
-
-
如果自定义控件需要在UIBuilder中显示 , 需要将自定义控件类加入到UxmlFactory
-
StatusBar -- 显示StatusBar控件在UIBuilder
-
UxmlTraits -- 显示UxmlTraits属性在UIBuilder
-
如果只需显示在UIBuilder , 不需要自定义属性 , 可以直接这样写
-
class StatusBar : VisualElement { public new class UxmlFactory : UxmlFactory<StatusBar> {} // ... }
-
-
如果需要显示在UIBuilder 并且 需要定义 UXML 特性 , 可以这样写
-
class StatusBar : VisualElement { public new class UxmlFactory : UxmlFactory<StatusBar, UxmlTraits> {} public new class UxmlTraits : VisualElement.UxmlTraits { UxmlStringAttributeDescription m_Status = new UxmlStringAttributeDescription { name = "status" }; public override IEnumerable<UxmlChildElementDescription> uxmlChildElementsDescription { get { yield break; } } public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) { base.Init(ve, bag, cc); ((StatusBar)ve).status = m_Status.GetValueFromBag(bag, cc); } } // ... }
-
-
UnityEditor.UIElement
-
VisualElement:UI元素的基类,用于构建UI层次结构
-
BindableElement:可与SerializedProperty绑定的元素,实现数据同步
-
Label:显示文本的UI控件
-
Button:可点击的按钮控件,触发事件回调
-
TextField:用于输入文本的控件
-
Toggle:复选框或开关按钮控件,表示选中状态
-
Slider / SliderInt:滑动条控件,选择数值范围(浮点数/整数)
-
Box:容器元素,用于在其内容周围绘制边框
-
Image:显示图像的控件
-
Template / Instance:定义和实例化可重用的UXML模板
-
SerializedObject:表示Unity对象的序列化状态,用于数据绑定
-
StyleSheet / Style:定义UI元素的样式规则,设置样式属性
UnityEditor.Experimental.GraphView
-
四个常用类
-
GraphView -- 视图(相当与VisualView)
-
常用属性
-
ports -- 视图的所有node的端口
-
-
常用方法
-
AddElement方法 -- 添加GraphElement到GraphView(如添加Node到GraphView中)
-
DeleteElements方法 -- 从GraphView删除所有GraphElement
-
GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter)方法 -- 返回startPort可以连接的端口
-
高亮Node
-
void Test(){ graphView.ClearSelection(); graphView.AddToSelection(MyNode); }
-
-
添加完端口需要使用刷新方法
-
RefreshExpandedState()
-
RefreshPorts()
-
-
-
四个VisualElement的拓展方法
-
private void AddConvinientOpe() { this.AddManipulator(new ContentZoomer()); //内容缩放 this.AddManipulator(new ContentDragger()); // 一个/多个内容拖拽 this.AddManipulator(new SelectionDragger()); // 选中内容拖拽 this.AddManipulator(new RectangleSelector()); //矩形选取 }
-
-
-
Node -- 节点
-
常用属性
-
inputContainer / outputContainer
-
-
常用方法
-
SetPosition方法
-
GetPosition方法
-
-
-
Port -- 连线的端口
-
常用属性
-
node
-
-
常用方法
-
Port.Create<Edge>(Orientation.Horizontal, Direction.Output, Port.Capacity.Multi, typeof(Port))
-
-
-
Edge -- 连线
-
常用方法
-
UpdateEdgeControl方法 -- 刷新
-
修改Edge连线颜色 -- 需要获取其两端的port, 对port的portColor进行修改
-
-
-
拓展
-
四个VisualElement的拓展方法
-
private void AddConvinientOpe() { this.AddManipulator(new ContentZoomer()); //让内容可缩放 this.AddManipulator(new ContentDragger()); //让一个/多个内容拖拽 this.AddManipulator(new SelectionDragger()); //让选中内容拖拽 this.AddManipulator(new RectangleSelector()); //让内容可以矩形选取 }
-