Unity自定义Attribute实现可多选的enum

在实现SceneName之后,我又给enum写了一个标签,这个标签的功能是使enum能够像LayerMask一样多选。
在这里插入图片描述

实现

这个需求比较直观,而且直接调函数就能实现功能,所以这里直接贴代码。

[AttributeUsage(AttributeTargets.Field)]
public class MultiSelector : PropertyAttribute
{
    
    
    public MultiSelector() {
    
     }
}
[CustomPropertyDrawer(typeof(MultiSelector))]
public class MultiSelectorEditor : PropertyDrawer
{
    
    
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
    
    
        Enum targetObject = fieldInfo.GetValue(property.serializedObject.targetObject) as Enum;
        targetObject = EditorGUI.EnumFlagsField(position, label, targetObject);
        fieldInfo.SetValue(property.serializedObject.targetObject, targetObject);
        if(GUI.changed)
        {
    
    
            EditorUtility.SetDirty(property.serializedObject.targetObject);
        }
    }
}

它的用法就是标记一个枚举变量,让它在编辑器里支持多选。

当然,这个实现是早期的实现,它和当时SceneName的写法是相同的。因此,它也存在初版SceneName所存在的问题,也就是如果被嵌在了另一个类里,那么在绘制时就会有问题。

原因在那篇文章里也大致解释过了,就是fieldInfo无法根据指定的名称获取到变量。

改进

因为改这个MultiSelector是在改SceneName之后,所以这次修改的方向就很清晰了:改用property提供的属性来访问枚举的值即可。

在property中提供了enumValueFlag这个属性来获得枚举的值。或者直接用intValue,得到的值也是一样的。

但是现在又有一个问题……

新的问题

EnumFlagsField是针对Enum的操作,而我们能获取到的是一个int值。

直接做类型转换当然是首先想到的方案,但是int是不能向Enum转换的,直接就会报错。

在这里插入图片描述

我也试了先转object再转Enum,但是也不能达到预期。

在这里插入图片描述
所以现在如何进行类型转换又成为了亟待解决的问题。

一个没有成功的思路

虽然Enum和int之间不能互相转换,但对于一个具体的枚举类型来说,可以直接进行类型的转换。

基于这个思路,我创建了一个有32个值的枚举类型,每个值对应32位二进制数的一位,这样就可以利用这个类型进行类型转换。

public enum Enum32
{
    
    
    e0=1<<0,
    e1=1<<1,
	...
    e30=1<<30,
    e31=1<<31,
}

但是由于转换后得到的值是Enum32类型,所以EnumFlagsField绘制的下拉框的值列表是Enum32的这些值。

在这里插入图片描述

虽然类型的问题是解决了,但这自然也是不行的,所以还需要再寻找其它方法。

一个比较成功的思路

在上述的尝试失败后,我又发现Enum提供了ToObject方法,它可以将一个整型值转成一个枚举。

在这里插入图片描述

所以现在的问题就转化为获取被修饰字段的类型。

获取类型

fieldInfo存储的是字段的信息,所以要获取字段的类型,应该是可以从这里入手的。

在这里插入图片描述

FieldType就是我们需要的类型。

综上,最终的写法如下:

[CustomPropertyDrawer(typeof(MultiSelector))]
public class MultiSelectorEditor : PropertyDrawer
{
    
    
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
    
    
        Enum targetObject = Enum.ToObject(fieldInfo.FieldType, property.enumValueFlag) as Enum;
        targetObject = EditorGUI.EnumFlagsField(position, label, targetObject);
        property.enumValueFlag = Convert.ToInt32(targetObject);
        if(GUI.changed)
        {
    
    
            EditorUtility.SetDirty(property.serializedObject.targetObject);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/m0_49792815/article/details/129142723