Unity编辑器扩展总结

编辑器扩展

功能层

MenuItem

  • 作用:在指定路径添加自定义功能的按钮(该路径可以是导航栏、Hierarchy、Project以及组件)

  • 使用:

    • eg: [MenuItem("CustomWindow/TinyBehaviourTreeEditor %w" , false , 0)]

      1. 在导航栏生成CustomWindow栏目并在该栏目生成按钮TinyBehaviourTreeEditor

      2. 按钮位于CustomWindow栏目的最上面

      3. 按钮可以通过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

扩展流程

添加控件
  1. 加载uxml文件

  2. new 对应类型的控件

  3. 将实例添加到根视觉树

修改控件值
  • 直接修改对应控件实例的成员

注册回调
  • 如果控件存在value属性,则可以用RegisterValueChangedCallback监听value的值是否改变

数据绑定
  • 注: 仅在编辑模式生效 , 只可绑定可序列化字段 ,只能绑定带有value属性的控件

  • 数据绑定通过SerializedObject实现

    • SerializedObject介绍

      • 用于编辑unity对象可序列化字段

      • Unity Editor 中,所有unity对象都是通过SerializedObject 进行序列化,如预设体等

      • 可以让ui数据和对象数据绑定,可以避免一方数据改变时显式利用事件回调处理另一数据

  • 绑定步骤

    • 创建 SerializedObject实例

    • 确定要绑定的视觉元素(控件)

      • 注意:如果是自定义控件需要使用数据绑定功能,有以下两种方式实现

        1. 让自定义控件继承自BaseField并指定value类型

        2. 需要实现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)

      1. 常用属性

        • ports -- 视图的所有node的端口

      2. 常用方法

        • AddElement方法 -- 添加GraphElementGraphView(如添加Node到GraphView中)

        • DeleteElements方法 -- 从GraphView删除所有GraphElement

        • GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter)方法 -- 返回startPort可以连接的端口

        • 高亮Node

          • void Test(){
                graphView.ClearSelection();
                graphView.AddToSelection(MyNode);
            }
        • 添加完端口需要使用刷新方法

          • RefreshExpandedState()

          • RefreshPorts()

      3. 四个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()); //让内容可以矩形选取
      }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值