Unity3D Editor ControlID 简单介绍

Posted 暗光之痕

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity3D Editor ControlID 简单介绍相关的知识,希望对你有一定的参考价值。

环境:Unity2021.1.14 Odin3.0.4 语言:C#

面向:Editor开发人员

总起

当我在工具代码中看到这行代码时:

GUIUtility.hotControl = id;

我产生了一个疑问,ControlID是什么?

第19章 GUI を自作する - エディター拡張入門中的介绍也只是寥寥几笔:

为每个GUI分配一个ControlID,此ID使每个GUI独立,如果没有正确分配这个ID,你最终会遇到多个GUI操作的冲突。比如当鼠标拖动GUI.Window时,范围选择工具起作用了。

生成/获取ControlID:

int id = GUIUtility.GetControlID(FocusType.Passive, rect);

通过ControlID控制样式:

EditorStyles.objectFieldThumb.Draw(rect, content, id);

而使用GUIUtility.hotControl可以找出当前处于焦点的ControlID,或者使用GUIUtility.keyboardControl你可以知道键盘的焦点。

一个例子

在Odin的使用中我发现了以下的bug(或者说设计如此):

 

我设计了这么个界面,Data中显示Datas的其中一个数据,然后选择显示哪个数据,由ChooseIndex决定。

代码如下:

using System;
using Sirenix.OdinInspector;
using UnityEngine;

public class TestControlID : MonoBehaviour
{
    [Serializable]
    public class Data
    {
        [ShowIf("@this.mode == Mode.Show")]
        public int testInt;

        public Mode mode = Mode.Show;
    }

    public enum Mode
    {
        Show,
        DontShow,
    }

    [OnValueChanged("Choose")]
    public int chooseIndex;

    public void Choose()
    {
        if (chooseIndex >= 0 && chooseIndex < datas.Length)
        {
            data = datas[chooseIndex];
        }
    }

    public Data data;

    public Data[] datas;
}

先把数据全选成NotShow,之后选择第一个Data将 Mode选择Show,再切到第二个,这时会神奇的发现第二个Data也“粘连”修改成了Show。

这个问题最终原因就是出在ControlID上:

  1. Odin使用的enum popup有两段操作,鼠标按下和抬起都会使值触发变化;
  2. 鼠标按下已经使值从DontShow改成了Show,造成了TestInt被隐藏,这导致了当前Mode框的ControlID发生了变化;
  3. 鼠标抬起也会触发值的变化,但此时的ControlID已经发生了变化,所以OdinSelector<T>.confirmedPopupControlId虽然被记录下来,但并没有触发;
  4. 等到我们改换显示第二个数据,因为计算出来ControlID是一致的,所以第二段此时才进行触发;

产生“粘连”修改问题,也很好解决:

  1. 禁用这种二段触发的popup,可以使用Unity原生popup;
  2. ControlID在计算的时候可以率先分配一个不共用的id段;
  3. 会被隐藏的属性都放到mode下面,这样ControlID不会发生变化。

这个例子直接放到InspectorWindow上进行切换是不会有问题的,Unity的处理方式实际就是第2种。

不过落到具体的方式上Unity2021和Unity2017还有所不同,2021采用了切换时会一直增长的方式,而2017则会为每个GameObject分配单独的ControlID。

总结

ControlID的具体算法因为是写在C++层的,我还是不是很了解,有大佬知道的话可以指引一下。

大体的作用实际就是标明每个控件的唯一ID,但是这种做法也会有局限,就是缓存下来的这个ID可能会随时变换,这是一个不稳定的ID。

以上是关于Unity3D Editor ControlID 简单介绍的主要内容,如果未能解决你的问题,请参考以下文章

unity3d没有editor怎么搞

在editor模式下遍历unity3d builtsetting中的场景

Unity3D Editor Undo回退效果实现1

Unity3D Editor Undo回退效果实现1

Unity3D引擎中特殊的文件夹

Unity3D用继承EditorUpdater类来实现Editor模式下的后台处理